1、背景
团队有2台API服务,使用Resin4布署的web服务。刚上线调用方非常少,跑了几个月后,程序正常得很。
但是由于业务的发展,此API要给多个高并发的应用调用,级别在300w/天左右,瞬间请求可去到100+/s。
自己看服务,其实服务执行情况还好,虽然请求量高了些,但是程序的成功率很高,CPU有波动,但是算正常。
可是后来,调用方运行一段时间后,说有1/3的请求都被拒绝或者超时了。于是在想是不是resin4可支撑的线程数太小。
2、第一次调优
于是修改了resin.properties里的线程池的大小:
-
- # Throttle the number of active threads for a port
- port_thread_max : 1024
- accept_thread_max : 1024
- accept_thread_min : 32
port_thread_max: 每个端口最多可以有的活跃线程数,避免系统负载压力过大。
但是观察了一段时间后,效率不明显,还是有拒绝。
3、第二次调优
就在昨天,发现两台服务一直在告警,说服务不可达,其实就是超长时间无响应。
无意中发现2台服务器的负载情况不均衡,一台基本没有请求到,一台很多请求。
这个其实跟上层的负载均衡有比较大关系。
但是通过查看系统情况,发现进程中存在大量的TIME_WAIT。
netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
- TIME_WAIT 23456
- FIN_WAIT1 3
- FIN_WAIT2 26
- ESTABLISHED 185
- SYN_RECV 2
- LAST_ACK 1
经过查看以下两篇文章:
http://kerry.blog.51cto.com/172631/105233/
http://blog.chinaunix.net/uid-24517549-id-4048652.html
其中有说到:
根据TCP协议定义的3次握手断开连接规定,发起socket主动关闭的一方 socket将进入TIME_WAIT状态,TIME_WAIT状态将持续2个MSL(Max Segment Lifetime),在Windows下默认为4分钟,即240秒,TIME_WAIT状态下的socket不能被回收使用. 具体现象是对于一个处理大量短连接的服务器,如果是由服务器主动关闭客户端的连接,将导致服务器端存在大量的处于TIME_WAIT状态的socket, 甚至比处于Established状态下的socket多的多,严重影响服务器的处理能力,甚至耗尽可用的socket,停止服务.
于是参考修改:
发现系统存在大量TIME_WAIT状态的连接,通过调整内核参数解决,
vi /etc/sysctl.conf
编辑文件,加入以下内容:net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_fin_timeout = 30
然后执行
/sbin/sysctl -p
让参数生效。
情况马上有好转,TIME_WAIT迅速下降,Established开始上升并稳定。
---2017年更新---
打开了端口回收,会导致大量连接失败。建议改为以下:
net.ipv4.tcp_tw_reuse = 0
net.ipv4.tcp_tw_recycle = 0
net.ipv4.tcp_timestamps = 1
把这三行加进去/etc/sysctl.conf,然后sysctl -p
然后把linux默认的可用端口号调大。因为默认的端口号为:
#sysctl -a|grep ip_local_port_range
net.ipv4.ip_local_port_range = 32768 61000
可修改 为:
net.ipv4.ip_local_port_range = 1024 65535
4、可选优化
连接数本身就很多,我们可以再优化一下TCP/IP的可使用端口范围,进一步提升服务器的并发能力。依然是往上面的参数文件中,加入下面这些配置:
net.ipv4.tcp_keepalive_time = 1200
net.ipv4.ip_local_port_range = 10000 65000
net.ipv4.tcp_max_syn_backlog = 8192
net.ipv4.tcp_max_tw_buckets = 5000这几个参数,建议只在流量非常大的服务器上开启,会有显著的效果。一般的流量小的服务器上,没有必要去设置这几个参数。这几个参数的含义如下:
net.ipv4.tcp_keepalive_time = 1200 表示当keepalive起用的时候,TCP发送keepalive消息的频度。缺省是2小时,改为20分钟。
net.ipv4.ip_local_port_range = 10000 65000 表示用于向外连接的端口范围。缺省情况下很小:32768到61000,改为10000到65000。(注意:这里不要将最低值设的太低,否则可能会占用掉正常的端口!)
net.ipv4.tcp_max_syn_backlog = 8192 表示SYN队列的长度,默认为1024,加大队列长度为8192,可以容纳更多等待连接的网络连接数。
net.ipv4.tcp_max_tw_buckets = 5000 表示系统同时保持TIME_WAIT的最大数量,如果超过这个数字,TIME_WAIT将立刻被清除并打印警告信息。默 认为180000,改为5000。对于Apache、Nginx等服务器,上几行的参数可以很好地减少TIME_WAIT套接字数量,但是对于 Squid,效果却不大。此项参数可以控制TIME_WAIT的最大数量,避免Squid服务器被大量的TIME_WAIT拖死。
5、总结:
所以要多角度考虑,一个软件的不足,不只是考虑其本身的问题,还要考虑所处的系统环境。