如何管理分布式调度程序中的不同节点选择唯一事件?



我有一个分布式作业调度器,它运行在三台机器上,从数据库中选择事件(弹性搜索)。

我面临的问题是有时所有的节点选择相同的事件。这对系统资源是不必要的负荷。

我想做的是实现一种机制,使分布式调度程序的每个节点都应该选择唯一的事件。

我正在研究以下选项:

  1. 在作业本身中添加节点ip,同时从弹性搜索中获取数据,我也可以传递节点id。(这是我正在使用的当前实现)。

  2. 我已经尝试探索zookeeper来完成同样的工作,但我不确定是否可以使用zookeeper。

谁能帮我在正确的方向移动这个?

使用后端存储作业并没有错,但如果事务数量非常高,它可能成为瓶颈(>1 k tps) .

对于分布式调度,您需要解决两个问题:

  1. 一个且只有一个工人应该接受一个任务(你的相关问题)。
  2. 如果一个worker运行任务失败(例如内存不足,重新启动,…),任务应该返回到持久化。

要在典型的后端中轻松解决这两个问题,可以添加两个字段:

State :: { PENDING, WORKING, DONE }
LastUpdate :: DateTime

要解决前一个问题,您必须自动查询和更新一条PENDING记录(即在同一事务中):

@Transactional
public Optional<Task> getTaskToWorkOnIfAny() {
Optional<Task> task = myBackend.getOnePendingTask();
if(task.isPresent())
// update task, I'm working on it!
myBackend.updateTask(task.get(), WORKING, new DateTime());
return task;
}

然后,像往常一样工作。

要解决后面的问题,只需检查任务是否WORKING太长时间(如果您的任务很长,您可以添加ping更新字段)。

如果我的任务失败,我应该写try/catch来移动WORKINGPENDING吗?好吧,你可以,但如果系统真的崩溃了,你的任务将是WORKING,所以,你应该遵循我之前的策略。

注意:考虑到整个问题,你只需要遵循前面的代码,其中getTaskToWorkOnIfAny类似于SELECT * FROM task WHERE state = 'PENDING' OR (state = 'WORKING' AND lastUpdate < yesterday()。仅此而已。

最新更新