今天遇到 rancher上的服务无法相应。
1、使用 jstack -l pid 查看当前线程的状态
发现大量线程处于Waiting 状态。
"DubboServerHandler-192.168.213.250:20889-thread-198" daemon prio=10 tid=0x00007f3a3b794800 nid=0x83b waiting on condition [0x00007f3a1ed86000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x0000000700c6c208> (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 org.apache.commons.pool2.impl.LinkedBlockingDeque.takeFirst(LinkedBlockingDeque.java:583)
at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:442)
at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:363)
at redis.clients.util.Pool.getResource(Pool.java:48)
at redis.clients.jedis.JedisPool.getResource(JedisPool.java:86)
从log 可以看出是由于 线程无法获取redis连接。
这样的线程大概有几百个。由于我们的Http请求,一开始时候是先从缓存取数据,如果没有才去数据库取,
所以所有的请求基本上都被waiting到获取redis连接上,而无法相应服务。
通过代码排查,发现是在建立 redis pool 的时候,使用的都是默认配置,
在默认配置中,最大的连接数为8个,并且获取连接时会持续等待,造成了程序在某个时候无法获取redis连接,后面的线程持续等待。
于是加上 pool的配置
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxIdle(maxIdle);
jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
jedisPoolConfig.setMaxTotal(maxTotal);
配置后,设置了超时时间,不至于所有线程都等待,而耗光app的资源。
现在还有一个问题, 就是正常情况下, 获取redis 连接用完就应该会释放资源,到底是什么原因导致最开始的
8个连接打满,等待,后续有没有线程唤醒他们?
查看springboot 的redisTemplate 发现每个方法都是用完之后释放的连接。
现在想到的:可能是某个时刻,redis 无法获取连接,导致所有的线程都是处于连接等待状态,那么就没有线程去唤醒等待的线程了。
网友评论