http keep-alive 相关资料非常多,如果深挖,那可能就长篇大论了,不合适普及,这只是一篇新手入门引导,
主要讲解 node 下 http 请求的坑,以及 keep-alive 的简单使用,后续才会详细剖析原理。
起因
我司使用 node 做中间层开发,所以 api 都是 node 代理转发的,虽然目前 qps 不是特别高,都能满足需求,但压测总归是有的。
不压不知道,一压,emmmmm。。。
搭建个纯净的 node 请求测试环境
先不说业务,我们来搭建个最简单的测试环境,看看压测工具能跑到多少 QPS。
然后我们写个 api 代理模块看看能跑到多少。
使用 node 官方例子 https://nodejs.org/en/about/。
1 | const http = require('http'); |
然后我们用 wrk 来压测,因为简单方便。
- 参数 -c 并发数,就想象成同时请求后台 api 的数量,一个页面往往会调用3-5个后台接口。
- 参数 -d 持续时间,这就是压测本质啊,持续越久,效果越真实,因为很多时候后面会挂掉的。
看看 10 并发,持续 10 秒的情况。
1 | $ wrk -c 10 -d 10 http://localhost:3000 |
可以看出 Req/Sec 的 Avg 值,就是平均 QPS 为 9.59k,因为默认开了2线程,所以总 QPS 为 19k。
好了,测试环境和测试结果已经有了直观的展现。
下面搭建 node 接口代理然后重新压测。
node 接口代理
我们由于业务需求,没用 http-proxy 做直接的代理转发,而是基于 got 模块,自定义的接口模型。
我们先不考虑业务开销,直接代理转发看看结果。
1 | const http = require('http'); |
代码跟刚才一样,只是多了一层 got 代理接口。
这里没用 got stream 直接 pipe 给 res,因为我们的代理接口中会做其他业务操作。
现在来压测下这个服务的情况吧。
1 | $ wrk -c 10 -d 10 http://localhost:8000 |
有点慌,什么情况,怎么会相差这么多。
我们在 3000 服务中加入 console.log(req.headers);
看看 headers 字段。
1 | const server = http.createServer((req, res) => { |
然后访问 8000 服务,看到控制台输出:
1 | { 'user-agent': 'got/9.3.2 (https://github.com/sindresorhus/got)', |
其中 connection 所以每次请求都会重新建立 tcp 连接,浪费了不少性能。
接下来我们要打开 keep-alive 提升代理性能。
开启 keep-alive
安装 agentkeepalive
模块,这是 fengmk2 大佬封装的模块,我们直接使用看看效果先。
1 | $ yarn add agentkeepalive |
然后在 8000 服务中开启代理。
1 | const http = require('http'); |
重新启动,访问 8000 服务,查看 3000 服务控制台。
1 | { 'user-agent': 'got/9.3.2 (https://github.com/sindresorhus/got)', |
看到已经开启了 keep-alive,我们把 3000 服务中的 log 先关掉,否则影响结果。
1 | $ wrk -c 10 -d 10 http://localhost:8000 |
可以看到性能提升了 1 倍,将近 1k 了,但跟原服务 9.59k 还是相差太多。
目前我们只能开多进程来提升整体 QPS 了。
比如开 9 进程,每个进程都能吃到近 1k,差不多可以吃满源服务。
但如果你开了 10 进程甚至更多,那瓶颈就会在源服务上,就需要给源服务加 cpu 或加服务器。
小结
这里还有个会影响结果的因素,而且影响会比较大。
因为是我本地测试,两个服务都跑本地,要严谨的话,应该跑在服务器上,或相同配置的虚拟机中。
不过本文意图是体验 keep-alive 和怎么用 node 吃满接口服务。
所以就不做那么严谨的测试了。
还要吐槽一点,node http 请求,性能真是低下啊,或者是我不知道怎么正确的使用。
因为 autocannon 压测工具,也是 node 写的,但他能吃满,我们直接写请求,只能达到 1/10。
我自己写了个基于 net 的 http 1.1 请求 demo 测试,只提升了100左右,并没有特别大的改进。
因为水平有限,没写基于 net + keep-alive 的 http 1.1 测试,所以不能下结论。
后续我会慢慢研究 keep-alive 然后记录分享的。