轉自簡書【https://www.jianshu.com/p/a85ec38245da】
最近遇到一個問題,springBoot程序中有一個監聽器,監聽redis中發來的消息(其實是監聽一個key的消失,以此做定時),后台程序監聽不到redis消息。
剛開始以為是redis鍵值未寫入,或者過期時間不對,經過排查,在定時開始時,key已經寫入,並且過期時間與系統中設置的一致。並且未見明顯報錯,直到在控制台發現:
2019-10-11 09:16:14,574 ERROR [rules-engine-4] o.s.d.r.l.RedisMessageListenerContainer - Connection failure occurred. Restarting subscription task after 5000 ms 2019-10-11 09:16:14,597 ERROR [agentconnection-pubsub-50] o.s.d.r.l.RedisMessageListenerContainer - Connection failure occurred. Restarting subscription task after 5000 ms 2019-10-11 09:16:14,599 ERROR [servicesession-expire-84] o.s.d.r.l.RedisMessageListenerContainer - Connection failure occurred. Restarting subscription task after 5000 ms
這時候才反應過來后台程序與redis連接出現了問題。
1)百度查看該報錯,很多是說:Redis訂閱客戶端訂閱buffer超過32M或持續60秒超過8M,訂閱立即被關閉!(意思是說客戶端消費速度比較慢,導致產生的消息大量堆積超過了限制客戶端被關閉)
client-output-buffer-limit pubsub 32mb 8mb 60
2)可以修改配置為(使其不受限制):
config set client-output-buffer-limit "normal 0 0 0 slave 268435456 67108864 60 pubsub 0 0 0"
3)這次遇到的問題好像不是這樣的,看到 “client-output-buffer-limit pubsub如果達到限制會關閉客戶端,然后客戶端會報此次這個錯誤,那是不是有可能是其他地方將這個客戶端關閉了造成這個錯誤;”
4)服務器的redis是部署在阿里雲,並且使用了haproxy(這個東西沒用過,還得學習,貼一張其他博主的圖紀錄一下)
timeout client:客戶端非活動狀態的超時時長
timeout server:客戶端與服務器端建立連接后,等待服務器端的超時時長
並借用了別人的解決方案
- 暫時解決方案
1)haproxy超時時間仍改回3min,因為后端代理了mysql等服務;
2)暫時繼續沿用目前這種方案,因為程序具備斷開重連機制,雖然redis發布訂閱不能持久化,斷開連接期間發布的消息訂閱端有可能丟失,但是目前業務發布消息很少,幾個月發布一次消息,在發布消息的時候連接斷開的概率還是比較小的,所以暫不處理。 - 永久解決方案
1)采用Rabbit Mq取代redis
2)tomcat直連redis
3)代碼處增加額外的發布信息,確保連接idle時間不會超過3min