Redis踩過的坑


現象:在使用redis雲提供的redis服務后,經常出現connect timeout:

redis.clients.jedis.exceptions.JedisConnectionException  
java.net.SocketException  
java.net.SocketTimeoutException:connect time out 

分析和懷疑:

   業務端一般認為redis出現問題,就是redis雲有問題,人的“正常”思維:看別人錯誤容易,發現自己難,扯多了, 出現這個有很多原因:
   (1). 網絡原因:比如是否存在跨機房、網絡割接等等。
   (2). 慢查詢,因為redis是單線程,如果有慢查詢的話,會阻塞住之后的操作。 
   (3). value值過大?比如value幾十兆,當然這種情況比較少,其實也可以看做是慢查詢的一種
   (4). aof重寫/rdb fork發生?瞬間會堵一下Redis服務器。
查詢原因:
  一開始懷疑是網絡問題,但是並未發現問題,觀察各種對比圖表,tcp listenOverFlow和timeout經常周期出現。(贊一下這個監控,我們監控現在還沒有這個層面的)。有關listenOverFlow分析如下:
    查看現有的連接數是否大於設置的backlog,如果大於就丟棄,並相應的參數值加1。其中backlog是由程序和系統參數net.core.somaxconn共同設置,當backlog的值大於系統設置的net.core.somaxconn時則取net.core.somaxconn的值,否則取程序設置的backlog值。
   這種出錯的方式也被記錄在TcpListenOverflows中(其只記錄了連接個數不足而產生溢出錯誤的次數!)
 覺得可能和TCP相關,於是分析了Tcp三次握手:最后一次握手客戶端的請求會進入服務器端的一個隊列(可以認為是下三圖)中,如果這個隊列滿了,就會發生上面的異常。(accept)
  (1) TCP三次握手: 
  (2) redis客戶端與redis服務器交互的過程(本質就是TCP請求)
  (3) I/O 多路復用程序通過隊列向文件事件分派器傳送套接字的過程
(4) 和redis有什么關系呢?
 由於Redis的單線程模型(對命令的處理和連接的處理都是在一個線程中),如果存在慢查詢的話,會出現上面的這種情況,造成新的accept的連接進不了隊列。
如果上面的圖沒法理解的話,看看這張圖:
解決方法:
    (1) 對慢查詢進行持久化,比如定時存放到mysql之類。(redis的慢查詢只是一個list,超過list設置的最大值,會清除掉之前的數據,也就是看不到歷史)
    (2) 對慢查詢進行報警(頻率、數量、時間)等等因素
    (3) 對業務端進行培訓,告訴他們一下redis開發的坑,redis不是萬金油,這個和Mysql DBA要培訓Mysql使用者一樣,否則防不勝防。
      比如他執行了 monitor, keys *, flushall, drop table, update table set a=1; 這種也是防不勝防的(當然也可以做限制,利用rename-command一個隨機數),但是提高工程師的水平才是關鍵。


免責聲明!

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



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