【问题标题】:How would you implement a working queue in etcd您将如何在 etcd 中实现工作队列
【发布时间】:2016-04-10 08:24:54
【问题描述】:

我刚刚开始研究 etcd,创建者的谈话中提到的用例之一是工作队列系统。

但是您将如何实际实施呢?

基本模式是这样的。

1 个进程生成“工作描述票证”,并将该票证放在 etcd 的文件夹中,比如说“/queue/worktickets/00000000001/”

1->许多进程监听“/queue/worktickets/”文件夹的变化。 当出现新的工单时,每个进程都会尝试通过在“/queue/locks/00000001”中创建一个新值来锁定该工单来获取工单。只有第一个能够创建锁定值。

创建锁票的进程完成了它的工作,然后从队列中删除票,可能还有锁值。然后尝试从队列中获取下一张可用的票。如果没有更多可用的票证,请再次开始监听“/queue/worktickets/”文件夹中的更改。

在我看来,这应该很容易实现,但是如果队列变大(票很容易生成但很难处理),那么似乎会有很多数据从 etcd 传输到每个客户端. 据我所知,没有办法说给我这个文件夹中不存在的第一个值,也没有一些给我文件夹中的前 n 个项目。

任何人都愿意分享他们对此的想法。

【问题讨论】:

  • etcd 存储库提供了包含 queue 的配方,这可能对您有用。

标签: queue distributed etcd workload


【解决方案1】:

所以我想出了一个我认为可靠的解决方案。以下是我设计解决方案的目标:

  • 工作人员从工作队列中检索项目应该是高效的(即 O(1) 次网络往返)。
  • 如果工作人员在处理物品时死亡或以其他方式失败,则该物品可供其他工作人员使用。

所以这个想法是有两个队列:一个挂起的队列和一个运行的队列。最初所有项目都在等待队列中。

当工作人员尝试检索项目时,它会使用事务(在 etcd 3 中提供)将其从待处理队列传输到运行队列。在同一个事务中,工作人员还为项目创建了一个锁。锁由租约保护,因此如果工人死亡,它会自动移除。

如果工作人员成功完成了项目的处理,它会从运行队列中删除项目,我们就完成了。如果worker失败,锁会过期,item会留在运行队列中。

因此,一旦挂起的队列耗尽,工作人员也应该查看正在运行的队列。期望运行队列与挂起队列相比会更小,因此查找当前未锁定的项目(通过简单地列出运行队列)不会很昂贵。

或者正如 @dannysauer 在 cmets 中提到的那样,您还可以有另一个容错进程,将项目从运行队列传输回待处理队列。

【讨论】:

  • 感谢 Derek 和 @dannysauer 的出色回答。我需要用潜在的大(100kB)值实现类似的东西。与其复制到看起来很昂贵的待处理文件夹,不如仅检查匹配的锁并获取没有相应锁的最旧的“工作项”然后尝试创建锁更有效吗?我假设在 etcd 中读取密钥比尝试创建密钥要便宜得多。似乎这也会捕获任何锁定过期的项目。
  • 已经有一段时间了,所以我可能是错的,但我认为check matching locks and take the oldest "work item" that doesn't have a corresponding lock 不可能以有效的方式。
【解决方案2】:

我想你已经解决了这个问题,但我这样做的方法是列出工作队列目录的内容(无论如何,这是你获取目录时得到的)。然后开始在列表中尝试在锁定目录中创建同名锁定,直到获得锁定。如果您使用“prevExist=false”标志,锁“文件”的创建是原子的,因此如果您成功创建它,您就是拥有该项目的锁的人。

理想情况下,您可以粗略估计处理该项目需要多长时间,然后将 TTL 设置为略长于该值(或者在可以估计时间的步骤之后定期刷新 TTL) .完成后,您要么从原始队列中删除该项目(并可能在“已完成”目录中重新创建),要么您的锁定到期,其他人将其取走。

此外,理想情况下,您应该将唯一的“节点标识符”(主机名,等等)放入锁定文件中,这样您的 TTL 更新就会进行比较和设置,如果您因花费太长时间而丢失锁定,该操作将失败.

工作目录可能会使用 POST 在目录上按顺序创建项目,而锁定队列和已完成目录将使用 PUT 按名称创建项目。

【讨论】:

  • 但是如果工作队列中有很多项目怎么办?您当然不想尝试一一锁定它们。有什么方法可以有效地检索未锁定的项目?
  • 如果你有很多客户,你会使用几个队列。作业进入“待处理”队列,然后客户端在处理作业时将待处理作业移动到“进行中”队列,然后在完成时移动到已完成队列或删除。如果在锁过期之前没有完成,你需要一些东西来观察锁并将正在进行的东西移回待处理。
  • 另一种方法是让工作队列使用顺序编号条目(etcd 将为您完成),然后使用每个客户端执行原子增量的计数器。您不必那样放置目录,因为您只需获取与计数器对应的一项。但是,您有一个所有客户端都依赖的单一争用点,这可能是一个问题,具体取决于工作定义。
  • 我发布了一个类似于您提到的多队列方法的解决方案。关于按顺序命名的方法:我认为它非常适合分发项目,但不清楚如果工作人员失败,你将如何将项目“返回”回队列,因为计数器会超过项目。跨度>
  • 是的;使用计数器,如果不完整的作业是一个问题,您仍然需要一个清理操作来检查不完整的作业。大多数时候,我不喜欢所有东西都使用单个共享锁。
猜你喜欢
  • 1970-01-01
  • 2012-12-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-03
  • 1970-01-01
  • 2011-01-07
相关资源
最近更新 更多