TCP状态-问题排查

前段时间遇到一个为问题,通过监控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中的一条日志记

 

119.163.52.24
2443
- [15/Jun/2012:00:00:00 +0800]
"GET http://shuju.wuliu.taobao.com/timeCostResponse.do?sellerId=341434852&ip=119.163.52.24"
200
63
"http://list.taobao.com/market/baby.htm?spm=640.1000530.0.620&cat=50095706&spercent=95&"
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_4) AppleWebKit/534.57.2 (KHTML, like Gecko) Version/5
.1.7 Safari/534.57.2"
日志具体字段解释:
%h 发送请求的客户端ip地址
%D 服务器处理本请求所用的时间
%m: 请求的方法
%t: 以公共日志时间格式表示的时间
%r: 请求的第一行
%s: 状态。对于进行内部重定向的请求
%b: CLF格式的已发送字节数量,不包含HTTP头

------------------------------------------------------------------------------------------------------

看了一下机器的性能情况,发现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的状态

 

-a (all)显示所有选项,默认不显示LISTEN相关
-t (tcp)仅显示tcp相关选项
-n 拒绝显示别名,能显示数字的全部转化成数字。
-p 显示建立相关链接的程序名

-u (udp)仅显示udp相关选项
-c 每隔一个固定时间,执行该netstat命令。
-l 仅列出有在 Listen (监听) 的服務状态
 

(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

(3)查看apache日志中访问前十名的IP地址
awk '{print $1}'  access_log |sort|uniq -c|sort -nr|head -10

 

(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进程数,换言之就增加了内存消耗。

 

猜你喜欢

转载自iamzhongyong.iteye.com/blog/1566099