关于dubbox部分rest接口超时问题研究
业务高峰期部分rest接口超时有一段时间了,之前一直怀疑是kafka、nginx、log4j、网络等原因并进行优化,一直没有太大改观。我们生产共有四台nginx反向代理网关,运维在某台nginx中通过日志grep看到,高峰期 nginx反向代理到后端某台tomcat,每秒达到100+,4台nginx则为400+,已超过tomcat设置的并发连接数和完全连接队列的大小(200+100=300)。前两天运维说把tomcat线程数调大到600之后(原来是200),超时问题就没有再出现了。
事后考虑原因分析如下:
tomcat配置中有一个参数叫acceptCount,这个参数在tomcat中指server端监听端口的完全连接队列的socket上限(backlog)。这个值在dubbox中是不能设置的,默认100。
另一个参数叫threadCount,这个参数指tomcat工作线程池大小。tomcat线程池每次从队列头部取线程去处理请求,请求完结束后再放到队列尾部,也就是说前后两次请求处理不会用同一个线程。如下:
换句话说,之前threadCount=200、acceptCount=100时,tomcat能接受的最大并发数就是200,如果并发数>200时,只会有额外的100个并发请求会在完全连接队列中排队,其他并发请求则根本进入不了完全连接队列中,会被服务端拒绝处理( 详见注1)。还有三种情况:
1、半连接队列满了: 详见注2
2、在完全连接队列中超时:出现这种情况,主要因为接口处理响应慢,导致tomcat工作线程池没有空闲的线程处理完全连接队列中的请求,完全连接队列中的请求在到达超时时间(20s)时,被nginx主动关闭了tcp连接(nginx日志中http ressponse code:504)。 有一点要注意,已经进入完全连接队列中的请求,最终会被tomcat处理,只不过此时连接已经断开,nginx不会收到tomcat的响应。
3、接口处理超时:出现这种情况,说明请求已经在tomcat的工作线程中处理了,确实由于接口处理响应慢,而最终被nginx主动关闭了tcp连接。
结论:
治标的方法是增加tomcat工作线程池(threadCount)的数量,而 治本的方法还是要提高接口的响应速度(rt:response time)。试想如果我们的所有接口都能控制在100ms之内,tomcat工作线程池设置为200,单机也能承受峰值2000(200 / 0.1)的并发量请求量(当然mem和cpu不能太差)。
注1:当accept队列满了之后,即使client继续向server发送ACK的包,也会不被响应,此时ListenOverflows+1,同时server通过/proc/sys/net/ipv4/tcp_abort_on_overflow来决定如何返回,0表示直接丢弃该ACK,1表示发送RST通知client;相应的,client则会分别返回 read timeout
或者 connection reset by peer
。
注2:对于SYN半连接队列的大小是由(/proc/sys/net/ipv4/tcp_max_syn_backlog)这个内核参数控制的,有些内核似乎也受listen的backlog参数影响,取得是两个值的最小值。当这个队列满了,不开启syncookies的时候,Server会丢弃新来的SYN包,而Client端在多次重发SYN包得不到响应而返回( connection time out
)错误。但是,当Server端开启了syncookies=1,那么SYN半连接队列就没有逻辑上的最大值了,并且/proc/sys/net/ipv4/tcp_max_syn_backlog设置的值也会被忽略。
最后再附录一张tcp连接建立 和 半连接队列和完全连接队列的图,很经典!
已有 0 人发表留言,猛击->> 这里<<-参与讨论
ITeye推荐