我只想讲述一次压测的故事

起因

前面一篇文章讲了我们面对爆发流量的情况对评论系统的优化,并指队列化定时写入的优化方式有损用户体验,希望根据当前流量智能识别是走队列还是直接落DB,于是我接着做了测试,直接落DB我们发表评论接口的qps居然只有100+r/s,于是进一步做了各种性能测试,希望找到瓶颈在哪

故事发展

起初的目的是找到评论接口的性能瓶颈,但是后来就越做越成漫谈类节目了,下面就开始漫谈…

首先是使用node自己写了个压测工具,原理很简单,使用async.parallel接口每秒并发的发送N个请求,且不等待应答,下一秒直接再发送N个请求。然后写了个最简单的node express框架,定义了一个接口/hello,用pm2启动了10个node进程,前端使用nginx做反向代理转发到各个node进程,然后使用压测工具开始压测,结果日了狗了,每秒并发2000+r/s的时候压测工具就开始各种报错,查看nginx日志各种502,这显然是我的姿势不对的问题,google发现是nginx的最大连接数配置的问题,修改worker_connections为102400,然后再压测,结果还是日了狗了,每秒并发2000+r/s继续报错,但是报错内容不同了,压测客户端显示建立连接失败,这个问题困扰了我很久,查看nginx日志,发现nginx每秒收到的请求数只有1000+,看上去像是压测机发送能力的问题,但是压测机CPU也并没有跑满,4核CPU大概都70%的样子,那为啥呢?后来偶然执行了一下netstat -apn|wc -l,默默地就懂了,压测客户机有大量处于time_wait状态的连接(客户端是主动断链方),然后配置压测客户端机器的tcp_tw_reuse,tcp_tw_recycle,实现time_wait状态的连接复用,我再压!结果依然日了狗了,2000+的并发依然报错,这次又变成服务器端的报错了,nginx日志显示,大量返回499,这次想明白就快多了,nginx主动与node后台服务器建立了大量连接,释放后处于time_wait状态,设置后台服务器机器tcp_tw_reuse,tcp_tw_recycle,实现time_wait状态的连接复用,再压!2000+的并发终于不报错了-_-!,然而我突然又发现我做的这些都没有意义,2000+的并发完全压不出性能瓶颈,node的压测工具压力又上不去,搞了半天还是要换刀~_~!

现在想明白一点了,我就是想知道nginx的性能,node express单进程的性能,node进程集群的性能和mysql的性能,这个反正也不要登录态(之前之所以自己写压测工具,因为我最初想压测的评论接口有登陆态),于是换ab,简单粗暴。

首先是ab压测单个node express进程,qps在3000+的样子,然后压测nginx,启动一个nginx worker,加载nginx echo模块,定义一个location直接echo返回,ab压测性能在20000+的样子(nginx确实屌),然后nginx做前端反向代理到后台10个node,压测下来qps大概15000+,比线性曲线差好远,但是这里也没有深究了,我更想压一下mysql,于是包node express的hello请求处理改成走一条insert sql,结果qps也是15000+,mysql毫无压力,这时候感觉走了这么长一圈路径来压mysql,mysql表示压力不大,只能换思路,直接压了。

用node写了个压测mysql的工具使用async.parallel发送mysql请求,每秒并发N个,且不等返回,下一秒直接发下一波,然后使用pm2启动多个压测进程压测,这样压力=N*进程数,多进程通过redis统计执行结果。然后又碰见日了狗了的问题了,压测客户端大量抛错,mysql服务器毫无压力。然后我用linux mysql客户端连了一下mysql报错too many connection,懂了,mysql最大连接数设置的问题,node mysql使用连接池机制,我设置成100了,10个进程就是1000,mysql默认最大连接数是100,修改max_connections为10000,再压测!压测机12核,服务机4核,mysql cpu压到360%左右,压测机就是狂发insert sql,12核cpu也都快到100%了,qps 20000+的样子,mysql无慢查,客户端无报错,看来20000+ insert无压力。又找了台机器做压测机继续加压,然而现象是qps反而低了,压测机的压测进程内存一直在增加,最后爆炸崩溃了,mysql服务器的压力反而小了,分析原因是应为建立的mysql连接有限,node mysql对每个连接都有队列,上一个请求没有返回,队列阻塞住了,看来还需要加压测集才能压出mysql insert的性能瓶颈,然而并找不到机器了,这个性能和网上的数据也是一个量级的,所以就没有继续深究了。但是上面的压测结果表明mysql还是很猛的,20000+的qps无压力,为毛上次5000+的并发就把我们mysql搞残了(当然,我们现网一个请求会执行很多条sql也是一个原因,大概10几条),于是就模拟现网的sql压测单行update操作,发现单行update操作真的是性能很差,只有2000+的qps(因为mysql innodb的行锁机制,update需要申请写锁,严重影响了性能),这下我要搞清的基础组件性能的问题基本就都清楚了。

总结

看网上的性能数据不如自己压一压,因为机器不同和网上的数据差异还是蛮大的,而且压测过程中真是是会碰到各种坑,对于处理现网高并发问题和系统容量预估有很大帮助。讲了这么多,最开始的目的其实忘了,我是想知道为啥我们评论接口只有100+的qps-_-!我还是继续压测吧…

Loading Disqus comments...
Table of Contents