3

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

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

基本模式将是这样的。

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

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

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

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

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

4

2 回答 2

4

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

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

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

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

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

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

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

于 2017-01-02T07:08:22.863 回答
0

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

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

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

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

于 2016-03-23T21:09:47.063 回答