keepalive的来龙去脉

今天有同事反应在性能测试环境cpu load很高有500多,我的分析过程是这样的,先用visualVM连上去观察了下,发现请求都卡在channelsocketread上面。

         这一步是mod_jk的代码,并未真正进入应用代码。所以怀疑是apachejboss之间出现了为题,为了印证这个猜测,先对jboss直接做压力测试,果然应用正常,load也在正常值。

         于是就观察了下httpd.confmod_jk.conf.发现两个配置除了用的都是正常值并没有其他特殊设置,在15个并发的情况下,就算有性能问题也不应该是这样的。

         Netstat –an观察网络连接,发现有很多的close_wait状态。根据tcp-ip关闭连接的四次握手过程和状态转变,close_wait应该是客户端主动发起的,而服务端被动接受关闭,并且服务端还未向客户端发送FIN请求导致。又仔细看了下httpd.conf中的keepalive设置为off。于是就明白是怎么回事了。

直接抓包看图:

Keepaliveon的时候:



 

 

Keepaliveoff的时候:

 
keepalive的来龙去脉_第1张图片
 

 

红框框部分可以看到,首先客户端(10.19.14.20)向服务器发送FIN请求seq=484

服务器响应ack=484+1并且发送FIN给客户FIN请求seq=142

客户端响应服务端请求ack=142+1

 

下面再看下具体的状态转换图:

 


keepalive的来龙去脉_第2张图片
  

从这个图中可以看到状态变为close_wait的一方为被动关闭方。再结合刚才的抓包图分析,在httpd.conf设置为keepaliveoff的时候,客户端会在请求结束之后主动发出close调用,这个时候服务端变为close_wait状态,但是由于apache程序的某些原因导致不能很好的在繁忙情况下处理完这些请求,导致load升高。

 

上面分析的都是针对http协议的keepalive设置,并且这个keepalive是需要http协议支持。

 

下面我们再来稍微看一下tcp层的keepalive参数。

其实tcp协议本身就是面向连接的协议,之所以这样设计是因为这个协议是提供一个高可靠的服务,在连接的基础上我们可以做很多的事情保证可靠性,例如流量的控制(滑动窗口),失败重传的机制等等。只要三次握手完成,那么TCP所谓的连接也就建立了。由于有这个三次握手的过程,所以很多坏人会利用这个过程疯狂往服务器发送SYN包,导致服务器响应不过来而挂掉。

那既然连接已经建立了,为什么还有有keepalive呢,因为连接是有个超时时间的,假如在规定时间内没有数据交换的话,就会超时,所以需要定期发送数据来保持连接,linux操作系统的套接口选项就有个SO_KEEPALIVE可以设置心跳的发送时间(默认2小时),可惜这个参数是针对全局的,你设置了,其他人在这台机器的应用心跳数据发送间隔时间都会改变,所以最好自己写程序来实现心跳。

由此可见,http协议的keepalive参数只不过是为了保持连接的一个实现方式而已,他是在http的头上面定义连接是否需要保持(on/off),和保持的时间(timeout).

 

最后再说一下长连接的用处:

1)  可以省去频繁建立连接的开销

2)  某些场景省去客户端对服务端的频繁轮询

3)  服务端和客户端可以灵活的来回读写数据,所谓的推和拉都可以基于此实现。

 

比如所谓的comet听着很炫,也就是长连接上的一些需求实现。但是由于不是所有的浏览器程序都支持长连接,例如IE就不支持流式的AJAX,只能通过例如flash socket程序,或者iframe等猥琐的方式来实现。

 

以上是小弟因为keepalive引起的乱弹,欢迎各位批评指正。谢谢。

 

补充2个文档:

 http://httpd.apache.org/docs/1.3/keepalive.html

http://en.wikipedia.org/wiki/Keepalive

你可能感兴趣的:(应用服务器,jboss,网络协议,网络应用,Comet)