如何创建分布式“去抖动”任务以消耗Redis列表?

时间:2014-10-09 19:15:00

标签: redis queue mutex distributed debouncing

我有以下用例:多个客户端推送到共享Redis列表。单独的工作进程应该排空此列表(处理和删除)。 Wait / multi-exec到位以确保,这很顺利。

出于性能原因,我不想立即调用'drain'进程,但是在x毫秒之后,从第一个客户端推送到(然后为空)列表的那一刻开始。

这类似于分布式下划线/ lodash debounce function,当第一个项目进入时,计时器开始运行(即:'领先'而不是'尾随')

我正在寻找以容错方式可靠地执行此操作的最佳方法。

目前我倾向于采用以下方法:

  1. 使用NXpx方法Redis Set。这允许:
    • 仅将值(互斥锁)设置为专用键空间(如果尚不存在)。这就是nx参数用于
    • 的内容
    • 在x毫秒后使密钥到期。这就是px参数用于
    • 的内容
  2. 如果可以设置该值,则此命令返回1,这意味着之前没有值。否则返回01表示当前客户端是自Redis列表耗尽后第一个运行该进程的客户端。因此,
  3. 此客户端将作业放在分布式队列上,该队列计划在x毫秒内运行。
  4. 在x毫秒之后,接收作业的工作人员开始排空列表。
  5. 这在纸上起作用,但感觉有点复杂。是否有其他方法可以以分布式容错方式工作?

    顺便说一句:Redis和分布式队列已经到位,所以我不认为将它用于此问题是一个额外的负担。

1 个答案:

答案 0 :(得分:5)

很抱歉,但正常的回复需要大量的文字/理论。因为你的好问题,你已经写好了答案:)

首先,我们应该定义术语。 “去抖”'在下划线/ lodash方面,应该在David Corbacho’s article解释下学习:

  

去抖动:将其视为"将多个事件分组在一个"中。想象一下,你回家,进入电梯,门正在关闭......突然你的邻居出现在大厅里,试图跳上电梯。讲礼貌!并为他打开门:你正在解除电梯的离开。考虑到同样的情况可能会再次发生在第三个人身上,等等......可能会在几分钟内推迟出发。

     

节气门:将其视为阀门,它可以调节执行的流量。我们可以确定在特定时间内调用函数的最大次数。因此,在电梯类比中,你很有礼貌地允许人们进入10秒,但是一旦延迟过去,你必须去!

您在询问debounce sinse第一个元素是否会被列入列表:

  

这样,与电梯类比。电梯升空后10分钟电梯应该上升。无论有多少人挤进电梯里都没关系。

在分布式容错系统的情况下,这应被视为一组要求:

  1. 在插入第一个元素(即创建列表)之后,新列表的处理必须在X时间内开始。
  2. 工人崩溃不应该破坏任何东西。
  3. 无死锁。
  4. 无论工人数量是多少,都必须满足第一项要求 - 无论是1还是N.
  5. 即。你应该知道(以分布式方式) - 一组工人必须等待,或者你可以开始列表处理。一旦我们说出"分发"和"容错"。这些概念总是与他们的朋友一起引导:

    1. 原子性(例如通过阻止)
    2. 预订
    3. 在实践中

      在实践中,我担心你的系统需要更复杂一点(也许你只是没有写过,而你已经拥有它)。

      你的方法:

      1. 通过SET NX PX与互斥锁进行悲观锁定。 NX保证一次只能完成一个进程(原子性)。 PX确保如果此过程发生某些事情,则Redis释放锁定(关于死锁定的容错部分)。
      2. 所有工作人员都尝试捕获一个互斥锁(每个列表键),因此只有一个人很高兴并且会在X时间之后处理列表。此过程可以更新互斥锁的TTL(如果需要更多时间,则最初需要)。如果进程崩溃 - 互斥锁将在TTL之后解锁并被其他工作人员抓取。
      3. 我的建议

        Redis中的容错reliable queue processing围绕RPOPLPUSH构建:

        • RPOPLPUSH项目从处理到特殊列表(每个工作人员每个列表)。
        • 处理项目
        • 从特殊列表中删除项目

        要求 因此,如果工作人员崩溃,我们总是可以将损坏的消息从特殊列表返回到主列表。 Redis保证RPOPLPUSH / RPOP的原子性。也就是说,只有一小群工人要等待一段时间。

        然后有两个选择。首先 - 如果有很多客户和较小的工人使用锁定工人。因此,尝试锁定工作中的互斥锁,如果成功 - 开始处理。

        反之亦然。每次执行LPUSH / RPUSH时都要使用SET NX PX(要让"等待N次,然后再弹出#34;解决方案,如果你有很多工人和一些推送客户端)。所以推动是:

        SET myListLock 1 PX 10000 NX 
        LPUSH myList value
        

        每个工作人员只检查myListLock是否存在,我们应该在设置处理互斥锁之前至少等待关键TTL并开始耗尽。