Как предотвратить одновременные задания, связанные с базой данных, на отдельных серверах? - PullRequest
0 голосов
/ 12 июня 2019

У нас есть работа, которую мы хотели бы запускать на двух отдельных серверах с интервалами. Это задание обрабатывает очередь электронной почты путем преобразования записей очереди в SMTP-сообщения один раз в минуту. Он отлично работает на одном сервере, но мы хотели бы избежать единой точки отказа и поочередно запускать задание на каждом из двух (или более) серверов.

Было бы лучше, если бы одно из заданий не выполнялось одновременно, поэтому я бы хотел, чтобы одно из них могло обнаруживать другое и останавливаться без выполнения какой-либо работы. По сути, они не должны наступать друг другу на ноги.

Это немного похоже на Как предотвратить одновременное выполнение заданий сервера Sql за исключением двух деталей:

  1. Я использую MariaDB с движком InnoDB
  2. Мой код написан на Java

Мой первый инстинкт - использовать базу данных, аналогичную приведенной выше. В MariaDB я мог бы создать для этой цели таблицу «блокировок» и использовать ее примерно так:

CREATE TABLE locks (id VARCHAR 10, PRIMARY KEY id);
INSERT INTO locks (id) VALUES ('email');

BEGIN;
SELECT id FROM locks WHERE id='email' FOR UPDATE;

[do my work, here, in another connection/transaction]

ROLLBACK; // or COMMIT

Я ожидаю, что FOR UPDATE приведет к блокировке записи блокировки до тех пор, пока я * COMMIT или ROLLBACK не выполню эту транзакцию. Это означает, что другой процесс, пытающийся выполнить тот же код, должен блокировать ожидание блокировки. Если я добавлю тайм-аут для этого SELECT запроса, я смогу определить тайм-аут и просто остановить «второй» процесс, не переходя к «реальной работе».

Будет ли эта схема работать так, как я ожидаю? В частности:

  1. Действительно ли SELECT ... FOR UPDATE в транзакции удерживает блокировку, пока транзакция не будет завершена. Я полагаю, что ответ на этот вопрос да - ну, я на это надеюсь, потому что у меня есть много другого кода, который опирается на эту технику.
  2. Будет ли SELECT ... FOR UPDATE блокировать только одну строку, или возможно, что база данных заблокирует более одной строки? Я хотел бы иметь возможность использовать эту технику на многих разных работах, только одна из них - работа по электронной почте. При необходимости я могу создать отдельные таблицы для каждого типа работы.
  3. Будет ли этот метод работать, если мы используем кластерную базу данных, такую ​​как Galera ? Насколько я понимаю, транзакционные блокировки в Galera блокируются только локально, и после фиксации транзакция будет распределена по кластеру. Поскольку у нас есть побочные эффекты за пределами базы данных (SMTP-сообщения), мы не можем гарантировать, что не будем отправлять одно и то же сообщение дважды.

Мы еще не используем кластеризованную базу данных, но ожидаем, что будем двигаться в этом направлении, поэтому было бы предпочтительным решение, которое может работать и в такой среде.

...