"Redis用戶端串連數一直降不下來"的有關問題解決

來源:互聯網
上載者:User

標籤:

[線上問題] "Redis用戶端串連數一直降不下來"的問題解決

前段時間,上線了新的 Redis緩衝Cache)服務,準備替換掉 Memcached。

 

為什麼要將 Memcached 替換掉?

原因是 業務資料是壓縮後的列表型資料,緩衝中儲存最新的3000條資料。對於新資料追加操作,需要拆解成[get + unzip + append + zip + set]這5步操作。若列表長度在O(1k)層級的,其耗時至少在50ms+。而在並發環境下,這樣會存在“資料更新覆蓋問題”,因為追加操作不是原子操作。(線上也確實遇到了這個問題)

 

針對“追加操作不是原子操作”的問題,我們就開始調研有哪些可以解決這個問題同時又滿足業務資料類型的分布式緩衝解決方案。

當前,業界常用的一些 key-value分布式緩衝系統如下:

  • Redis
  • Memcached
  • Cassandra
  • Tokyo Tyrant (Tokyo Cabinet)

參考自:

  • 2010年的技術架構建議 – Tim Yang
  • From distributed caches to in-memory data grids
  • Cassandra vs MongoDB vs CouchDB vs Redis vs Riak vs HBase vs Couchbase vs OrientDB vs Aerospike vs Hypertable vs Elasticsearch vs Accumulo vs VoltDB vs Scalaris comparison

通過對比、篩選分析,我們最終選擇了 Redis。原因有以下幾個:

  • Redis 是一個 key-value 的緩衝(cache)儲存(store)系統(現在我們只用它來做緩衝,目前還未當作DB用,資料存放在 Cassandra 裡)
  • 支援豐富的資料結構List 就專門用於儲存列表型資料,預設按操作時間排序。Sorted Set 可以按分數排序元素,分數是一種廣義概念,可以是時間評分。其次,其豐富的資料結構為日後擴充提供了很大的方便。
  • 提供的所有操作都是原子操作,為並發天然保駕護航。
  • 超快的效能,見其官方效能測試《How fast is Redis?》。
  • 擁有比較成熟的Java用戶端 - Jedis,像新浪微博都是使用它作為用戶端。(官方推薦的Clients)

囉嗦了一些其它東西,現在言歸正傳。

 

Redis 服務上線當天,就密切關注 Redis 的一些重要監控指標(clients用戶端串連數、memory、stats:伺服器每秒鐘執行的命令數量、commandstats:一些關鍵命令的執行統計資訊、redis.error.log異常日誌)。(參考自《Redis監控方案》)

 

觀察到下午5點左右,發現“用戶端串連數”一直在增長,最高時都超過了2000個(見),即使減少也就減1~2個。但應用的QPS卻在 10 個左右,而線上應用伺服器不超過10台。按理說,伺服器肯定不會有這麼高的串連數,肯定哪裡使用有問題。

 

 

現在只能通過逆向思維反向來推測問題

  • Redis服務端監控到的“用戶端串連數”表明所有用戶端總和起來應該有那麼多,所以首先到各個應用伺服器上確認串連數量;
  • 通過“sudo netstat -antp | grep 6379 | wc -l”確認,有一台應用Redis的串連數都超過了1000個,另一台應用則在400左右,其它的都在60上下。(60上下是正常的)
  • 第一個問題:為什麼不同的機器部署了同一個應用程式,表現出來的行為卻是不一樣?
  • 第二個問題:串連數超過1000個的那台,其請求量(140)是比其它機器(200+)要低的(因為它在Nginx中配置的權重低),那它的串連數為什麼會這麼高?到底發生了什嗎?
  • 對於“第二個問題”,我們通過各個應用的Redis異常日誌(redis.error.log)知道發生了什麼。最高那台應用的異常操作特別多,共有130+個異常,且存在“關閉叢集連結時異常導致串連泄漏”問題;另一台較高的應用也存在類似的情況,而其它正常的應用則不超過2個異常,且不存在“串連泄漏”問題。這樣,“第二個問題”算是弄清楚了。(“串連泄漏”問題具體如何修複見《[FAQ] Jedis使用過程中踩過的那些坑》)
  • 至此,感覺問題好像已經解決了,但其實沒有。通過連續幾天的觀察,發現最高的時候,它的串連數甚至超過了3000+,這太恐怖了。(當時 leader 還和我說,要不要重啟一下應用)
  • 即使應用的QPS是 20個/s,且存在“串連泄漏”問題,串連數也不會超過1000+。但現在串連數盡然達到了3000+,這說不通,只有一個可能就是未正確使用Jedis
  • 這時候就繼續反推,Redis的串連數反映了Jedis對象池的池對象數量。線上部署了2台Redis伺服器作為一個叢集,說明這台應用共持有(3000/2=1500)個池對象。(因為Jedis基於Apache Commons Pool的GenericObjectPool實現)
  • 第三個問題:根據應用的QPS,每秒鐘請求需要的Active池對象也不會超過20個,那其餘的1480個都是“空閑池對象”。為什麼那麼多的“空閑池對象”未被釋放?
  • 現在就來反思:Jedis的那些配置屬性與對象池管理“空閑池對象”相關,GenericObjectPool背後是怎麼管理“空閑池對象”的?

由於在使用Jedis的過程中,就對Apache Commons Pool摸了一次底。對最後的兩個疑惑都比較瞭解,Jedis的以下這些配置與對象池管理“空閑池對象”相關:

redis.max.idle.num=32768
redis.min.idle.num=30
redis.pool.behaviour=FIFO
redis.time.between.eviction.runs.seconds=1
redis.num.tests.per.eviction.run=10
redis.min.evictable.idle.time.minutes=5
redis.max.evictable.idle.time.minutes=1440

 

在上面說“每台應用的Jedis串連數在60個左右是正常的”的理由是:線上共部署了2台Redis伺服器,Jedis的“最小空閑池對象個數”配置為30 (redis.min.idle.num=30)。

 

GenericObjectPool是通過“驅逐者線程Evictor”管理“空閑池對象”的,詳見《Apache Commons Pool之空閑對象的驅逐檢測機制》一文。最下方的5個配置都是與“驅逐者線程Evictor”相關的,表示對象池的空閑隊列行為為FIFO“先進先出”隊列方式,每秒鐘(1)檢測10個空閑池對象,空閑池對象的空閑時間只有超過5分鐘後,才有資格被驅逐檢測,若空閑時間超過一天(1440),將被強制驅逐。

 

因為“驅逐者線程Evictor”會無限制迴圈地對“池對象空閑隊列”進行迭代式地驅逐檢測。空閑隊列的行為有兩種方式:LIFO“後進先出”棧方式、FIFO“先進先出”隊列方式,預設使用LIFO。下面通過兩幅圖來展示這兩種方式的實際運作方式:

   一、LIFO“後進先出”棧方式

 

二、FIFO“先進先出”隊列方式

 

從上面這兩幅圖可以看出,LIFO“後進先出”棧方式 有效地利用了空閑隊列裡的熱點池對象資源,隨著流量的下降會使一些池對象長時間未被使用而空閑著,最終它們將被淘汰驅逐;而 FIFO“先進先出”隊列方式 雖然使空閑隊列裡所有池對象都能在一段時間裡被使用,看起來它好像分散了資源的請求,但其實這不利於資源的釋放。而這也是“用戶端串連數一直降不下來”的根源之一

redis.pool.behaviour=FIFO
redis.time.between.eviction.runs.seconds=1
redis.num.tests.per.eviction.run=10
redis.min.evictable.idle.time.minutes=5

按照上述配置,我們可以計算一下,5分鐘裡到底有多少個空閑池對象被迴圈地使用過。
根據應用QPS 10個/s計算,5分鐘裡大概有10*5*60=3000個空閑池對象被使用過,正好與上面的“串連數盡然達到了3000+”符合,這樣就說得通了。至此,整個問題終於水落石出了。(從監控圖也可以看出,在21號晚上6點左右修改配置重啟服務後,串連數就比較平穩了)

 

這裡還要解釋一下為什麼使用FIFO“先進先出”隊列方式的空閑隊列行為?

因為我們在Jedis的基礎上開發了“故障節點自動摘除,恢複正常的節點自動添加”的功能,本來想使用FIFO“先進先出”隊列方式在節點故障時,對象池能快速更新整個叢集資訊,沒想到弄巧成拙了。

修複後的Jedis配置如下:

redis.max.idle.num=32768
redis.min.idle.num=30
redis.pool.behaviour=LIFO
redis.time.between.eviction.runs.seconds=1
redis.num.tests.per.eviction.run=10
redis.min.evictable.idle.time.minutes=5
redis.max.evictable.idle.time.minutes=30

 

綜上所述,這個問題發生有兩方面的原因:

    1. 未正確使用對象池的空閑隊列行為LIFO“後進先出”棧方式)
    2. 關閉叢集連結時異常導致串連泄漏”問題

 

http://www.myexception.cn/internet/1849994.html

 

"Redis用戶端串連數一直降不下來"的有關問題解決

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.