手头的活干得差不多了,代码没多大变动,即便现在使用的单用户单线程模型比较原始也没什么扩展性,单个节点应付不了高并发的访问。在用loadrunner进行压力测试的过程中也发现了些问题,有的是程序问题有的是centos参数设置。
首先是在服务器端发现了大量套接字处于CLOSE_WAIT状态,套接字使用数不断上升,直到用完了所有的文件描述符不再响应新的请求。根据TCP状态图,知道这种状态是套接字被动关闭,即客户端关闭套接字,服务器再向套接字写入数据则返回broken pipe错误。也就是说,服务器没有正常关闭该套接字,而在回看代码的过程中 又确实调用了closesocket,也尝试过shutdown或者所谓非优雅的关闭套接字设置lingertime选项都没能解决问题。磨了几天,想起来服务线程传入参数不对,传的一个局部变量,过了生存周期,而关闭套接字的时候也自然是返回一个错误。后来改为new一个对象出来作为传入参数在新线程里面delete。
改过来之后再测,发现周期性的吞吐量下降,用netstat一查发现大量套接字处于TIME_WAIT状态,根据TCP状态图,这个属于正常现象,即等待2MSL时间确保ACK信息以及之前发送的重复包全部消失。如果是在linux系统下可以修改相关参数快速回收TIME_WAIT状态的套接字,
修改/etc/sysctl.conf文件,/sbin/sysctl -p是设置生效
1 #对于一个新建连接,内核要发送多少个 SYN 连接请求才决定放弃,不应该大于255,默认值是5,对应于180秒左右时间
2 net.ipv4.tcp_syn_retries=2
3 #net.ipv4.tcp_synack_retries=2
4 #表示当keepalive起用的时候,TCP发送keepalive消息的频度。缺省是2小时,改为300秒
5 net.ipv4.tcp_keepalive_time=1200
6 net.ipv4.tcp_orphan_retries=3
7 #表示如果套接字由本端要求关闭,这个参数决定了它保持在FIN-WAIT-2状态的时间
8 net.ipv4.tcp_fin_timeout=30
9 #表示SYN队列的长度,默认为1024,加大队列长度为8192,可以容纳更多等待连接的网络连接数。
10 net.ipv4.tcp_max_syn_backlog = 4096
11 #表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭
12 net.ipv4.tcp_syncookies = 1
13 #表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭
14 net.ipv4.tcp_tw_reuse = 1
15 #表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭
16 net.ipv4.tcp_tw_recycle = 1
17 ##减少超时前的探测次数
18 net.ipv4.tcp_keepalive_probes=5
19 ##优化网络设备接收队列
20 net.core.netdev_max_backlog=3000
改好之后,又发现集群里的存储节点在并发量上去的时候容易挂掉,查看日志上面写的pthread failed,resources temporary unavailable,服务器这边也出现这种情况,在网上查了下,linux默认对每个进程的线程数有限制,另一方面默认每个线程8M的栈空间,用户空间的内存有限制,再就是线程资源默认是在主线程调用join 的时候回收。对照代码,线程启动的时候设置了栈为1M,且为DETACHED状态,尝试在ulimit里面修改MAX USER PROCESSER选项,发现没什么效果,最后是修改/etc/security/limits.conf文件,加上2行参数设置可以启动的线程数。
1 * soft nproc 20000
2 * hard nproc 20000