前段时间遇到一个为问题,通过监控apache的日志发现,http接口调用的响应时间非常长。
----------------------------------------------------------------------------------------------------------------------
插一段apache日志格式:
例如:httpd.conf中的部分log格式
LogFormat "%h %D %{X_READTIME}i %t \"%m http://%V%U%q\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
logs中的一条日志记
------------------------------------------------------------------------------------------------------
看了一下机器的性能情况,发现CPU、load、内存都没有啥问题,基本没有打的波动,很是疑惑,最后看了一下网络的情况,
sar -n SOCK 后发现tcp创建的连接数很多,远远超出了正常的范围,于是开始看TCP链接的状态,最后问题定位是请求的一个外部服务器出现问题,
导致TCP链接一直没有释放,后来httpclient的超时时间设置短了点,并且使用完了主动关闭,而不是依赖外部服务器关闭,发布解决。
------------------------------------------------------------------------------------------------------
(1)CLOSED:起始点,在超时或者链接关闭的时候进入此状态;
(2)LISTEN:服务器端在等待连接过来的时候的状态,等待客户端来链接服务器;
(3)SYN_SENT:客户端发起连接,发送SYN给服务器,如果服务器不能链接,则直接进入CLOSED状态;
(4)SYN_REVD:和SYN_SENT对应,服务器接收客户端SYN请求,服务器有LISTEN状态进入SYB_REVD状态,同事服务器回应一个ACK,同时发送一个SYN给客户端,另外一种情况,客户端在发起SYN的同时接收服务器的SYN请求,客户端由SYN_SENT进入到SYN_REVD状态;
(5)ESTABLISHED:服务器和客户端在完成3次握手进入此状态,说明已经可以传输数据;
(6)FIN_WAIT_1:主动关闭的一方,有状态ESTABLISHED进入此状态,同时发送ACK;
(7)FIN_WAIT_2:主动关闭的一方,在接收到对方的FIN ACK,进入此状态,由此不能再接收对方的数据,但是能够向对方发送数据;
(8)CLOSE_WAIT:接收到FIN以后,被动关闭的一方进入此状态;
(9)LAST_ACK:被动关闭的一方,发起关闭请求,由状态CLOSE_WAIT进入此状态
(10)TIME_WAIT:最纠结的状态来了。有3个状态可以转化成它,我们一一来分析:
a.由FIN_WAIT_2进入此状态:在双方不同时发起FIN的情况下,主动关闭的一方在完成自身发起的关闭请求后,接收到被动关闭一方的FIN后进入的状态。
b.由CLOSING状态进入:双方同时发起关闭,都做了发起FIN的请求,同时接收到了FIN并做了ACK的情况下,由CLOSING状态进入。
c.由FIN_WAIT_1状态进入:同时接受到FIN(对方发起),ACK(本身发起的FIN回应),与b的区别在于本身发起的FIN回应的ACK先于对方的FIN请求到达,而b是FIN先到达。这种情况概率最小
--------------------------------------------------------------------------------------------
netstat 命令常用参数,用来查询TCP的状态
(1)查看apache进程数量:
ps -ef | grep httpd | wc -l
(2)查看TCP各个状态的数量:
netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
netstat -nat |awk '{print $6}'|sort|uniq -c
(1)为什么 TIME_WAIT 状态需要保持 2MSL 这么长的时间?
TIME_WAIT的等待时间为2MSL,即最大段生存时间.如果 TIME_WAIT 状态保持时间不足够长(比如小于2MSL),第一个连接就正常终止了.第二个拥有相同相关五元组的连接出现(因为连接终止前发起的一方可能需要重发 ACK,所以停留在该状态的时间必须为MSL的2倍.),而第一个连接的重复报文到达,干扰了第二个连接.TCP实现必须防止某个连接的重复报文在连接终 止后出现,所以让TIME_WAIT态保持时间足够长(2MSL),连接相应方向上的TCP报文要么完全响应完毕,要么被丢弃.建立第二个连接的时候,不 会混淆.
(2)对apache的操作
HTTP协议1.1版规定default行为是Keep-Alive,也就是会重用TCP连接传输多个request/response.所以我打开 http中的keepalive On,发现TIME_WAIT就立刻少了下来.只有300的样子.总结一下.我认为有二个原因.
1.keepalive没有开,导致每次请求都要建立新的tcp连接,请求完成以后关闭,增加了很多time_wait的状态,没有重 用,KeepAlive我认为它指的是保持连接活跃,类似于Mysql的永久连接.如果将KeepAlive设置为On,那么来自同一客户端的请求就不需 要再一次连接,避免每次请求都要新建一个连接而加重服务器的负担.
2.然后keepalive在系统中本身的值很高.默认空闲连接 7200 秒(2 小时)内没有活动.才会断开.
keeplive的timeout时间是请求完成后,链接仍然处于ESTABLISHED状态的时间。
对于一些特定场景才需要keepalive,比如请求一个页面,它带有图片、 js、css,且这些请求也将马上再次落到这台机器上(从这个角度讲我们不需要)。
–打开keepalive,减少三次握手四次挥手的开销,但是同时相当于增加了apache处理线程的堆积,进而可能增加apache进程数,换言之就增加了内存消耗。