近千節點的Redis Cluster高可用集羣案例:優酷藍鯨優化實戰

在優酷,咱們使用 Redis Cluster 構建了一套內存存儲系統,項目代號爲藍鯨。藍鯨的設計目標是高效讀寫,全部數據都在內存中。藍鯨的主要應用場景是 cookie 和大數據團隊計算的數據,都具備較強的時效性,所以全部的數據都有過時時間。更準確的說藍鯨是一個全內存的臨時存儲系統。前端

到目前爲止集羣規模逐漸增加到 700+ 節點,即將達到做者建議的最大集羣規模 1,000 節點。咱們發現隨着集羣規模的擴大,帶寬壓力不斷突出,而且響應時間 RT 方面也會略微升高。與一致性哈希構建的 Redis 集羣不同,Redis Cluster 不能作成超大規模的集羣,它比較適合做爲中等規模集羣的解決方案。node

運維期間,吞吐量與 RT 一直做爲衡量集羣穩定性的重要指標,這裏在本文中,咱們碰到的影響集羣吞吐量與 RT 的一些問題與探索記錄下來,但願對你們有所幫助。redis

1 - Redis Cluster 工做原理

Redis 採用單進程模型,除去 bgsave 與 aof rewrite 會另外新建進程外,全部的請求與操做都在主進程內完成。其中比較重量級的請求與操做類型有:數據庫

  1. 客戶端請求
  2. 集羣通信
  3. 從節同步
  4. AOF 文件
  5. 其它定時任務

Redis 服務端採用Reactor 設計模式,它是一種基於事件的編程模型,主要思想是將請求的處理流程劃分紅有序的事件序列,好比對於網絡請求一般劃分爲:Accept new connectionsRead input to bufferProcess requestResponse等幾個事件。並在一個無限循環的 EventLoop 中不斷的處理這些事件。更多關於Reactor,請參考 https://en.wikipedia.org/wiki/Reactor編程

比較特別的是,Redis 中還存在一種時間事件,它實際上是定時任務,與請求事件同樣,它一樣在 EventLoop 中處理。Redis 主線程的主要處理流程以下圖:設計模式

主線程處理流程

理解了 Redis 的單進程模型與主要負載狀況,很容易明白,想要增長 Redis 吞吐量,只須要儘可能下降其它任務的負載量就好了,因此提升 Redis 集羣吞吐量的方式主要有:緩存

A) - 提升 Redis 集羣吞吐的方法安全

  1. 適當調大 cluster-node-timeout 參數

咱們發現當集羣規模達到必定程度時,集羣間消息通信開銷的帶寬是極其可觀的。cookie

集羣通訊機制網絡

Redis 集羣採用無中心的方式,爲了維護集羣狀態統一,節點之間須要互相交換消息。Redis採用交換消息的方式被稱爲 Gossip ,基本思想是節點之間互相交換信息最終全部節點達到一致,更多關於 Gossip 可參考 https://en.wikipedia.org/wiki/Gossip_protocol

gossip

總結集羣通訊機制的一些要點:

  • Who:集羣中每一個節點
  • When:定時發送,默認每隔一秒
  • What:一個長度爲 16,384 的 Bitmap 與集羣中其它節點狀態的十分之一

如何理解集羣中節點狀態的十分之一?假如集羣中有 700 個節點,十分之一就是 70 個節點狀態,節點狀態具體數據結構見下邊代碼:

輸入圖片說明

咱們將注意力放在數據包大小與流量上,每一個節點狀態大小爲 104 byte,因此對於 700 個節點的集羣,這部分消息的大小爲 70 * 104 = 7280,大約爲 7KB。另外每一個 Gossip 消息還須要攜帶一個長度爲 16,384 的 Bitmap,大小爲 2KB,因此每一個 Gossip 消息大小大約爲 9KB。

隨着集羣規模的不斷擴大,每臺主機的流量不斷增加,咱們懷疑集羣間通訊的流量已經大於前端請求產生的流量,因此作了如下實驗以明確集羣流量情況。

實驗過程

實驗環境爲:節點 704,物理主機 40 臺,每臺物理主機有 16 個節點,集羣採用一主一從模式,集羣中節點 cluster-node-timeout 設置爲 30 秒。

實驗的大概思路爲,分別截取一分鐘時間內一個節點,在集羣通訊端口上,進入方向與出去方向的流量,並統計出消息條數,並最終計算出臺主機由於集羣間通信產生的帶寬開銷。實驗具體過程以下:

輸入圖片說明

經過實驗能看到進入方向與出去方向在 60s 內收到的數據包數量爲 2,700 多個。由於 Redis 規定每一個節點每一秒只向一個節點發送數據包,因此正常狀況每一個節點平均 60s 會收到 60 個數據包,爲何會有這麼大的差距?

原來考慮到 Redis 發送對象節點的選取是隨機的,因此存在兩個節點好久都沒有交換消息的狀況,爲了保證集羣狀態能在較短期內達到一致性,Redis 規定當兩個節點超過 cluster-node-timeout 的一半時間沒有交換消息時,下次心跳交換消息。

解決了這個疑惑,接下來看帶寬狀況。先看 Redis Cluster 集羣通訊端口進入方向每臺主機的每秒帶寬爲:

輸入圖片說明

輸入圖片說明

輸入圖片說明

輸入圖片說明

通過以上實驗咱們能得出兩個結論:

集羣間通訊佔用大量帶寬資源 調整 cluster-node-timeout 參數能有效下降帶寬

Redis Cluster 斷定節點爲 fail 的機制

可是並非 cluster-node-timeout 越大越好。當 cluster-node-timeou 增大的時候集羣判斷節點 fail 的時間會增長,從而 failover 的時間窗口會增長。集羣斷定節點爲fail所需時間的計算公式以下:

當節點向失敗節點發出 PING 消息,而且在 cluster-node-timeout 時間內尚未收到失敗節點的 PONG 消息,此時斷定它爲 pfail 。pfail 即部分失敗,它是一種中間狀態,該狀態隨着集羣心跳不斷傳播。再通過一半 cluster-node-timeout 時間後,全部節點都與失敗的節點發生過心跳而且把它標記爲 pfail 。固然也可能不須要這麼長時間,由於其它節點之間的心跳一樣會傳遞 pfail 狀態,這裏姑且以最大時間計算。

Redis Cluster 規定當集羣中超過一半以上節點認爲一個節點爲 pfail 狀態時,會把它標記爲 fail 狀態,並廣播給其餘全部節點。對於每一個節點而言平均一秒鐘收到一個心跳包,每次心跳都會攜帶隨機的十分之一的節點個數。因此如今問題抽像爲通過多長時間一個節點會積累到一半的 pfail 狀態數。這是一個機率問題,由於我的並不擅長几率計算,這裏直接取了一個較大機率能知足條件的數值 10。

因此上述公式不是達到這麼長時間必定會斷定節點爲 fail,而是通過這麼長時間集羣有很大機率會斷定節點 fail 。

Redis Cluster 默認 cluster-node-timeout 爲 15s,咱們將它設置成了 30s。也就是說 700 節點的集羣,集羣間帶寬開銷爲 104.5MBit / s,斷定節點失敗時間窗口大概爲 55s,實際上大多數狀況都小於 55s,由於上邊的計算都是按照高位時間估算的。

總而言之,對於大的 Redis 集羣 cluster-node-timeout 參數的須要謹慎設定。

提升 Redis 集羣吞吐的方法 2. 控制主節點寫命令傳播

Redis 中主節點的每一個寫命令傳播到如下三個地方:

本地 AOF 文件,以持久化持數據 主節點的全部從節點,以保持主從數據同步 本節點的 repl_backlog 緩存,主要爲了支持部分同步功能,詳見官網 Replcation 文檔 Partial resynchronization 部分:http://redis.io/topics/replication

其中 repl_backlog 部分傳播在 replicationFeedSlaves 函數中完成。

減小從節點的數量

高可用的集羣不該該出現單點,因此 Redis 集羣通常都會是主從模式。Redis 的主從同步機制是全部的主節點的寫請求,會同步到全部的從節點。若是沒有從節點,對於主節點來講,它只須要處理該請求便可。但對於有 N 個從節點的主節點來講,它須要額外的將請求傳播給 N 個從節點。請注意這裏是對於每一個寫請求都會這樣處理。顯而易見從節點的數量對主節點的吞吐量的影響是比較大的,咱們採用的是一主一從模式。

由於從節點不須要同步數據,生產環境中觀察主節點的 CPU 佔用率要比從節點機器要高,這對這條結論起到了佐證的做用。

關閉 AOF 功能

若是開啓 AOF 功能,每一個寫請求都會 Append 到本地 AOF 文件中,雖然 Linux 中寫文件操做會利用到操做系統緩存機制,可是若是關閉 AOF 功能主線程中省去了寫 AOF 文件的操做,顯然會對吞吐量的增長有幫助。

AOF 是 Redis 的一種持久化方式,若是關閉了 AOF 功能怎麼保證數據的安全性。咱們的作法是定時在從節點 BGSAVE。固然具體採用何種策略須要結合具體狀況來決定。

去掉頻繁的 Cluster nodes 命令

在運維過程當中發現前端請求的平均 RT 增長很多,大概 50% 左右。經過一番調研,發現是頻繁的 cluster nodes 命令致使。

當時集羣規模爲 500+ 節點,cluster nodes 命令返回的結果大小有 103KB。cluster nodes 命令的頻率爲:每隔 20s 向集羣全部節點發送。

提升 Redis 集羣吞吐的方法 3. 調優 hz 參數

Redis 會定時作一些任務,任務頻率由 hz 參數規定,定時任務主要包含:

主動清除過時數據 對數據庫進行漸式Rehash 處理客戶端超時 更新請求統計信息 發送集羣心跳包 發送主從心跳

如下是做者對於 hz 參數的介紹:

輸入圖片說明

咱們沒有修改 hz 參數的經驗,因爲其複雜性,而且在 hz 默認值 10 的狀況下,理論上不會對 Redis 吞吐量產生太大影響,建議沒有經驗的狀況下不要修改該參數。

參考資料

關於 Redis Cluster 能夠參考官方的兩篇文檔:

Redis cluster tutorial: http://www.redis.io/topics/cluster-tutorial Redis Cluster specification: http://www.redis.io/topics/cluster-spec

相關文章
相關標籤/搜索