网易云信IM系统中的Web版使用了Socket.IO实现浏览器环境下的长链服务;区别于常规的长链服务,为该服务的压测提出了一些新的挑战,本文总结了测试过程当中的一些收获供参考。
Part1测试工具选项
1、工具选型
Gatling
Node.js
JMeter
Java WebSocket
这些工具都是能够支持WebSocket协议的工具,主要从如下几个方面进行对比:
上手难易程度
测试资源开销
和性能测试平台结合的难易程度
2、对比过程
对比场景
(1)5000个用户,每秒钟发送100个登陆请求,并保持链接
(2)5000个用户,每隔5s发送一条点对点消息,即发送消息频率1000
工具使用过程html
工具简介:Gatling是一款基于Scala 开发的高性能服务器性能测试工具,它主要用于对服务器进行负载测试,并分析和测量服务器的各类性能指标。
工具语言:Scala语言
工具官网:http://gatling.io/docs/2.0.0-...
相关代码:前端
遇到的问题:
(1)scale语言比较陌生,脚本编写时困难较多,目前暂未实现隔必定时间,即发心跳又发消息的场景;
(2)没法和性能测试平台结合,系统整合成本比较高;java
工具简介:
Node.js是一个基于Chrome V8引擎的JavaScript运行环境。Node.js使用了一个事件驱动、非阻塞式I/O的模型,使其轻量又高效;而Socket.IO是一个基于Node.js架构体系的且原生支持WebSocket协议,可用做实时通讯的软件包。Socket.IO为跨浏览器构建实时应用提供了完整的封装,且彻底由JavaScript实现,语言更容易理解。
工具语言:JavaScript
工具官网:
• http://socket.io/docs/
• http://nodejs.cn/
相关代码:node
遇到问题:
(1)多节点并发分布式控制
(2) 整合到现有的性能测试平台程序员
工具简介:
JMeter是比较常见的性能测试开源工具,支持多种协议而且能够自定义java请求,更加灵活。
工具语言:
(1)Java
(2) JMeter xml脚本文件
工具官网:
http://jmeter.apache.org/user...
https://blog.flood.io/socket-...
相关代码:web
遇到问题
JMeter的工具本上是同步的,若是创建1万个链接的话,须要启动1万个线程处理,所以不适合测试高并发长链接的场景。apache
工具简介
Jetty提供了功能更强的WebSocket API,使用一个公共的核心API供WebSocket的服务端和客户端使用。
工具语言: Java
工具官网
http://www.eclipse.org/jetty/
相关代码json
遇到问题
须要本身写并发控制
3、对比结果总结
由于用来作性能压测,因此考虑到压测客户端须要实现高并发请求,选择Gatling和Socket.IO作了简单的对比测试。后端
Part2 长链服务端性能问题的定位
如第一部分所述,咱们最终选择用Socket.IO实现了并发压测的长链客户端,下面简单说明下长链服务器端测试的一些收获;
首先,简单描述下被测试服务器的功能浏览器
为此,咱们肯定该服务主要的测试点为
如下是此次测试过程当中遇到的一系列问题:
问题1:最大链接数只能达到65K+
65535,对于程序员来讲,这是一个很敏感的数字,由于一台服务器,限制的最大端口号即为65535,因此出现这个问题后:
第一反应:端口号不够用了。 分析认为Link服务做为服务端,对外提供的服务端口仅有一个,因此不存在服务端端口号不够用的状况;
第二反应:句柄数不够用了。文件句柄数至关于文件的标识符,创建一条socket链接,一样会使用一个文件句柄,而系统默认的单个进程使用的文件句柄为1024;
对于这种须要保持大量链接的服务来讲,通常状况下都是须要修改文件句柄数的,文件句柄数修改的方法以下:
A)查看单个进程使用的最大文件句柄数的方法:
B)查看当前进程打开了多少个文件句柄呢:
C)修改Linux的最大文件句柄数限制的方法:
1)ulimit -n 65535
在当前session有效,用户退出或者系统从新后恢复默认值
2)修改用户下的.profile文件:在.profile文件中添加:ulimit -n 65535
只对当前用户有效
3)修改文件/etc/security/limits.conf,在文件中添加:
(当即生效-当前session中运行ulimit -a命令没法显示)
4)修改文件/etc/sysctl.conf添加:
运行命令:/sbin/sysctl -p 使配置生效
可是修改文件句柄的限制后,该问题依然没有获得解决。
这个时候想到可使用dmesg查看系统日志,dmesg命令能够显示Linux内核的环形缓冲区信息,能够从中得到诸如系统架构、CPU和挂载的硬件,RAM等运行级别的大量系统信息,所以dmesg命令在设备故障的诊断方面是很是重要的。经过dmesg,查看到了以下问题:
从上面的信息可见conntrack表满了,那么conntrack表是作什么的?
nf_conntrack/ip_conntrack用来跟踪链接条目,会使用一个哈希表来记录 established 的记录
nf_conntrack 在 2.6.15 被引入,而 ip_conntrack 在 2.6.22 被移除,若是该哈希表满了dmesg命令就会出现:
nf_conntrack: table full, dropping packet
如何修改conntrack表的大小
到此为止,这个问题咱们算是解决了,总结下,遇到的网络相关的知识点包括 文件句柄 和conntrack表。
问题2:在某些用例场景下,稳定链接只能创建3800+
这个问题的前提是某些时候,也就是说偶现的,这种状况基本上能够排除是应用程序内部的问题。那对于这个问题咱们使用了哪些定位手段呢?
watch -d 按期查看一些信息,默认是2s;
netstat -st | grep ignored 查看TCP链接的一些统计信息;
可见有SYNs to LISTEN sockets ignored在不停增长,这代表收到链接创建过程当中的三次握手的ACK包,可是因各类缘由(包括accept队列满) 建立socket失败;
backlog:简单理解来讲,链接已经在TCP层创建成功(完成了三次握手的过程)可是尚未被应用程序所接受,这种状况下,该连接会存放到backlog这样一个缓冲队列内
经过上面这个命令能够看到应用程序的backlog队列已经满了,可是即使把这个值调整为1024,该队列仍是会满的。
到这儿,咱们的定位过程陷入了僵局,下一步该怎么定位呢?这期间咱们查看了内存信息,CPU使用状况等,均没有找对地方;可是在定位过程当中,咱们发现,有时候JStack、JProfiler等工具都没法连上该服务了。
忽然想到文件句柄是否是满了?又执行了如下几条命令:
/proc/{pid}这个目录下了对应了全部在运行的进程的相关信息,
经过查看/proc/{pid}/fd目录下的个数咱们能够看到当前进程使用的文件句柄数有多少。
经过查看limits文件里面的值,能够看到系统对该进程的一些限制,不幸的是,出现这个问题的时候,max open files这个值被限制为了4096。
调整该值以后最终解决了这个问题
问题3:大量的链接创建不成功
当咱们解决了一个又一个的问题后,忽然发现高压力下存在大量的链接创建不成功的问题,主要表如今:
原来:每秒钟500个链接创建的请求时,5w个用户均可以创建成功;
如今:每秒钟500个链接创建的请求时,5w个用户只有4w左右的链接能够创建成功;
这个问题也花费了不短 的时间,咱们使用了各类命令查看各类网络指标
经过netstat查看到send-q中有大量的消息堆积;
经过sar查看到有大量的重传;
总结起来仍是TcpDump抓包比较效果更好,从测试的开始,咱们就只抓这一条链路上的包,且发送方和接收方,双方都抓包:
而后经过Wireshark分析,能够看到
发送方/客户端:存在必定时间段发送出大量的重传包
接收方/服务端:客户端发送大量重传包的这个过程当中,什么都没有收到
这基本说明网络有问题
而后咱们经过netperf测试了下网络带宽的状况,发现这两台机器之间的网络上限只有21Mb,并且测试过程当中的网络请求量是超过这个值的。因为是在云主机环境上,经过咨询云网络相关的同事发现,问题缘由是由于云主机之间的网络QoS开启限制致使的,限制了每台云主机之间的网络带宽最高位21Mb,超过这个值则会被丢包。
TCP的连接状态图
最后总结下在定位相似的网络问题中一些常规的命令、工具和关注的方向
可使用如下命令
推荐使用如下工具
重点关注如下指标
想要获取更多产品干货、技术干货,欢迎关注网易云信博客。