今天遇到 rancher上的服務(wù)無(wú)法相應(yīng)华嘹。
1竟终、使用 jstack -l pid 查看當(dāng)前線程的狀態(tài)
發(fā)現(xiàn)大量線程處于Waiting 狀態(tài)榴捡。
"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 可以看出是由于 線程無(wú)法獲取redis連接诱桂。
這樣的線程大概有幾百個(gè)帘瞭。由于我們的Http請(qǐng)求淑掌,一開(kāi)始時(shí)候是先從緩存取數(shù)據(jù),如果沒(méi)有才去數(shù)據(jù)庫(kù)取蝶念,
所以所有的請(qǐng)求基本上都被waiting到獲取redis連接上抛腕,而無(wú)法相應(yīng)服務(wù)。
通過(guò)代碼排查祸轮,發(fā)現(xiàn)是在建立 redis pool 的時(shí)候兽埃,使用的都是默認(rèn)配置,
在默認(rèn)配置中适袜,最大的連接數(shù)為8個(gè)柄错,并且獲取連接時(shí)會(huì)持續(xù)等待,造成了程序在某個(gè)時(shí)候無(wú)法獲取redis連接苦酱,后面的線程持續(xù)等待售貌。
于是加上 pool的配置
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxIdle(maxIdle);
jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
jedisPoolConfig.setMaxTotal(maxTotal);
配置后,設(shè)置了超時(shí)時(shí)間疫萤,不至于所有線程都等待颂跨,而耗光app的資源。
現(xiàn)在還有一個(gè)問(wèn)題扯饶, 就是正常情況下恒削, 獲取redis 連接用完就應(yīng)該會(huì)釋放資源,到底是什么原因?qū)е伦铋_(kāi)始的
8個(gè)連接打滿尾序,等待钓丰,后續(xù)有沒(méi)有線程喚醒他們?
查看springboot 的redisTemplate 發(fā)現(xiàn)每個(gè)方法都是用完之后釋放的連接每币。
現(xiàn)在想到的:可能是某個(gè)時(shí)刻携丁,redis 無(wú)法獲取連接,導(dǎo)致所有的線程都是處于連接等待狀態(tài)兰怠,那么就沒(méi)有線程去喚醒等待的線程了梦鉴。