具有多线程的MySql数据库中任务项的Java任务调度

Posted

技术标签:

【中文标题】具有多线程的MySql数据库中任务项的Java任务调度【英文标题】:Java task scheduling for task items in MySql database with Multi-threading 【发布时间】:2021-06-13 08:22:33 【问题描述】:

我正在用java spring编写一个任务调度模块来处理存储在mysql数据库中的任务项。

Task表的架构结构:

ID | TASK_UUID | TASK_CONTENT(VARCHAR) | CREATED_TS | UPDATED_TS | STATUS(NEW/PROCESSING/COMPLETE)

我想实现多个任务调度程序工作人员以从 Task 表中获取要执行的任务。我可以通过什么方式确保任务调度程序不会同时执行相同的任务?有什么好的java框架可以用吗?

#编辑1: 任务执行模块设计为由不同的机器运行,因此同步方法可能不起作用。

#编辑 2: 每台机器都会获得随机或不规则数量的任务。所以如果使用自增序列,索引的分配大小也应该是不规则的,否则会有一些任务永远处理不完。

#编辑 3: 每台机器都运行着 Quartz Scheduler,配置了一个恒定的任务获取和执行作业。每个作业之间的时间间隔约为10 秒。因此,我的目标是确保每个机器调度程序在每次石英作业运行中都能获取至少 10 个任务

【问题讨论】:

使用数据库中事务的原子性。例如,添加一个“task scheduler id”列并设置它,如果它为空,就可以解决问题。如果在事务中完成。 所以@Erk 建议添加另一列有效地标识正在处理任务的机器的ID... 停止/失败/机器处理它死亡/等的任务怎么办?你怎么对付他们? (我提出问题是为了帮助您回答/帮助我们所有人回答)。 @MrR,是的,可能还需要时间戳列和超时处理。 @Kaguya 除非你需要一个master,DB是你的sequencer,所以任何机器都可以请求下一个任务,只有1台会得到它。 【参考方案1】:

您可以像这样解决原子性或事务问题,

使用任务的 ID,假设它是增量的。如果你有三台机器运行任务调度。然后只需将 id 修改为 3 并将结果为 0, 1 ,2 的任务分配给固定机器。所以不同的机器不会互相干扰(或竞争条件)

【讨论】:

非常聪明的想法。当我们假设每台并行机器都受到高可用性功能的保护时,您的方法将起作用。它还可以用作任务处理的负载平衡器。【参考方案2】:

您可以将方法 getTask 创建为同步方法:

例如:

synchronized Task getTask() 
  // get NEW task from DB
  // update status to PROCESSING
  // return task


#编辑1: 如果是这样,只需使用 SELECT FOR UPDATE 查询来阻止其他查询访问相同的任务。 例如:

SELECT * FROM Task t WHERE t.status = NEW ORDER BY t.created_ts LIMIT 1 FOR UPDATE;
UPDATE Task SET status = PROCESSING WHERE id = <the task id> .

您可以创建一个过程来包装查询。

【讨论】:

mysql 是一种相当繁重的方式来做到这一点 - 所以我想知道它是否全部在一个进程中运行(或者多台机器可以调度和/或执行任务) - 如果是这样的话不能使用同步。 @MrR 你是对的。该模块将由多台机器或集群运行。 所以@Kaguya 说多台机器/集群 - 所以数据库是确保跨多台机器的多个用户无法获得相同任务的方法。使用查询更新下一个要运行的任务 - 返回详细信息,并设置为运行。 @MrR 如果两台机器要更新同一个任务来运行呢?在这种情况下会有竞争条件吗? 如果是这样,只需使用 SELECT FOR UPDATE 查询来阻止其他查询访问相同的任务。例如:SELECT * FROM Task t WHERE t.status = NEW ORDER BY t.created_ts LIMIT 1 FOR UPDATE;更新任务集状态 = PROCESSING WHERE id = 。您可以创建一个过程来包装查询。

以上是关于具有多线程的MySql数据库中任务项的Java任务调度的主要内容,如果未能解决你的问题,请参考以下文章

java 一个线程处理多个任务

Java Thread 多线程 介绍

java多线程功力

java多线程功力

java多线程

Java线程多线程与线程池总结