如何防止独立服务器上同时发生与数据库相关的作业?

时间:2019-06-12 14:55:55

标签: java concurrency scheduled-tasks

我们有一项工作,希望每隔一段时间在两台单独的服务器上运行。该作业通过实质上每分钟一次将队列记录转换为SMTP消息来处理电子邮件队列。它可以在单个服务器上很好地工作,但是我们希望避免出现单点故障,并在两个(或更多)服务器中的每一个上交替运行该作业。

最好不要同时运行这些作业,因此我希望其中一个能够检测到另一个正在运行并停止而无需做任何工作。基本上,他们不应该踩到对方的脚趾。

这与How to Prevent Sql Server Jobs to Run simultaneously相似,但有两个细节:

  1. 我正在使用带有InnoDB引擎的MariaDB
  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将导致锁定记录被锁定,直到我COMMITROLLBACK该事务为止。这意味着另一个试图执行相同代码的进程应阻止等待锁定。如果我在该SELECT查询上添加了超时,则可以检测到超时并仅停止“第二”过程而无需继续“实际工作”。

该计划会按我期望的方式工作吗?具体来说:

  1. 事务中的SELECT ... FOR UPDATE是否真的持有锁,直到事务完成。我相信答案是-很好,我希望如此,因为我还有很多其他依赖这种技术的代码。
  2. SELECT ... FOR UPDATE将仅锁定一行,还是数据库将锁定多于一行?我希望能够在许多不同的工作上使用此技术,其中只有一项是“电子邮件”工作。如有必要,我可以为每种作业类型创建单独的表。
  3. 如果我们使用诸如Galera之类的集群数据库,该技术是否行得通?我的理解是,Galera中的事务锁定仅在本地锁定,并且在提交后,事务将分布在整个群集中。由于我们在数据库外部(SMTP邮件)有副作用,因此我们不能保证避免重复发送相同的邮件两次。

我们还没有使用集群数据库,但是我们希望朝着这个方向发展,因此,首选在这种环境下也可以运行的解决方案。

0 个答案:

没有答案