У нас есть работа, которую мы хотели бы запускать на двух отдельных серверах с интервалами. Это задание обрабатывает очередь электронной почты путем преобразования записей очереди в SMTP-сообщения один раз в минуту. Он отлично работает на одном сервере, но мы хотели бы избежать единой точки отказа и поочередно запускать задание на каждом из двух (или более) серверов.
Было бы лучше, если бы одно из заданий не выполнялось одновременно, поэтому я бы хотел, чтобы одно из них могло обнаруживать другое и останавливаться без выполнения какой-либо работы. По сути, они не должны наступать друг другу на ноги.
Это немного похоже на Как предотвратить одновременное выполнение заданий сервера Sql за исключением двух деталей:
- Я использую MariaDB с движком InnoDB
- Мой код написан на 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
запроса, я смогу определить тайм-аут и просто остановить «второй» процесс, не переходя к «реальной работе».
Будет ли эта схема работать так, как я ожидаю? В частности:
- Действительно ли
SELECT ... FOR UPDATE
в транзакции удерживает блокировку, пока транзакция не будет завершена. Я полагаю, что ответ на этот вопрос да - ну, я на это надеюсь, потому что у меня есть много другого кода, который опирается на эту технику.
- Будет ли
SELECT ... FOR UPDATE
блокировать только одну строку, или возможно, что база данных заблокирует более одной строки? Я хотел бы иметь возможность использовать эту технику на многих разных работах, только одна из них - работа по электронной почте. При необходимости я могу создать отдельные таблицы для каждого типа работы.
- Будет ли этот метод работать, если мы используем кластерную базу данных, такую как Galera ? Насколько я понимаю, транзакционные блокировки в Galera блокируются только локально, и после фиксации транзакция будет распределена по кластеру. Поскольку у нас есть побочные эффекты за пределами базы данных (SMTP-сообщения), мы не можем гарантировать, что не будем отправлять одно и то же сообщение дважды.
Мы еще не используем кластеризованную базу данных, но ожидаем, что будем двигаться в этом направлении, поэтому было бы предпочтительным решение, которое может работать и в такой среде.