精华 多核单服务器各种配置和业务压力下的node.js性能测试
发布于 13 年前 作者 DoubleSpout 16217 次浏览 最后一次编辑是 8 年前

上篇文章我提到用taskset绑定多核cpu来运行node.js可以提高其稳定性和性能,我们拿数据说话,今天花了一天时间用来做压力测试,结果虽然仅供参考,但是也能说明一些问题。 <br/> <br/><strong>声明:此次性能测试数据绝对真实,结果仅供参考。</strong> <br/> <br/>网络环境:内网 <br/>压力测试服务器: <br/>服务器系统:Linux 2.6.18 <br/>服务器配置:Intel® Xeon™ CPU 3.40GHz 4 CPUS <br/>内存:6GB <br/> <br/>发包服务器: <br/>发包工具:apache 2.2.19自带的ab测试工具 <br/>服务器系统:Linux 2.6.18 <br/>服务器配置:Pentium® Dual-Core CPU E5800 @ 3.20GHz 2CPUS <br/>内存:1GB <br/> <br/><strong>第一轮测试:空框架测试 <br/></strong> <br/> <br/><strong>服务端node.js代码:</strong> <br/><pre>var http=require(‘http’); <br/>var server = http.createServer(function(request, response) { <br/>response.writeHead(200, {‘Content-Type’:‘text/plain’}); <br/>response.end(‘Hello World\n’); }) <br/>server.listen(8880); //注:这里会根据情况设置8880-8883 这4个端口 <br/>console.log(‘Server running at http://10.1.10.150:8880/’);</pre> <br/>灰常简单的代码,返回”hello world”,也是官方示例代码。 我们先测node.js空框架裸奔性能,具体业务的性能要接下来会进行测试。 <br/> <br/><strong>Nginx端代码:</strong> <br/><pre>upstream node_server_pool { <br/>server 10.1.10.150:8880 ; <br/>server 10.1.10.150:8881 ; <br/>server 10.1.10.150:8882 ; <br/>server 10.1.10.150:8883 ; <br/>} <br/>server { <br/>listen 8888; <br/>server_name 10.1.10.150; <br/>location / { <br/>proxy_pass http://node_server_pool; <br/>} <br/>}</pre> <br/><strong>第一种测试:在服务端只开一个node.js服务,端口为8880,直接通过ab对8880端口进行压力测试。 </strong> <table border=“0” cellspacing=“0” cellpadding=“0”> <tbody> <tr> <td valign=“top”></td> <td valign=“top”>1000/10</td> <td valign=“top” width=“71”>1000/30</td> <td valign=“top” width=“71”>3000/10</td> <td valign=“top” width=“71”>3000/30</td> <td valign=“top” width=“71”><span style=“color: #ff0000”>5000/30</span></td> <td valign=“top” width=“71”>7000/30</td> <td valign=“top” width=“71”>8000/30</td> </tr> <br/><tr> <br/><td valign=“top” width=“71”>Rps</td> <br/><td valign=“top” width=“71”>1801</td> <br/><td valign=“top” width=“71”>1613</td> <br/><td valign=“top” width=“71”>1995</td> <br/><td valign=“top” width=“71”>1993</td> <br/><td valign=“top” width=“71”><span style=“color: #ff0000”>2403</span></td> <br/><td valign=“top” width=“71”>2233</td> <br/><td valign=“top” width=“71”>1963</td> <br/></tr> <br/><tr> <br/><td valign=“top” width=“71”>Tpq</td> <br/><td valign=“top” width=“71”>0.63</td> <br/><td valign=“top” width=“71”>0.62</td> <br/><td valign=“top” width=“71”>0.49</td> <br/><td valign=“top” width=“71”>0.46</td> <br/><td valign=“top” width=“71”><span style=“color: #ff0000”>0.42</span></td> <br/><td valign=“top” width=“71”>0.45</td> <br/><td valign=“top” width=“71”>0.52</td> <br/></tr> <br/><tr> <br/><td valign=“top” width=“71”>fail</td> <br/><td valign=“top” width=“71”>0</td> <br/><td valign=“top” width=“71”>0</td> <br/><td valign=“top” width=“71”>0</td> <br/><td valign=“top” width=“71”>0</td> <br/><td valign=“top” width=“71”><span style=“color: #ff0000”>0</span></td> <br/><td valign=“top” width=“71”>0</td> <br/><td valign=“top” width=“71”>170</td> <br/></tr> <br/></tbody> <br/></table> <br/>说明: <br/>1000/10:代表命令./ab -c 1000 -t 10 http://10.1.10.150:8880/ <br/>rps:代表每秒处理请求数,并发的主要指标 <br/>tpq:每个请求处理的时间,单位毫秒。 <br/>fail:代表平均处理失败请求数。 <br/> <br/><strong>第二种测试: <br/></strong> <br/>Node.js开8882-8883这2个端口,通过taskset分别绑定到2个不同的CPU上去,然后利用nginx反向代理和负载均衡,nginx监听8888端口,将nginx开两个进程,绑定到另外两个cpu上,所以ab测试包将发到8888端口。<strong> <br/></strong> <br/><span style=“color: #3366ff”>小窍门:之前我曾经开4个node.js绑定4个CPU然后nginx开4个进程,绑定4个CPU,结果悲剧了,压测一直卡死,原来是node.js和nginx抢CPU造成的,后来楚汉分界,nginx用前2个CPU,而node.js拿后两个cpu。另外nginx也像汽车一样,要先热车,重启后先随便压测几次,然后过一会水温就上来了,就可以踩油门了,哈哈。</span> <br/> <br/>第一步对nginx负载均衡的测试,访问8888端口,然后一个个关掉node.js进程,发现当全部关掉后,页面不能访问,负载均衡设置成功。 第二步测试cpu绑定情况,单独对8881-8882端口进行ab压测,发现只有对应绑定cpu功耗很高,绑定单独cpu成功。 <br/><table border=“0” cellspacing=“0” cellpadding=“0”> <br/><tbody> <br/><tr> <br/><td valign=“top” width=“71”></td> <br/><td valign=“top” width=“71”>1000/30</td> <br/><td valign=“top” width=“71”><span style=“color: #ff0000”>3000/30</span></td> <br/><td valign=“top” width=“71”>4000/30</td> <br/><td valign=“top” width=“71”>5000/30</td> <br/><td valign=“top” width=“71”>7000/30</td> <br/></tr> <br/><tr> <br/><td valign=“top” width=“71”>Rps</td> <br/><td valign=“top” width=“71”>2526</td> <br/><td valign=“top” width=“71”><span style=“color: #ff0000”>2471</span></td> <br/><td valign=“top” width=“71”>2059</td> <br/><td valign=“top” width=“71”>2217</td> <br/><td valign=“top” width=“71”>2016</td> <br/></tr> <br/><tr> <br/><td valign=“top” width=“71”>Tpq</td> <br/><td valign=“top” width=“71”>0.43</td> <br/><td valign=“top” width=“71”><span style=“color: #ff0000”>0.41</span></td> <br/><td valign=“top” width=“71”>0.47</td> <br/><td valign=“top” width=“71”>0.44</td> <br/><td valign=“top” width=“71”>0.48</td> <br/></tr> <br/><tr> <br/><td valign=“top” width=“71”>fail</td> <br/><td valign=“top” width=“71”>0</td> <br/><td valign=“top” width=“71”><span style=“color: #ff0000”>0</span></td> <br/><td valign=“top” width=“71”>0</td> <br/><td valign=“top” width=“71”>0</td> <br/><td valign=“top” width=“71”>50</td> <br/></tr> <br/></tbody> <br/></table> <br/><strong> <br/>第三种测试: <br/></strong> <br/>Node.js开8881-8883这3个端口,通过taskset分别绑定到3个不同的CPU上去,然后利用nginx反向代理和负载均衡,nginx监听8888端口,将nginx开一个进程,绑定到另外第一个cpu上,所以ab测试包将发到8888端口。 <br/><table border=“0” cellspacing=“0” cellpadding=“0”> <br/><tbody> <br/><tr> <br/><td valign=“top” width=“71”></td> <br/><td valign=“top” width=“71”>1000/30</td> <br/><td valign=“top” width=“71”><span style=“color: #ff0000”>3000/30</span></td> <br/><td valign=“top” width=“71”><span style=“color: #000000”>5000/30</span></td> <br/><td valign=“top” width=“71”>7000/30</td> <br/></tr> <br/><tr> <br/><td valign=“top” width=“71”>Rps</td> <br/><td valign=“top” width=“71”>2269</td> <br/><td valign=“top” width=“71”><span style=“color: #ff0000”>2305</span></td> <br/><td valign=“top” width=“71”><span style=“color: #000000”>2164</span></td> <br/><td valign=“top” width=“71”>2149</td> <br/></tr> <br/><tr> <br/><td valign=“top” width=“71”>Tpq</td> <br/><td valign=“top” width=“71”>0.43</td> <br/><td valign=“top” width=“71”><span style=“color: #ff0000”>0.43</span></td> <br/><td valign=“top” width=“71”><span style=“color: #000000”>0.45</span></td> <br/><td valign=“top” width=“71”>0.48</td> <br/></tr> <br/><tr> <br/><td valign=“top” width=“71”>fail</td> <br/><td valign=“top” width=“71”>0</td> <br/><td valign=“top” width=“71”><span style=“color: #ff0000”>0</span></td> <br/><td valign=“top” width=“71”><span style=“color: #000000”>0</span></td> <br/><td valign=“top” width=“71”>0</td> <br/></tr> <br/></tbody> <br/></table> <br/><strong> <br/>第一轮评测总结: </strong> <br/><table border=“0” cellspacing=“0” cellpadding=“0”> <br/><tbody> <br/><tr> <br/><td valign=“top” width=“71”></td> <br/><td valign=“top” width=“71”>单进程</td> <br/><td valign=“top” width=“71”>双进程</td> <br/><td valign=“top” width=“71”>三进程</td> <br/></tr> <br/><tr> <br/><td valign=“top” width=“71”>commond</td> <br/><td valign=“top” width=“71”>5000/30</td> <br/><td valign=“top” width=“71”>3000/30</td> <br/><td valign=“top” width=“71”>3000/30</td> <br/></tr> <br/><tr> <br/><td valign=“top” width=“71”>Rps</td> <br/><td valign=“top” width=“71”>2403</td> <br/><td valign=“top” width=“71”>2471</td> <br/><td valign=“top” width=“71”>2305</td> <br/></tr> <br/><tr> <br/><td valign=“top” width=“71”>Tpq</td> <br/><td valign=“top” width=“71”>0.42</td> <br/><td valign=“top” width=“71”>0.41</td> <br/><td valign=“top” width=“71”>0.43</td> <br/></tr> <br/><tr> <br/><td valign=“top” width=“71”>fail</td> <br/><td valign=“top” width=“71”>0</td> <br/><td valign=“top” width=“71”>0</td> <br/><td valign=“top” width=“71”>0</td> <br/></tr> <br/></tbody> <br/></table> <br/><strong>注:这里仅拿出相近的峰值的数据进行比较。 <br/></strong> <br/>为什么第三种方式会比第二种方式性能更差呢?明明多开了一个node.js进程来处理请求,其实是nginx转发速度造成的,这就类似让一辆STI跑在小马路上,纵然STI马力大,但是路况太差,跑不快,不如让迈腾跑在高架上。 <br/> <br/><span style=“color: #3366ff”>在空框架,不涉及业务处理的情况下,单开node.js和双开node.js性能相差无及,毕竟nginx转发也要消耗掉一部分性能,提升大约5%-10%左右。当然稳定性提升100%。 <br/></span> <br/>接下来我们开始第二轮性能测试,在有业务处理压力的情况下,我们看看2者之间的差别。 <br/><strong></strong> <br/><strong>第二轮测试:有业务处理压力的测试 <br/></strong> <br/>nginx代码不变,node.js代码改为:<strong> </strong> <br/><pre>var http = require(‘http’); <br/>var server = http.createServer(function (request, response) { <br/>for(var i=0;i<180000;i++){ <br/>var j = i/3; <br/>} <br/>response.writeHead(200, {‘Content-Type’: ‘text/plain’}); <br/>response.end(‘Hello World\n’); }) <br/>server.listen(8882); <br/>console.log(‘Server running at http://10.1.10.150:8882/’);</pre> <br/>这里唯一不同的是增加了一个循环,模拟业务处理。 <br/><strong> <br/></strong> <br/><strong>第二轮测试结果:</strong> <br/><pre> <br/><table border=“0” cellspacing=“0” cellpadding=“0”> <br/><tbody> <br/><tr> <br/><td valign=“top” width=“81”>process</td> <br/><td valign=“top” width=“81”><span style=“color: #0000ff”>单进程</span></td> <br/><td valign=“top” width=“81”><span style=“color: #ff6600”>双进程</span></td> <br/><td valign=“top” width=“81”><span style=“color: #008800”>三进程</span></td> <br/><td valign=“top” width=“81”><span style=“color: #0000ff”>单进程</span></td> <br/><td valign=“top” width=“81”><span style=“color: #ff6600”>双进程</span></td> <br/><td valign=“top” width=“81”><span style=“color: #008800”>三进程</span></td> <br/><td valign=“top” width=“81”><span style=“color: #0000ff”>单进程</span></td> <br/><td valign=“top” width=“81”><span style=“color: #ff6600”>双进程</span></td> <br/><td valign=“top” width=“81”><span style=“color: #008800”>三进程</span></td> <br/></tr> <br/><tr> <br/><td valign=“top” width=“81”>Commond</td> <br/><td valign=“top” width=“81”>1000/30</td> <br/><td valign=“top” width=“81”>1000/30</td> <br/><td valign=“top” width=“81”>1000/30</td> <br/><td valign=“top” width=“81”>3000/30</td> <br/><td valign=“top” width=“81”>3000/30</td> <br/><td valign=“top” width=“81”>3000/30</td> <br/><td valign=“top” width=“81”>5000/30</td> <br/><td valign=“top” width=“81”>5000/30</td> <br/><td valign=“top” width=“81”>5000/30</td> <br/></tr> <br/><tr> <br/><td valign=“top” width=“81”>rps</td> <br/><td valign=“top” width=“81”>203</td> <br/><td valign=“top” width=“81”>311</td> <br/><td valign=“top” width=“81”>432</td> <br/><td valign=“top” width=“81”>198</td> <br/><td valign=“top” width=“81”>300</td> <br/><td valign=“top” width=“81”>451</td> <br/><td valign=“top” width=“81”>202</td> <br/><td valign=“top” width=“81”>294</td> <br/><td valign=“top” width=“81”>412</td> <br/></tr> <br/><tr> <br/><td valign=“top” width=“81”>tpq</td> <br/><td valign=“top” width=“81”>4.93</td> <br/><td valign=“top” width=“81”>3.2</td> <br/><td valign=“top” width=“81”>2.37</td> <br/><td valign=“top” width=“81”>5.03</td> <br/><td valign=“top” width=“81”>3.33</td> <br/><td valign=“top” width=“81”>2.2</td> <br/><td valign=“top” width=“81”>4.94</td> <br/><td valign=“top” width=“81”>3.42</td> <br/><td valign=“top” width=“81”>2.44</td> <br/></tr> <br/><tr> <br/><td valign=“top” width=“81”>50%req</td> <br/><td valign=“top” width=“81”>4500ms</td> <br/><td valign=“top” width=“81”>1500ms</td> <br/><td valign=“top” width=“81”>750ms</td> <br/><td valign=“top” width=“81”>5000ms</td> <br/><td valign=“top” width=“81”>2000ms</td> <br/><td valign=“top” width=“81”>1500ms</td> <br/><td valign=“top” width=“81”>7000ms</td> <br/><td valign=“top” width=“81”>2000ms</td> <br/><td valign=“top” width=“81”>2000ms</td> <br/></tr> <br/><tr> <br/><td valign=“top” width=“81”>Fail</td> <br/><td valign=“top” width=“81”>0</td> <br/><td valign=“top” width=“81”>0</td> <br/><td valign=“top” width=“81”>0</td> <br/><td valign=“top” width=“81”>0</td> <br/><td valign=“top” width=“81”>0</td> <br/><td valign=“top” width=“81”>0</td> <br/><td valign=“top” width=“81”>235</td> <br/><td valign=“top” width=“81”>0</td> <br/><td valign=“top” width=“81”>0</td> <br/></tr> <br/></tbody> <br/></table> <br/></pre> <br/>说明: <br/>1000/30:代表命令./ab -c 1000 -t 30 http://10.1.10.150:8888/ <br/>rps:代表每秒处理请求数,并发的主要指标 <br/>tpq:每个请求处理的时间,单位毫秒。 <br/>fail:代表平均处理失败请求个数 <br/>50%req:代表50%的请求在多少毫秒内返回。 <br/> <br/><strong>两轮测试结果总结: <br/></strong> <br/>Var type1 = 裸奔node.js服务 <br/>Var type2= nginx反向代理+负载均衡+node.js多开绑定cpu <br/> <br/><strong><span style=“color: #ff6600”>在业务处理比较简单的情况下,type1和type2的性能差别不是很大,但是当业务处理压力上来以后,type2每秒处理请求数性能提升100%,从用户响应速度上提升200%,从稳定性上提升200%。综上所述,在一台4核cpu服务器上需要启动node.js服务的话,最好的方式就是前1个cpu绑定nginx进程使用,后3个cpu绑定node.js进程。</span> <br/></strong> <br/>我的博客地址,内有图有真相:http://snoopyxdy.blog.163.com/

8 回复

第二轮测试的场景是cpu密集型,不适合nodejs。 <br/> <br/>建议加上第三种测试,测试网络IO或者磁盘IO等

同意, node.js 最风騒的地方就是非阻塞异步响应哪! <br/>建议,再加个测试四: <br/>- 对 redis 和 dbd/sqlite 纯内存DB 和 纯文件DB 访问 的压力测试

感谢suqian大师的关注!泪流满面啊~不胜荣幸啊! <br/>node.js的优势确实是在非阻塞上,CPU-bound测不出好成绩。 <br/>我们公司现在用node.js去跑异步脚本,就是对数据从memcache分析转存mysql。 <br/>不过本文旨在说明用nginx+node.js可以提升性能和稳定性,不在考察node.js的压测性能。下周正好手头有几台服务器,这两天配置好connection pool,准备和PHP进行一次mysql、redis和memcache的性能对比,希望大师继续关注啊。 <br/>其实在写本文时我也对multi-node和spark进行了压力测试,“hello world”裸奔在5000client时qps 4000+,但是请求响应时间不如nginx,所以如果单服务器的话,我们实际生产还是会选择nginx+node.js,毕竟nginx有更丰富和高效的转发策略。

我很惊讶NodeJS的性能, 以前测试Apache/nginx的性能都是以{万请求/秒}为单位的, 这里竟然普遍只有2000多 <br/> <br/>即使是tomcat/jetty这种应用服务器, 也能达到1w+的rps吧

Nodejs跟netty不知道如何~

貌似Markdown语法裸奔了????页面内容看起来费劲啊!

楼主这种测试没啥意思,NodeJS的强项是IO异步来完成高并发响应的

nodejs就是个消息处理器, 所有的操作都是操作系统完成的,想计算,还不如让nodejs调用一段shell脚本。

回到顶部