使用StackExchange.Redis客戶端進行Redis訪問出現的Timeout異常排查


問題產生


 

這兩天業務系統在redis的使用過程中,當並行客戶端數量達到200+之后,產生了大量timeout異常,典型的異常信息如下:

Timeout performing HVALS Parser2#Hash#VersionState, inst: 1, mgr: ExecuteSelect, err: never, queue: 2, qu: 0, qs: 2,
qc: 0, wr: 0, wq: 0, in: 0, ar: 0, clientName: GS-SERVER-2894, IOCP: (Busy=0,Free=1000,Min=8,Max=1000), WORKER: 
(Busy=0,Free=32767,Min=8,Max=32767), Local-CPU: 0% (Please take a look at this article for some common client-side 
issues that can cause timeouts: https://github.com/StackExchange/StackExchange.Redis/tree/master/Docs/Timeouts.md)

No connection is available to service this operation: HVALS Parser2#Hash#VersionState

SocketFailure on HVALS

運行環境:

Redis服務器版本:2.8.19
.net Framework版本:4.5.2
StackExchange.Redis版本:1.1.603

 

 

問題分析


 

 

首先定位問題,排除Redis基礎組件本身問題,使用redis提供的benchmark工具進行測試:

redis-benchmark -h 10.200.XX.XX -p 30301 -q -n 100000 -c 300 -d 10240

由於redis使用docker提供服務因此端口映射到30301,模擬100000次真實場景請求,300並發,每次請求數據大小10K。

經測試,對常見的hset,hget,sadd,spop等短耗時操作,TPS均保持在25K-30K之間,因此初步排除docker提供的redis服務的問題。

因此問題大致定位在了業務系統代碼中,即使用的redis客戶端工具(StackExchange.Redis)這部分。

 

通過StackExchange對Timeout異常的相關信息(可見這個問題挺常見)及stackoverflow等站點上的相關內容,產生timeout異常比較常見的原因包含(但不限於):

1:服務器資源不足;

2:耗時過長的指令(StackExchange客戶端連接的只讀屬性TimeoutMilliseconds=1000);

3:StackExchange阻塞任務過多(異常信息中的qs值持續增長),對這種情況,StackExchange給出的建議是實現一個復用器池(ConnectionMultiplexer Pool)並動態選取最低負載的復用器進行連接,避免一個鏈接timeout導致所有鏈接阻塞的情況;

4:CLR中Thread Pool最小按需創建線程數過小導致的等待成本(500ms),可見StackExchange的ConnectionMultiplexer使用的是線程池;

此外,在StackExchange.Redis項目的Issue中與Time out相關的主題中,也有人提及在更新StackExchange.Redis的客戶端版本后(1.1.605+)該異常不再出現的問題。

 

問題解決


 

 

根據以上可能產生問題的原因,對業務代碼做出以下修改:

1:不再繼續使用StackExchange.Redis內部封裝的主/從線程池,明確主/從ConnectionMultiplexer對象;

2:修改CLR的Thread Pool最小創建線程閾值數量;

3:在ConnectionMultiplexer單例視線中加入對其IsConnected屬性的判斷,在其連接斷開后手動釋放資源並重新連接;

4:避免如HVALS等可能導致慢操作的指令;

5:升級StackExchange.Redis版本至1.1.605+(目前最新版本1.1.608)。

 

修改完畢后進行測試,time out異常目前已排除。

 

 

2016-10-17 補充


 

StackExchange.Redis客戶端(V1.1.608)經測試有這么一個特質,即,由complexer單例對象創建的IDatabase對象,在產生Timeout異常后會導致這個complexer單例對象超時,即由其創建的新的IDatabase對象也會繼續Timeout,相當蛋疼。。。

實際使用過程中,由於網絡各種原因,出現Timeout異常難免,但是無法恢復確實很麻煩。測試complexer對象無法dispose,close后重建。。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM