【发布时间】:2021-01-26 01:25:45
【问题描述】:
我有一个单线程、基于 Web 的 CPU 密集型工作负载,以 Node.js 服务器(express)的形式实现,并部署在 Kubernetes 上,没有 CPU 请求/限制(尽力而为)。在四核物理机上执行此工作负载平均需要约 700-800 毫秒。服务器位于 Nginx 负载均衡器后面(均采用默认配置)。简而言之,工作量简单如下:
for (let $i = 0; $i < 100; $i++) {
const prime_length = 100;
const diffHell = crypto.createDiffieHellman(prime_length);
const key = diffHell.generateKeys('base64');
checksum(key);
}
我的 Express app.js 中有一个事件处理程序,它在接收或发送请求时在控制台中记录时间戳,如下所示:
app.use((req, res, next) => {
const start = process.hrtime();
console.log(`Received ${req.method} ${req.originalUrl} from ${req.headers['referer']} at {${now()}} [RECEIVED]`)
res.on('close', () => {
const durationInMilliseconds = helper.getDurationInMilliseconds(start);
console.log(`Closed received ${req.method} ${req.originalUrl} from ${req.headers['referer']} {${now()}} [CLOSED] ${durationInMilliseconds.toLocaleString()} ms`)
});
next();
})
我同时从 3 台不同的物理机向该服务发送 3 个并行请求。所有这些服务器以及所有 kubernetes 节点都启用了 NTP,并且它们的本地时间同步在一起。
为了运行流量,我在单独的screen(使用linux的屏幕)中ssh到所有这3台服务器,在命令行中准备curl命令,然后使用以下命令发送并输入以运行流量同时:
screen -S 12818.3 -X stuff "
" & screen -S 12783.2 -X stuff "
" & screen -S 12713.1 -X stuff "
"
从日志中,我可以看到所有 3 个请求同时发送:在 17:26:37.888
有趣的是,服务器在完成下一个请求后立即收到每个请求:
- 请求 1 在 17:26:37.922040382 收到,需要 740.128 毫秒 过程
- 请求 2 在 17:26:38.663390107 收到,需要 724.524ms 过程
- 请求 3 在 17:26:39.388508923 收到,需要 695.894 毫秒 过程
这是容器中生成的日志(使用kubectl logs -l name=s1 --tail=9999999999 --timestamps提取):
2020-10-11T17:26:37.922040382Z Received GET /s1/cpu/100 from undefined at {1602429997921393902} [RECEIVED]
2020-10-11T17:26:38.662193765Z Closed received GET /s1/cpu/100 from undefined {1602429998661523611} [CLOSED] 740.128 ms
2020-10-11T17:26:38.663390107Z Received GET /s1/cpu/100 from undefined at {1602429998662810195} [RECEIVED]
2020-10-11T17:26:39.387987847Z Closed received GET /s1/cpu/100 from undefined {1602429999387339320} [CLOSED] 724.524 ms
2020-10-11T17:26:39.388508923Z Received GET /s1/cpu/100 from undefined at {1602429999387912718} [RECEIVED]
2020-10-11T17:26:40.084479697Z Closed received GET /s1/cpu/100 from undefined {1602430000083806321} [CLOSED] 695.894 ms
我使用htop 和pidstat 检查了CPU 使用率,奇怪的是一直只使用1 个内核...
我期待 node.js 服务器同时接收所有请求并在不同的线程中处理它们(通过生成新线程),但似乎并非如此。如何让 node.js 并行处理请求,并利用它拥有的所有内核?
这是我的完整代码:
var express = require('express');
const crypto = require('crypto');
const now = require('nano-time');
var app = express();
function checksum(str, algorithm, encoding) {
return crypto
.createHash(algorithm || 'md5')
.update(str, 'utf8')
.digest(encoding || 'hex');
}
function getDurationInMilliseconds (start) {
const NS_PER_SEC = 1e9;
const NS_TO_MS = 1e6;
const diff = process.hrtime(start);
return (diff[0] * NS_PER_SEC + diff[1]) / NS_TO_MS;
}
app.use((req, res, next) => {
const start = process.hrtime();
console.log(`Received ${req.method} ${req.originalUrl} from ${req.headers['referer']} at {${now()}} [RECEIVED]`)
res.on('close', () => {
const durationInMilliseconds = getDurationInMilliseconds(start);
console.log(`Closed received ${req.method} ${req.originalUrl} from ${req.headers['referer']} {${now()}} [CLOSED] ${durationInMilliseconds.toLocaleString()} ms`)
});
next();
})
app.all('*/cpu', (req, res) => {
for (let $i = 0; $i < 100; $i++) {
const prime_length = 100;
const diffHell = crypto.createDiffieHellman(prime_length);
const key = diffHell.generateKeys('base64');
checksum(key);
}
res.send("Executed 100 Diffie-Hellman checksums in 1 thread(s)!");
});
module.exports = app;
app.listen(9121)
【问题讨论】:
标签: node.js multithreading express nginx kubernetes