現象
某系統的tomcat,收不到上游系統請求,日誌停止不滾動,進程還存活(俗稱的tomcat假死)。
分析排查
應用排查
1、登錄應用jstack -l pid > jstack.txt,查看堆棧信息,發現大量的連redis集羣的BLOCKED信息:
"http-nio-9080-exec-200" #287 daemon prio=5 os_prio=0 tid=0x00002aaad4716800 nid=0x47db waiting for monitor entry [0x000000005287e000]
java.lang.Thread.State: BLOCKED (on object monitor)
at redis.clients.jedis.JedisClusterInfoCache.getSlotPool(JedisClusterInfoCache.java:151)
- waiting to lock <0x0000000648ecf770> (a redis.clients.jedis.JedisClusterInfoCache)
at redis.clients.jedis.JedisSlotBasedConnectionHandler.getConnectionFromSlot(JedisSlotBasedConnectionHandler.java:54)
at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.java:47)
at redis.clients.jedis.JedisClusterCommand.run(JedisClusterCommand.java:32)
at redis.clients.jedis.JedisCluster.get(JedisCluster.java:97)
2、登錄監控平臺,發現一個redis節點已經監控不到。在應用上telnet該節點,返回超過最大連接數。於是基本定位故障:某redis節點超過最大連接數,導致無法訪問。
分析問題
應用程序
- 應用程序在生成流水號時,強依賴redis,沒有做降級方案。
- 應用端jedispool設置了連接超時時間,但是過大,造成請求阻塞。
- 此redis集羣爲公用集羣,至少有60個子系統在使用,每個子系統都有設置了最大連接數,理論上,是不會超出10000的。
redis集羣排查
4、登錄redis-cli,list連接清單,發現了某應用集羣有大量的連接,並處於establish狀態,斷定來源IP爲問題應用,並且應用使用了redis的發佈訂閱功能:subscribe。
連接信息.png
5、登錄問題應用服務器,使用netstat查看未發現到redis服務器的連接。由此定位問題爲redis連接未及時釋放。
長連接問題排查
- 查看網絡拓撲爲應用->防火牆->redis。登錄防火牆,連接數依然爲0-1個,確認問題爲redis未及時回收連接。
- 查看操作系統tcp keepalive設置爲7200s(2小時),未生效,推測此配置被redis配置覆蓋。(在測試環境使用相同配置,進行tcpdump抓包測試,確認無誤。)
- 查看redis配置tcp_keepalive爲0,代表關閉tcp連接狀態檢查,與現象一致。
- 查看防火牆長連接配置爲30分鐘無流量主動斷開連接,與現象一致。
結論
- 應用與redis之間有jupiter防火牆,防火牆30分鐘無數據通信,會拆連接,拆的時候不會通知兩端回收連接。
- redis-server設置了keepalive=0,此配置覆蓋了操作系統的keepalive=7200s,導致redis-server不主動檢測連接狀態,所以不會主動回收連接。
- 客戶端應該是jvm有默認設置,或者走了操作系統的配置(待驗證),所以客戶端機器上可以正常回收連接。
解決方案
- redis設置tcp_keepalive=60s
- 應用程序jedispool設置連接檢測。
轉載:https://www.jianshu.com/p/e0fbcdd6eb73