如何使用消息队列在 Node JS 中执行长事件处理?

Posted

技术标签:

【中文标题】如何使用消息队列在 Node JS 中执行长事件处理?【英文标题】:How to perform long event processing in Node JS with a message queue? 【发布时间】:2021-08-22 01:05:53 【问题描述】:

我正在使用 Google Pub/Sub 作为消息队列在 Node JS 中构建电子邮件处理管道。消息队列有一个限制,它需要在 10 分钟内确认已发送的消息。但是,它发送到 Node JS 服务器的作业可能需要一个小时才能完成。因此,同一个作业可能会运行多次,直到其中一个完成。我担心这会阻塞 Node JS 事件循环并降低服务器速度。

找到附上的架构图。我的问题是:

    鉴于消息队列希望在 10 分钟内得到响应,我应该使用消息队列来启动这个长时间运行的作业,还是应该考虑其他一些架构? 如果启动多个此类作业,我是否应该担心 Node JS 事件循环被阻塞。每个作业基本上都在迭代一个 MongoDB 游标,创建数十万封电子邮件。

【问题讨论】:

好吧,听起来您要么不应该使用该队列(超时无法更改),要么您应该将工作分解为在超时之前很长时间很容易完成的工作。跨度> 我很怀疑你是否有 nodejs 事件循环阻塞问题,只要你所有的 I/O 都使用异步方法。您所做的任何事情听起来都占用大量 CPU,这就是阻塞事件循环的原因。您的整个项目可能受到 MongoDB 和您用于发送电子邮件的任何东西的限制,因此您可能应该确保您没有将其中任何一个压倒到它们变得迟缓并失去吞吐量的地步。 感谢您澄清我可能不必担心事件循环阻塞。 【参考方案1】:

好吧,听起来您要么不应该使用该队列(超时无法更改),要么您应该将您的工作分解为在超时之前很长时间很容易完成的工作。听起来您只需要将工具与工作要求相匹配。如果该队列不符合您的要求,您可能需要不同的机制。我不完全了解您从 Google 的 pub/sub 中需要什么,但是如果您只想序列化对一堆作业的访问,那么创建自己的队列或在 NPM 上找到通用队列通常相当容易。

我相当怀疑你是否存在 nodejs 事件循环阻塞问题,只要你所有的 I/O 都使用异步方法。您所做的一切听起来都占用大量 CPU,这就是阻塞事件循环(长时间运行占用大量 CPU 的操作)的原因。您的整个项目可能同时受到 MongoDB 和您用于发送电子邮件的任何东西的限制,因此您可能应该确保您没有将其中任何一个压倒到导致它们变得迟缓并失去吞吐量的地步。

【讨论】:

【参考方案2】:

回答原来的问题:

    如果消息队列希望在 10 分钟内得到响应,我是否应该使用消息队列来启动这个长时间运行的作业? 我应该考虑其他一些架构吗?

是的,消息队列可以很好地处理这类事件。重要的是要确保最终的动作是幂等的,这样即使你不小心处理了重复的事件,最终的结果也会被应用一次。这个来自 Google Cloud 的 guide 是一个有用的资源,可帮助您使订阅者具有幂等性。

为了绕过 Pub/Sub 的 10 分钟限制,我最终创建了一个内存表来跟踪活动作业。如果正在积极处理作业并且 Pub/Sub 再次发送消息,它将什么也不做。如果服务器重新启动并丢失作业,内存中的表也会消失,因此如果作业不完整,可以再次处理。

    如果启动多个此类作业,我是否应该担心 Node JS 事件循环被阻塞。每个作业基本上都在迭代一个 MongoDB 游标创建数十万封电子邮件。 根据 jfriend00 留下的评论,我暂时忽略了这一点。您还可以对正在处理的作业数量进行速率限制。

【讨论】:

以上是关于如何使用消息队列在 Node JS 中执行长事件处理?的主要内容,如果未能解决你的问题,请参考以下文章

浏览器事件循环与node事件循环

node事件循环和消息队列简单分析

#yyds干货盘点#JS是单线程的,那么JS是如何实现并发请求的?

消息队列何时提供NodeJS的支持

在Node.js中使用RabbitMQ系列二 任务队列

从 node.js 中的消息队列中读取消息