背景:
1.系統由多個進程組成,幾乎每個進程都需要訪問redis。
2.所有進程都部署在一台機器,包括redis/mysql。
3.redis驅動程序使用的是jedis 2.8。
4.每個進程配置的redis連接池數量都較大,最大大概幾百個連接。
5.現場人員報告,頁面某功能偶現不可用的情況,經查相關進程日志,是由於redis連接建立失敗導致的。
排查過程:
1.搭建壓力測試環境,模擬現網壓力,同樣出現了redis建立連接失敗,異常顯示socket connection timeout。
2.嘗試修改連接池配置,將idl調成和total一致,均為200,問題並未解決。
3.嘗試加大連接池數量,問題並未解決。
4.后來想到,redis服務器是單線程的,即同一時刻,僅處理一個連接發出的指令,那么連接池中的多個連接,雖然將指令發送至redis,但redis並未立即處理,而是在排隊。那么,與其將指令發送給redis,在redis端排隊,不如在本進程內排隊,暫不將指令發送至redis,即將redis連接池idl/total均設為1,僅維持一條與redis的連接,如果業務量過大,本進程內排隊超時,也就是等待從連接池獲取連接超時,那么可以通過加大連接池的maxwait值來解決。想到此點之后,將連接池idl/total調整為1,開始壓力測試,未再出現連接建立超時。
5.問題解決。
經驗:redis服務器是單線程模型,加大連接池,只是加大排隊的隊列數,但是,redis是多進程共用,壓力較大,在處理大量的redis指令的同時,還要維護大量的連接,是很耗資源的。所以,每個進程僅維持一條與redis的連接,通過加大maxwait,來控制在本進程內排隊,可以降低redis的壓力。redis和mysql等不同,mysql是可以多個連接的指令並行執行的,所以連接池設置過大沒有意義。