Redis客戶端週期性出現connect timeout

1、背景:

大部分互聯網公司都會有Mysql或者Oracle的DBA,可是在Nosql方面通常不會設置專門的DBA。不過對於一些知名的互聯網公司來講,Nosql的使用量是巨大的,因此一般讓Mysql的DBA或者單獨聘請工程師來維護一些Nosql數據庫,好比:java

Redis, Hbase, Memcache(其實嚴格講不是nosql), Mongodb, Cassandra。從講座看美團網應該是有專職的Redis DBA。因此做爲業務開發人員不須要本身安裝、配置、運維Redis,只須要找Redis DBA來申請就能夠了。mysql

這裏爲了簡化說明:Redis DBA提供的服務叫作Redis雲,業務開發人員叫作業務端(redis的使用者)redis

2、現象

業務端在使用redis雲提供的redis服務後,常常出現connect timeout:sql

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

3、分析和懷疑:

業務端通常認爲redis出現問題,就是redis雲有問題,人的「正常」思惟:看別人錯誤容易,發現本身難,扯多了, 出現這個有不少緣由:數據庫

   (1). 網絡緣由:好比是否存在跨機房、網絡割接等等。服務器

   (2). 慢查詢,由於redis是單線程,若是有慢查詢的話,會阻塞住以後的操做。 網絡

   (3). value值過大?好比value幾十兆,固然這種狀況比較少,其實也能夠看作是慢查詢的一種運維

   (4). aof重寫/rdb fork發生?瞬間會堵一下Redis服務器。nosql

   (5). 其餘..................tcp

4、查詢緣由

演講者一開始懷疑是網絡問題,可是並未發現問題,觀察各類對比圖表,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的鏈接進不了隊列。

 5、解決方法:

一、對慢查詢進行持久化,好比定時存放到mysql之類。(redis的慢查詢只是一個list,超過list設置的最大值,會清除掉以前的數據,也就是看不到歷史)

二、對慢查詢進行報警(頻率、數量、時間)等等因素

三、其實應該作的是:對業務端進行培訓,告訴他們一下redis開發的坑,redis不是萬金油,這個和Mysql DBA要培訓Mysql使用者同樣,不然防不勝防。好比他執行了 monitor, keys *, flushall, drop table, update table set a=1; 這種也是防不勝防的(固然也能夠作限制,利用rename-command一個隨機數),可是提升工程師的水平纔是關鍵。

相關文章
相關標籤/搜索