我将有五个节点:pending_tasks
、completed_tasks
、running_tasks
、workers
和queues
。pending_tasks
是保存任务的节点,包括新任务和由于工作节点故障而重新触发的任务。completed_tasks
保存已完成任务的详细信息。running_tasks
保存分配给工作人员的任务。在 PoC 实现中,我曾经使用 XML 编码的 POJO 来存储任务的详细信息。pending_tasks
、completed_tasks
和中的节点running_tasks
都是持久节点。
workers
持有代表可用工作人员的临时节点。鉴于它们是短暂的,这些节点表示工作器中的故障。queues
直接相关workers
: 中queues
的每个节点都有一个节点workers
。中的节点queues
用于保存分配给每个工人的任务。
现在,你需要一个大师。主人负责三件事:i)注意pending_tasks
新任务;ii)在新工人到来时注意workers
登记新的,并在工人失踪时重新安排任务;iii) 发布任务的结果(当我做这个 PoC 时,结果将通过发布/订阅通知机制)。除此之外,master 必须在启动时进行一些清理,因为在 master 停机期间,worker 可能会失败。queues
pending_tasks
completed_tasks
主算法如下:
at (start-up) {
for (q -> /queues) {
if q.name not in nodesOf(/workers) {
for (t -> nodesOf(/queues/d.name)) {
create /pending_tasks/t.name
delete /running_tasks/t.name
delete /queues/d.name/t.name
}
delete /queues/d.name
}
}
for (t -> nodesOf(/completed_tasks)) {
publish the result
deleted /completed_tasks/c.name
}
}
watch (/workers) {
case c: Created => register the new worker queue
case d: Deleted => transaction {
for (t -> nodesOf(/queues/d.name)) {
create /pending_tasks/t.name
delete /running_tasks/t.name
delete /queues/d.name/t.name
}
delete /queues/d.name
}
}
watch (/pending_tasks) {
case c: Created => transaction {
create /running_tasks/c.name
create persistent node in one of the workers queue (eg, /queues/worker_0/c.name)
delete /pending_tasks/c.name
}
}
watch (/completed_tasks) {
case c: Created =>
publish the result
deleted /completed_tasks/c.name
}
工人算法如下:
at (start-up) {
create /queue/this.name
create a ephemeral node /workers/this.name
}
watch (/queue/this.name) {
case c: Created =>
perform the task
transaction {
create /completed_tasks/c.name with the result
delete /queues/this.name/c.name
delete /running_tasks/c.name
}
}
关于我什么时候想到这个设计的一些注释。首先,在任何给定时间,都不会运行针对相同计算的任务。因此,我根据已进行的计算来命名这些任务。因此,如果两个不同的客户端请求相同的计算,则只有一个会成功,因为只有一个能够创建/pending_tasks
节点。同样,如果任务已经在运行,则/running_task/
节点的创建将失败并且不会分派新任务。
其次,master和worker都可能出现任意故障,不会丢失任何任务。如果一个worker失败了,观察到的delete事件/worker
会触发任务的重新分配。如果一个 master 失败并且任何给定数量的 worker 在新的 master 就位之前失败,启动过程会将任务移回/pending_tasks
并发布任何挂起的结果。
第三,我可能忘记了一些极端情况,因为我无法再访问这个 PoC 实现了。我很乐意讨论任何问题。