我需要帮助来了解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实例处理吗?
答案 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
之前可以更新锁定,则该作业将被视为已停止并自动重新启动;将进行双重处理。在以下情况下可能会发生这种情况:
- 运行作业处理器的Node进程意外终止。
- 您的作业处理器过于占用CPU,导致Node事件循环停滞,结果,Bull无法续签作业锁定(有关如何更好地检测到此错误,请参阅#488)。您可以通过将作业处理器分成较小的部分来解决此问题,以使任何部分都不能阻止Node事件循环。另外,您可以为lockDuration设置传递一个更大的值(权衡是,识别一个真正的停滞的工作将花费更长的时间)。
这样,您应该始终侦听
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)。
因此,您的问题的答案是:是的,如果您在多个节点实例中注册进程处理程序,则将由多个节点实例处理您的进程。