问题:
项目新更换了数据源driud,生产发版一周后突然发现所有的请求都不能响应了。
- 查看后台日志(info级别),并没有报错。
- 怀疑CPU跑满了,top命令查看,cup,内存消耗正常。应该不是GC出问题。
- jstack上场,由于日志没有进程号,无法直接用(擦!)。使用
ulimit -a
查看文件描述符等限制lsof -n|awk '{print $2}' | sort | uniq -c | sort -nr | more
获得进程号63330jstack 63330
查看后发现很多线程都是WAITING状态
"http-nio-8080-exec-54" daemon prio=10 tid=0x0000000000e61000 nid=0xcc9 waiting on condition [0x00007f4a753d4000] java.lang.Thread.State: WAITING (parking) at sun.misc.Unsafe.park(Native Method) - parking to wait for <0x00000007a143f230> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject) at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186) at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2043) at com.alibaba.druid.pool.DruidDataSource.takeLast(DruidDataSource.java:1732) at com.alibaba.druid.pool.DruidDataSource.getConnectionInternal(DruidDataSource.java:1330) at com.alibaba.druid.pool.DruidDataSource.getConnectionDirect(DruidDataSource.java:1198) at com.alibaba.druid.filter.FilterChainImpl.dataSource_connect(FilterChainImpl.java:4619)
- netstat -anp|grep 9085 发现 listen监听基本都是 close_wait
至此可以定位,所有的请求都被druid的获取连接操作阻塞了,因为数据链接没有释放,连接池中无可用连接,导致请求被阻塞了,不过druid也提供了相应的方案,如下
很多人遇到了连接泄露的情况,可见druid的官方issue,如https://github.com/alibaba/druid/issues/1160
park
public static void park(Object blocker)
- 为了线程调度,在许可可用之前禁用当前线程。
- 如果许可可用,则使用该许可,并且该调用立即返回;否则,为线程调度禁用当前线程,并在发生以下三种情况之一前,使其处于休眠状态:
- 其他某个线程调用将当前线程作为目标调用 unpark;或者
- 其他某个线程中断当前线程;或者
- 该调用不合逻辑地(即毫无理由地)返回。
此方法不报告是哪个线程导致该方法返回。调用者应该重新检查最先导致线程暂停的条件。调用者还可以确定返回时该线程的中断状态。