只针对BIO模式,目标请求会sleep两秒再返回结果,经过jmeter测试工具进行并发测试html
操做系统:windows && linuxlinux
tomcat7测试:windows
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000" maxThreads="1" acceptCount="2"
redirectPort="8443" />tomcat
文档:http://localhost:8080/docs/config/http.html并发
官方解释:acceptCount对暂时没法执行的请求进行队列保存,超出设置则拒绝链接。socket
测试发现没法限制住最大并发数,全部请求均可以依次执行,每次有1个线程执行(maxThreads=1)tcp
最大并发数若是过大,大于acceptCount值好几倍,会随机出现链接被拒绝。工具
进一步调查-----------------------------------------------------------------------------------------------------------------------------------源码分析
首先关于tcp queue简单介绍:测试
tcp三次握手:
第一次,客户端发送syn,等待服务端确认,此时客户端进入SYN_SEND状态
第二次,服务端接收syn包并确认,发送syn+ack给客户端,此时服务端进入SYN_RECV状态
第三次,客户端收到syn+ack,再次向服务端发送ack,此时客户端进入ESTAB状态(注意,此时服务端未必进入ESTAB状态)
半链接队列:服务端维护的与客户端保持SYN_RECV状态的链接队列,等待客户端回复,当收到客户端ack后,若是条件容许(全链接队列未达到最大值),服务端进入ESTAB状态,从半链接队列移到全链接队列的队尾。
全链接队列:完成三次握手等待accept。完成三次握手即进入了全链接队列的队尾,当进程调用accept时,全链接队列中的队头项将返回给进程,并从队列中移出链接。若是该队列为空,那么进程将被投入睡眠,直到TCP在该队列中放入一项才唤醒它。
在listen(int sockfd, int backlog)中,backlog在Linux 2.2以后表示的是已完成三次握手但还未被应用程序accept的队列长度。
全链接队列满,半链接队列未满:
客户端发出syn分节,服务端收下,并向客户端发出syn+ack。
客户端收到服务端syn+ack后,成为ESTAB状态,向服务端发送第三次握手ack。
服务端收到ack后,发现全链接队列已满,默认状况下,服务端什么也不作,状态依然是SYN_RECV。
客户端会重传syn和ack,当达到必定的阈值(/proc/sys/net/ipv4/tcp_synack_retries)时,客户端与服务端断开链接,服务端删除客户端在半链接队列中的syn分节。
全链接、半链接队列都满:
客户端发出syn分节,服务端发现半链接队列已满,直接丢弃syn,使客户端重传syn。
客户端重传syn,再次到达服务端后,服务端发现已经重传过,则收下,并告诉客户端syn+ack。
后续流程与上述一致,相比之下,多了一次客户端重传syn分节。
修改tcp参数配置:
tcp_synack_retries和tcp_syn_retries定义SYN 的重试链接次数
/etc/rc.d/rc.local文件中追加:
sysctl -w net.ipv4.tcp_synack_retries=3
sysctl -w net.ipv4.tcp_syn_retries=3
重启。
也可直接执行命令:
sysctl -w net.ipv4.tcp_synack_retries=1
sysctl -w net.ipv4.tcp_syn_retries=3
关于队列的长度:
半链接队列:≈2 * min(backlog, net.ipv4.tcpmax_syn_backlog)
全链接队列:min(/proc/sys/net/core/somaxconn(本系统128), backlog),表示最多有 min() + 1个 ESTAB 的链接等待 accept()。
修改somaxconn,
在/etc/sysctl.conf中添加以下:
net.core.somaxconn = 2048
而后在终端中执行
sysctl -p
进一步试验-------------------------------------------------------------------------------------------------------------------------------------------------------------------
在linux下,经过ss -ant进行观察tcp queue
并发5个请求
acceptCount配置做为socket中的backlog的值,若是acceptCount不设置或者设置为0,则会取默认值,经测试是100。
全链接队列大小为 min(/proc/sys/net/core/somaxconn(本系统128), 2) + 1=3,即等待服务端accept的ESTAB状态的链接最多有3个,如Recv-Q所示。
3个Recv-Q为323(表示请求bytes数值)的ESTAB状态的链接正等待server accept
1个Recv-Q为0的ESTAB状态的链接表示server端已经accept了请求,只是尚未返回结果(sleep中)。
1个SYN-RECV状态是半链接状态,位于半链接队列当中(此时客户端已经处于ESTAB状态),全链接队列已经满了。
对于处在半链接状态的链接,客户端会定时重发,直至达到阈值,以下:
第一次握手
第二次握手
第三次握手
客户端发送数据包
但因为此时服务端未能将链接从半链接队列移至全链接队列,状态依然是SYN-RECV,即未获得服务端ack,所以客户端继续发数据包
发送几回以后,服务端有了回应,告诉客户端说,你以前发的包丢了
而后客户端也告诉服务端,丢失的状态、对应的id号及次数,这里的43就是第三次握手的43,失败次数是1
而后客户端又开始重传了
终于服务端受不了了,此时客户端服务端完全断开。
经过调整ipv4.tcp_synack_retries和ipv4.tcp_syn_retries,能够增长重试次数
结论:
对于tomcat中的acceptCount只是全链接队列的大小,就是说客户端和服务端都已是ESTAB状态的链接,不考虑connectionTime的状况,在此队列中的链接最终都会被处理。对于大于acceptCount的链接请求,若是在tcp重试阈值范围以内完成半链接到全链接的状态转换,那么仍是有机会被服务端accept并处理的。
所以,不能说只要大于acceptCount的链接就必定被拒绝!
参考文献:
http://www.cnblogs.com/leezhxing/p/5329786.html
http://blog.chinaunix.net/uid-24782829-id-3456109.html
http://www.cnblogs.com/menghuanbiao/p/5212131.html
http://www.cnblogs.com/zengkefu/p/5606696.html 有详细的源码分析