今天早上UIOC,现象是发现调用某个服务的接口总是超时,这个环境昨晚没有发版本无缘无故就出问题很是奇怪。到公司各种查,最终通过问题服务重启前打印的堆栈信息看到几乎所有的线程都在等待连接池释放连接后获取空闲连接。错误如下:
"xxxxxxxxxxxxx" prio=10 tid=0x00007f6b7c002800 nid=0x40ff waiting on condition [0x00007f6b37020000]
java.lang.Thread.State: TIMED_WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000000f97918b8> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.parkUntil(LockSupport.java:239)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitUntil(AbstractQueuedSynchronizer.java:2072)
at org.apache.http.pool.PoolEntryFuture.await(PoolEntryFuture.java:129)
at org.apache.http.pool.AbstractConnPool.getPoolEntryBlocking(AbstractConnPool.java:281)
at org.apache.http.pool.AbstractConnPool.access$000(AbstractConnPool.java:62)
at org.apache.http.pool.AbstractConnPool$2.getPoolEntry(AbstractConnPool.java:176)
at org.apache.http.pool.AbstractConnPool$2.getPoolEntry(AbstractConnPool.java:172)
at org.apache.http.pool.PoolEntryFuture.get(PoolEntryFuture.java:100)
at org.apache.http.impl.conn.PoolingClientConnectionManager.leaseConnection(PoolingClientConnectionManager.java:212)
问题已经很明显,因为使用了连接池,但连接不够用,造成大量的等待,后面的请求获取不到连接所以最终超时,并且这种等待都有滚雪球的效应。
问题原因主要因为我们对httpclient连接池参数设置不合理造成,我们使用的是httpclient4.4.1,除了连接超时和响应超时这两个参数之外,和连接池相关的两个参数如下:
1、MaxtTotal:整个连接池的大小
2、DefaultMaxPerRoute:根据连接到的主机对MaxTotal的一个细分
比如:MaxtTotal=400 DefaultMaxPerRoute=200
只连接到http://x.com时,到这个主机的并发最多只有200;而不是400;
连接到http://x.com 和 http://y.com时,到每个主机的并发最多只有200;即加起来是400(但不能超过400),所以起作用的设置是DefaultMaxPerRoute。
之前一直对线程池和连接池有点混淆,总结一下:
线程池和连接池(http连接池或db连接池)概念上其实是一样的,反复创建都要消耗系统资源,所以才需要使用池保存起来反复使用。针对使用tomcat容器的场景,tomcat工作线程池中每个运行线程都在处理一个upstream请求,需要访问第三方接口或DB时,都是从对应池中取连接进行同步请求操作(一般情况不会另外启动一个线程来异步请求第三方接口或DB)。同步请求操作中(请求发出后),tomcat工作线程会切换到等待状态(WAITING),等请求响应返回后,操作系统再根据调度算法,最终唤醒线程并切换到运行状态(RUNNABLE),如果同步请求操作(访问第三方接口或DB)响应很快,这个线程两次上下文切换(context switch)也是很快的,用jstack几乎是看不到中间状态。
相关链接:
使用httpclient必须知道的参数设置及代码写法、存在的风险
http://jinnianshilongnian.iteye.com/blog/2089792