如何避免 Nest.Js / Node.Js 进程占用 CPU 的 100%?
How to avoid a Nest.Js / Node.Js process taking up 100% of the CPU?
我在 Nest.Js / Node.Js 上有一个应用程序 运行ning 进行文本处理,因此它有一个 .map
(或 .forEach
) 需要大量资源的迭代(标记一个句子,然后删除停用词等——每个句子可能有数万个)。
为了可重复性,我在下面提供了我使用的代码,没有文本处理细节——只是一个很长的重循环来模拟我的问题:
const before = Date.now()
const statements = [...Array(100)]
let l = 0
let p = 0
const processed =
statements.map((value, index) => {
// a set of consecutive functions that take a long time to execute
for (let i = 0; i < 100000; i++) {
l = l + i * Math.random()
}
// console.log(index + ' ' + l + ' ' + (Date.now() - before))
p = index
return l
})
console.log(processed)
const after = Date.now()
console.log(p + ' results in ' + (after - before) + ' ms')
对于非常大的文件,该进程占用了 100% CPU,因此应用程序变得无响应。
我想知道您是否知道任何解决方案可以防止该应用占用所有可用的 CPU。比如有没有一种方法可以将任何单个进程设置为占用 80% 而始终为其他用户留出 20%?
PS 我 运行 它来自 Amazon 的 ECS,所以我当然可以创建集群,也可以使用 PM2 进行集群化,但我想知道如何避免内部单个进程的 100% 负载Javascript / Node.Js 应用程序本身。我提到 Nest.Js 框架是因为也许那里也有解决方案。
就限制单个线程使用 100% CPU 而言,在服务器级别有一些架构方法可以做到这一点,但我认为这并不是您真正想要的结果。 CPU 使用 100% 不是问题(CPUs 通常会在很短的时间内飙升至 100% CPU 以尽快处理事情),更多的是它会长时间使用 100% CPU 并阻止其他应用程序获得 CPU 周期。
从我在示例代码中看到的情况来看,在 NestJS 中使用队列可能是更好的解决方案。 Documentation can be seen here using Bull. 这样您就可以利用正在处理的作业的速率限制并在那里进行调整,其他应用程序将不会等待整个过程的完成。
例如,如果您有 100,000 个文件要处理,您可能希望创建一个一次处理其中 1,000 个文件的作业,并创建 100 个作业以放入队列中。对于需要大量计算时间的进程来说,这是一个相当典型的进程。
我知道这不是您正在寻找的确切答案,但希望它会有所帮助并提供一个不特定于您的体系结构的解决方案。
JS 是一种同步语言。现在,在您的节点应用程序上使用它时,如果操作不当,您最终可能会阻塞主线程。
https://nodejs.org/en/docs/guides/dont-block-the-event-loop/
Node.js有两种线程:一种是Event Loop,另一种是k Workers。 Event Loop负责JavaScript回调和non-blockingI/O,一个Worker执行完成异步请求的C++代码对应的任务,包括阻塞I/O和CPU-intensive 工作。两种类型的线程一次只能处理一个 activity。如果任何回调或任务需要很长时间,线程 运行 就会被阻塞。如果您的应用程序进行阻塞回调或任务,这最多会导致吞吐量下降 (clients/second),最坏情况下会导致完全拒绝服务。
要编写 high-throughput,更多 DoS-proof 网络服务器,您必须确保在良性输入和恶意输入上,您的事件循环和您的 Workers 都不会阻塞。
一个请求是将操作卸载到另一个区域。
- 例如,您可以对数据库进行部分操作吗
- 如果您正在处理 mongodb,可以 mongodb 管理聚合中的 replaceAll,或者进行一些其他操作
- 这样您就不必在节点应用程序级别执行此操作
我在 Nest.Js / Node.Js 上有一个应用程序 运行ning 进行文本处理,因此它有一个 .map
(或 .forEach
) 需要大量资源的迭代(标记一个句子,然后删除停用词等——每个句子可能有数万个)。
为了可重复性,我在下面提供了我使用的代码,没有文本处理细节——只是一个很长的重循环来模拟我的问题:
const before = Date.now()
const statements = [...Array(100)]
let l = 0
let p = 0
const processed =
statements.map((value, index) => {
// a set of consecutive functions that take a long time to execute
for (let i = 0; i < 100000; i++) {
l = l + i * Math.random()
}
// console.log(index + ' ' + l + ' ' + (Date.now() - before))
p = index
return l
})
console.log(processed)
const after = Date.now()
console.log(p + ' results in ' + (after - before) + ' ms')
对于非常大的文件,该进程占用了 100% CPU,因此应用程序变得无响应。
我想知道您是否知道任何解决方案可以防止该应用占用所有可用的 CPU。比如有没有一种方法可以将任何单个进程设置为占用 80% 而始终为其他用户留出 20%?
PS 我 运行 它来自 Amazon 的 ECS,所以我当然可以创建集群,也可以使用 PM2 进行集群化,但我想知道如何避免内部单个进程的 100% 负载Javascript / Node.Js 应用程序本身。我提到 Nest.Js 框架是因为也许那里也有解决方案。
就限制单个线程使用 100% CPU 而言,在服务器级别有一些架构方法可以做到这一点,但我认为这并不是您真正想要的结果。 CPU 使用 100% 不是问题(CPUs 通常会在很短的时间内飙升至 100% CPU 以尽快处理事情),更多的是它会长时间使用 100% CPU 并阻止其他应用程序获得 CPU 周期。
从我在示例代码中看到的情况来看,在 NestJS 中使用队列可能是更好的解决方案。 Documentation can be seen here using Bull. 这样您就可以利用正在处理的作业的速率限制并在那里进行调整,其他应用程序将不会等待整个过程的完成。
例如,如果您有 100,000 个文件要处理,您可能希望创建一个一次处理其中 1,000 个文件的作业,并创建 100 个作业以放入队列中。对于需要大量计算时间的进程来说,这是一个相当典型的进程。
我知道这不是您正在寻找的确切答案,但希望它会有所帮助并提供一个不特定于您的体系结构的解决方案。
JS 是一种同步语言。现在,在您的节点应用程序上使用它时,如果操作不当,您最终可能会阻塞主线程。
https://nodejs.org/en/docs/guides/dont-block-the-event-loop/
Node.js有两种线程:一种是Event Loop,另一种是k Workers。 Event Loop负责JavaScript回调和non-blockingI/O,一个Worker执行完成异步请求的C++代码对应的任务,包括阻塞I/O和CPU-intensive 工作。两种类型的线程一次只能处理一个 activity。如果任何回调或任务需要很长时间,线程 运行 就会被阻塞。如果您的应用程序进行阻塞回调或任务,这最多会导致吞吐量下降 (clients/second),最坏情况下会导致完全拒绝服务。
要编写 high-throughput,更多 DoS-proof 网络服务器,您必须确保在良性输入和恶意输入上,您的事件循环和您的 Workers 都不会阻塞。
一个请求是将操作卸载到另一个区域。
- 例如,您可以对数据库进行部分操作吗
- 如果您正在处理 mongodb,可以 mongodb 管理聚合中的 replaceAll,或者进行一些其他操作
- 这样您就不必在节点应用程序级别执行此操作