Bull Queue并发问题

时间:2019-01-10 15:44:32

标签: javascript node.js concurrency bull.js

我需要帮助来了解Bull Queue(bull.js)如何处理并发作业。

假设我有10个Node.js实例,每个实例都实例化连接到相同Redis实例的Bull Queue:

const bullQueue = require('bull');
const queue = new bullQueue('taskqueue', {...})
const concurrency = 5;
queue.process('jobTypeA', concurrency, job => {...do something...});

这是否意味着在所有10个节点实例中全局最多有5个(并发)并发运行的jobTypeA类型的作业?还是我误会了,并发设置是每个节点的实例?

如果一个Node实例指定不同的并发值会怎样?

我可以确定作业不会被多个Node实例处理吗?

5 个答案:

答案 0 :(得分:1)

更深入地研究它,我认为Bull根本无法处理在多个Node实例之间分布的情况,因此该行为充其量是未定义的。

答案 1 :(得分:1)

Bull设计用于以“至少一次”的语义同时处理作业,尽管如果处理器正常工作(即不停顿或崩溃),则实际上是“恰好一次”。但是,您可以将最大停顿重试次数设置为0(maxStalledCount https://github.com/OptimalBits/bull/blob/develop/REFERENCE.md#queue),然后语义将“最多一次”。

已经说过,我将尝试回答张贴者提出的两个问题:

  

如果一个Node实例指定不同的并发值会怎样?

我将假设您的意思是“队列实例”。如果是这样,则在处理器中指定并发性。如果并发是X,则发生的情况是该给定处理器最多同时处理X个作业。

  

我可以确定作业不会被多个Node实例处理吗?

是的,只要您的工作不会崩溃或您的最大停顿工作设置为0。

答案 2 :(得分:0)

啊,欢迎光临!这是一个元答案,可能不是您想要的,而是解决此问题的一般过程:

  

您可以指定并发参数。公牛会打电话给您   并行处理该最大值。

我个人并不真正理解这一点,也不了解公牛提供的保证。由于它不是很清晰:

海事组织最大的事情是:

  

我可以确定作业不会被多个节点处理   实例?

如果排他消息处理是不变的,并且即使有大量文档,也将导致您的应用程序不正确,我强烈建议您对库:p

进行尽职调查

答案 3 :(得分:0)

TL; DR是:在正常情况下,作业仅被处理一次。如果出现问题(例如Node.js进程崩溃),则作业 可能会被双重处理。

牛市官方README.md的名言:

  

重要注意事项

     

队列的目标是“至少一次”的工作策略。这意味着在某些情况下,一项作业可能会被处理多次。当工作人员在整个处理过程中未能为给定作业锁定锁时,通常会发生这种情况。

     

当一个工人正在处理工作时,它将使该工作“锁定”,以便其他工人无法处理它。

     

重要的是要了解锁定是如何工作的,以防止您的作业丢失其锁定-成为 stalled -并因此而重新启动。通过在间隔lockDuration(通常是lockRenewTime的一半)上为lockDuration创建一个锁来在内部实现锁定。如果在lockDuration之前可以更新锁定,则该作业将被视为已停止并自动重新启动;将进行双重处理。在以下情况下可能会发生这种情况:

     
      
  1. 运行作业处理器的Node进程意外终止。
  2.   
  3. 您的作业处理器过于占用CPU,导致Node事件循环停滞,结果,Bull无法续签作业锁定(有关如何更好地检测到此错误,请参阅#488)。您可以通过将作业处理器分成较小的部分来解决此问题,以使任何部分都不能阻止Node事件循环。另外,您可以为lockDuration设置传递一个更大的值(权衡是,识别一个真正的停滞的工作将花费更长的时间)。
  4.   
     

这样,您应该始终侦听stalled事件并将其记录到错误监视系统中,因为这意味着您的作业可能会被双重处理。

     

作为一种安全措施,有问题的作业将不会无限期地重新启动(例如,如果作业处理器离开而使其Node进程崩溃),作业将从停止状态恢复最多maxStalledCount次(默认值:{{ 1}})。

答案 4 :(得分:0)

由于面对a problem with too many processor threads,我花了很多时间来研究它。

简而言之,公牛的并发处于队列对象级别,而不是队列级别。

如果您深入研究代码,则在队列对象上调用.process的那一点会调用并发设置。这意味着即使在同一个Node应用程序中,如果您创建多个队列并多次调用.process,它们也会增加可以处理的并发作业数。

一个贡献者发表了以下内容:

  

是的,当我第一次使用Bull时,这也让我有些惊讶   时间。队列选项永远不会在Redis中保留。你可以有很多   根据需要对每个应用程序排队实例,每个实例可以有不同的实例   设置。在您注册并发设置时会设置并发设置   处理器,实际上是特定于每个process()函数调用,而不是   队列。如果要使用命名处理器,则可以多次调用process()   次。每个调用都会注册N个事件循环处理程序(使用Node的   process.nextTick()),并发数量(默认为1)。

因此,您的问题的答案是:是的,如果您在多个节点实例中注册进程处理程序,则将由多个节点实例处理您的进程。