很抱歉,但正常的反应需要一堆文字/理论。因为你的好问题你已经写了一个很好的答案:)
首先,我们应该定义术语。下划线/lodash 方面的“去抖动”应该在David Corbacho 的文章解释下学习:
Debounce:将其视为“将多个事件组合在一起”。想象一下你回家,进入电梯,门正在关上……突然你的邻居出现在大厅里并试图跳上电梯。要有礼貌!并为他打开门:你正在阻止电梯离开。考虑到第三个人可能会再次发生同样的情况,依此类推……可能会延迟出发几分钟。
节流阀:把它想象成一个阀门,它调节处决的流程。我们可以确定一个函数在特定时间内可以被调用的最大次数。所以在电梯的类比中,你足够礼貌地让人们进来 10 秒,但一旦延迟过去,你必须走!
您询问的debounce
第一个元素将被推送到列表中:
所以,以电梯为例。电梯应在电梯到达第一人后 10 分钟后上升。不管有多少人挤进电梯里。
在分布式容错系统的情况下,这应该被视为一组要求:
- 新列表的处理必须在插入第一个元素(即创建列表)之后的 X 时间内开始。
- 工人崩溃不应该破坏任何东西。
- 无死锁。
- 无论工人的数量是多少 - 无论是 1 还是 N,都必须满足第一个要求。
即您应该知道(以分布式方式) - 一组工作人员必须等待,或者您可以开始处理列表。一旦我们说出“分布式”和“容错”这个短语。这些概念总是伴随着他们的朋友:
- 原子性(例如通过阻塞)
- 预订
在实践中
在实践中,恐怕你的系统需要稍微复杂一点(也许你只是没有写,而你已经有了)。
你的方法:
- 通过 SET NX PX 使用互斥锁进行悲观锁定。
NX
是保证一次只有一个进程在做这项工作(原子性)。确保如果此过程发生某些事情,PX
Redis 会释放锁(死锁容错的一部分)。
- 所有工作人员都试图捕获一个互斥锁(每个列表键),所以只有一个人很高兴并且会在 X 次之后处理列表。这个过程可以更新互斥体的 TTL(如果需要更多的时间)。如果进程崩溃 - 互斥锁将在 TTL 后解锁并与其他工作人员一起抓取。
我的建议
Redis 中的容错可靠队列处理围绕RPOPLPUSH 构建:
- RPOPLPUSH 项目从处理到特殊列表(每个工人每个列表)。
- 处理项目
- 从特殊列表中删除项目
要求因此,如果工人崩溃了,我们总是可以将损坏的消息从特殊列表返回到主列表。Redis 保证了 RPOPLPUSH/RPOP 的原子性。也就是只有问题组的工人等待一段时间。
然后是两个选项。首先 - 如果有很多客户和较少的工人在工人一侧使用锁定。因此,尝试将互斥锁锁定在 worker 中,如果成功 - 开始处理。
反之亦然。每次执行 LPUSH/RPUSH 时使用 SET NX PX(如果您有很多工作人员和一些推送客户端,则有“在弹出之前等待 N 时间”解决方案)。所以推是:
SET myListLock 1 PX 10000 NX
LPUSH myList value
每个工作人员只需检查 myListLock 是否存在,我们应该至少等待关键 TTL,然后再设置处理互斥锁并开始耗尽。