微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用 node.js 和 Bullmq 部署 API 的流程布局

如何解决使用 node.js 和 Bullmq 部署 API 的流程布局

让我先说这个问题,我知道关于这个话题可能不会有明确的、是或否的答案,而且给出的答案可能是由意见驱动的。但是,在部署和操作以下 API 设计方面,我确实需要并感谢您提供建议和/或指导。

我在做什么

对于我的 SaaS,我想通过 API 向我的客户提供其功能。 SaaS 提供的任务是一项长期运行、计算成本高的任务。因此,不幸的是,运行一个简单的、“同步”的 API,调用者等待这个任务的结果作为对他们请求的响应来传递是不合适的。 相反,我选择了一种方法调用者调度 Jobs 并定期查询 API 以查看给定作业是否已完成。我对这个设计很满意。

到目前为止我做了什么

为了实现,我构建/使用了以下技术:

  • Node.js 服务器
  • Express 用于 API 和路由的 npm 包
  • Redis 用于作业调度的数据库
  • bullmq 用于 Redis 连接和队列管理的 npm 包

使用 bullmq,我创建了一个 Queue 并将 Jobs 添加到该队列以响应对给定端点的调用

对我来说,这是在 api.ts(缩短)中:

import Express from "express"
import { Queue } from "bullmq"

const api = Express()
const queue = new Queue("com.mysaas.workerQueue")

api.post("/job",async (request,response) => {
    var data,jobId
    ...

    await queue.add("com.mysaas.defaultJob",data,{
        jobId: jobId,removeOnComplete: true,...
    })

    response.send({
        status: "success",job: jobId
    })
}
...

此外,我创建了处理预定作业的工作线程,由 bullmq 包协调,在幕后使用 Redis

对我来说,这是在 worker.ts(缩短)中:

import { Worker } from "bullmq"

const worker = new Worker("com.mysaas.workerQueue",async (job) => {
    await someWork()
    ...
},{concurrency: 25})

我目前如何在我的开发环境中运行它

tsc 将 Typescript 编译为 Javascript。

我使用 pm2 作为进程管理器和守护进程。要运行 api,我使用以下命令:

pm2 start -i max build/api/api.js

这将为每个可用的 cpu 内核启动一个节点进程(我的开发机器上为 8 个)。

为了运行一个worker,我打开另一个终端并执行:

node build/worker/worker.js

我可以通过打开更多终端并重复上面的命令来添加工作人员。 这样做会导致多个工作人员从 Jobs获取 Queue,分担工作量并同时完成多个作业,从而更快。

所有这些在我的开发环境中都非常有效。

我不确定什么

不知道目前的做法是否适合生产环境。我已经研究了 pm2bullmq 的文档,但我似乎找不到关于如何将这两者结合起来的明确描述。当然,我的目标是最大限度地提高性能和 API 吞吐量。

以下几点仍然在我脑海中悬而未决:

  • pm2 是否会在每个可用内核上实际运行一个进程,即将某个内核分配给给定进程?或者它会产生与核心数量一样多的进程,并且较低级别的系统机制将负载平衡哪个核心的计算时间用于哪个进程。
  • 如果是前者,我从 API 进程的实例启动的子进程是否会被分配给父进程正在运行的核心?
  • 如上所述启动一个工作程序,我们可以提供一个 concurrency 选项,它会告诉 Bullmq 产生尽可能多的进程来运行工作程序代码。并发是否也仅限于分配给主初始值的核心工作进程(以 node build/worker/worker.js 开头)。

鉴于我对上述几点的不确定性,我提炼出三种在生产环境中运行流程的方法

  1. 使用 pm2 start -i max build/api/api.js 启动 API 进程和守护进程。使用 pm2 start -i max build/worker/worker.js 启动工作进程和守护进程。这将为每个可用内核留下 1 个 api 进程和 1 个工作进程。我认为这种方法可以优化 cpu 负载。但是,我不知道应该为 concurrency 工作器的 bullmq 参数分配什么值。

  2. 将工作代码移动/导入 API 进程。使用 pm2 start -i max build/api/api.js 启动 API 进程和守护进程。这将给我留下 1 个进程,其中包括每个内核的 api 和 worker。在我看来,这里的缺点是 worker 和 api 是同一个进程,这意味着如果 api 部分由于某种原因导致进程崩溃,worker 会随之关闭。对吗?

  3. 使用 pm2 start -i max build/api/api.js 启动 API 进程和守护进程。使用 concurrency 参数的高值 (100+) 启动并妖魔化单个工作进程。假设并发工作进程被系统负载平衡到可用内核,这也应该导致优化的 cpu 利用率。缺点是如果单个工作进程崩溃,则在恢复之前不会完成任何工作。

我的直觉告诉我方法 1. 在我的场景中是最好的。但是,这是我第一次将这种 node.js 应用程序部署到生产环境中。因此,我衷心感谢您对所描述项目的任何帮助、建议、指导或反馈。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。