RedisClient 報出java.net.SocketException: Broken pipe異常

FeelTouch發表於2018-12-20

問題場景:

讀寫資料量小時沒有問題,當讀寫資料量大的時候偶爾會報出這個異常

原因分析:大資料操作時間較長,被redis server強行close了,超過redis server的某個值。

相關引數:minEvictableIdleTimeMillis 。執行緒中如果檢測到當前連線的最後活躍時間和當前時間的差值大於
minEvictableIdleTimeMillis,則關閉當前連線

其他案例:

在方案三上線以後,我認為這些redis應該會消停了,redis執行一段時間後,的確再也沒用timeout exception了,但是在執行一段時間後,tpn在向redis執行請求時,往redis寫入命令時會報這個異常:
java.net.SocketException: Broken pipe。我們知道,如果一個socket連線已經被遠端給close掉了,但是客戶端沒有察覺,仍然通過這個連線讀寫資料,那麼就會產生Broken pipe異常。因為tpn使用jedis,通過common pool來實現jedis的connection pool,我第一反應就是tpn沒用正確使用jedis的connection pool,沒有銷燬掉broken的redis connection,而是已經重新把歸還給了connection pool,或者是jedis的connection  pool有bug,造成了connection洩露,導致ton在往一條已經往一條已經被close的連線寫入資料。但是仔細檢查了一遍tpn的程式碼和jedis connection pool的程式碼,發現沒用什麼問題,那就說明有些redis是真的被redis服務端給關閉了,但是jedis 的connection pool沒有發現。
     因為客戶端的jedis pool沒有問題,那麼基本上可以確定的確是redis server端關閉了一些連線。首先懷疑的就是tpn的redis 配置出錯了,錯誤地配置了redis.conf裡的timeout 配置項:
首先懷疑的是不是tpn的redis配置不多,造成因此就去檢視redis的相關程式碼。redis的配置檔案redis.config裡面有timeou這個配置項:
          # Close the connection after a client is idle for N seconds (0 to disable)          timeout 0
   檢查了下tpn 6臺redis上的所有配置檔案,發現都沒有配置這個選擇,但是tpn部署了兩個版本的redis,redis-2.6.14和redis-2.4,結果在redis-2.4裡面,如果沒有配置這個值,redis就會使用預設的值,5*60(s),而redis-2.6.14的預設值是0,即disable timeout,同時又去檢視了下jedis common pool的設定,發現minEvictableIdleTimeMillis=1000L * 60L * 60L * 5L(ms),即一個redis連線的空閒時間超過5個小時才會被connection pool給回收。很明顯,就是因為客戶端和服務端的connection idle time設定不一樣,造成了connection被一端關閉了,但是另一端沒有感知,所有造成了broken pipe。解決辦法就是把redid-2.4升級到redid-2.6.14。
 

相關文章