http://www.tuicool.com/articles/nM7zymJ
Redis 集群 方案選型比較
Redis數據量日益增大,使用的公司越來越多,不僅用于做緩存,同時趨向于存儲這一塊,這樣必促使 集群 的發展,各個公司也在收集適合自己的集群方案, 目前行業用的比較多的是下面幾種集群架構 ,大部分都是采用分片技術,保證單實例內存增大帶來的一系列問題 ,下面所列出的 codis 方案目前正在不斷測試過程中,測試過程沒有展示出來, 主要從以下幾點出發 。
測試架構 和性能 :
1、keepalived+haproxy 故障測試
2、Zookeeper 集群節點測試
3、Codis-proxy 集群節點測試
4、Codis-server 集群節點測試
5、 腳本 寫入大量 測試數據 并模擬 數據遷移
6、 性能測試
下面具體介紹 codis 和其他幾大集群方案
集群方案:
1、 主從高可用(該方案就是單實例形式,只是為了保證數據的安全,對于用戶數據少,業務的前期可以采用,目前我司緩存架構就是采用該方案)
2、 客戶端分片(典型代表: Jedis 。自主寫分片算法,代碼掌握在自己手中,可控性強,但是需要專業的開發運維人員維護,技術要求和維護成本高)
3 、代理分片(典型代表: Twemproxy , redis 集群沒有正式推出之前官網推薦的方案,也是目前使用最多的)
4、 Redis cluster ( 3 版本推出的集群方案,歷時四年之多的開發)
5、 Codis 集群(豌豆莢 15 年開源的解決方案,開源之前其已經用了 2 年之多,與其同期官網推出 redis cluster )
6、 各大互聯網公司自主研發的集群架構,但是還沒有開源,可能也不會開源
根據以上的簡單介紹,下面主要解釋后面三種集群方案的特點,以及針對 業務 的具體情況,斟酌選擇合適的架構思考。
codis 架構圖

簡單說明: 1 、 codis-proxy 提供連接集群 redis 的服務入口
2 、 codis-config 管理工具,支持包括添加 / 刪除 redis/proxy 節點,發起數據遷移等操作,自帶一個 dashboard 工具,瀏覽器可以直觀查看集群的運行狀態
3 、 codis-server-group 實現 redis 讀寫的水平擴展、高性能
4 、 codis-server 實現 redis 實例服務,通過 codis-ha 實現服務的高可用
5 、 Zookeeper/etcd 存放數據路由表和 codis-proxy 節點的元信息, codis-config發起的命令通過其同步到各個存活的 codis-proxy ,則 zookeeper 如果出問題則可能導致數據不一致的情況或者嚴重的會對外提供服務造成影響
說明:一切知識點來源于官方,本人經過測試一步步驗證,大致總結以上幾點
Twemproxy 架構圖

簡單說明: 1 、 proxy 提供分片算法和 redis 服務入口,支持高可用
2 、 Redis 提供實現實例,并且通過 sentinel 支持高可用
3 、 Redis-Twemporxy 提供通知底層 HA 切換至 proxy
4 、每個層結構出現問題或者變更節點信息等所有操作都需要重新規劃分片算法,則需要重啟服務
Redis cluster 架構圖

簡單說明: 1 、 redis cluster 本身集群方案,客戶端可以任一連接一個節點
2 、 redis-trib.rb 腳本為集群的管理工具,比如自動添加節點,規劃槽位,遷移數據等一系列操作( ruby 語言)
3 、每個節點都和 N-1 個節點通信,所以要維護好這個集群架構的每個節點信息,不然會導致整個集群不可工作
注意:以下三大方案redis cluster基于3.0版本
Redis 集群方案各參數比較
| Twemproxy | Codis | Redis Cluster |
架構設計 | 分布式 CAP, 犧牲 P 性能,而僅僅只是數據分片 | 分布式 CAP, 犧牲 P 性能,設計初衷為數據一致性 | 分布式 CAP,犧牲 C 數據強一致性原則,追求redis 最大的特點性能 |
設計模型 | Proxy-based | Proxy-based | Gossip/P2P |
設計思路 | 分布式邏輯和存儲引擎分開,邏輯層 proxy 代理,存儲用的是原子 redis ,當每個層面需要添加刪除節點必須重啟服務生效(要重新利用散列函數生成 KEY 分片更新) | 分布式邏輯和存儲引擎分開,邏輯層 codis-proxy ,存儲用的是修改過的 codis-server, 這種好處是 proxy 層可以自動擴展和收縮,存儲層也同樣可以,每個層面都可以熱插撥 | 分布式的邏輯和存儲引擎不分開,即又負責讀寫操作,又負責集群交互,升級困難,如果代碼有 bug ,集群無法工作 |
架構特點 | Proxy 無狀態, redis數據層有狀態的,客戶端可以請求任一 proxy 代理上面,再由其轉發至正確的 redis 節點,該 KEY分片算法至某個節點都是預先已經算好的,在 proxy 配置文件保存著,但是如果更新或者刪除節點,又要根據一致性 hash 重新計算分片,并且重啟服務 | Proxy 無狀態, codis-server 分為組間,每個組存在一個主節點(必須有并且只能有一個)和多個從節點。客戶端請求都是和 proxy 鏈接,鏈接哪個 proxy 都一樣,然后由它根據 zookeeper 路由信息轉發至正確節點,直接可以定位到正確節點上 | 這個結構為無中心的組織,不好把控集群當前的存活狀態,客戶端可以向任一節點發送請求,再有其重定向正確的節點上。如果在第一次請求和重定向期間 cluster 拓撲結構改變,則需要再一次或者多次重定向至正確的節點,但是這方面性能可以忽悠不計 |
codis獨特之處 | 不支持 | 1、 有中心節點,邏輯問題交由 proxy 處理, codis還有個特點下層存儲可以根據數據的冷熱程度把冷數據暫時保存至磁盤,待其為熱數據的時候又可以上線(這點我還沒有測試) 2、 提供數據在線遷移的工具 比如需求要從 redis 或者 twemproxy 遷移數據至 codis或者以后 redis 數據庫中,又不想直接預熱,可以借助其提供的 redis-port 命令行工具 | 不支持 |
開發語言 | C 語言 | Go 語言、 C 語言 | C 語言 |
服務啟動方式 | 單進程 | 多進程 | 單進程 |
性能問題 | 1、 單點的話比起原子redis 降低 20% 左右; 2、 增加 PIPELINE 管道提高性能 只要是代理的設計性能瓶頸肯定在其,因 redis實在太快 | 1、 相當于單 redis 實例 40% 性能丟失 ( 從最開始的版本比 Twemproxy慢20% 至目前比其快 100%) ; 2、 彌補:增加 proxy 數量和支持多核,比起 Twemproxy 還是好一點,因 Twemproxy 最好的情況跑滿一個 CPU ; 3、 彌補:增加 PIPELINE管道提高性能 只要是代理的設計性能瓶頸肯定在其,因 redis 實在太快 | 沒什么損失,追求的就是這個 1000 個節點內擁有線性的伸縮性,和操作 redis實例性能差不多 |
分片算法 | Redis 一致 hash ,當初設計好如后續變更修改(增減節點)需要配置 proxy 通知新的算法,重啟服務 | 通過presharding采用 solt槽位的形式,整個集群分為1024 個哈希槽,分片算法位SlotId = crc32(key) % 1024,增減節點不需要重啟服務 | 采用 solt 槽位的形式,整個集群分為 16384 個哈希槽,分片算法位 SlotId = crc16(key) % 16384,增減節點不需要重啟服務 |
所需組件 | Redis 、 twemproxy(nutcracker) | Codis 、 zookeeper | redis |
數據一致性 | 不能保證強一致性 1、 如 redis cluster 第一種情況沒有,設計不一樣 2、 網絡分裂,這種情況其有監控工具可以通知管理員某個主節點宕機,這時如果管理員切換 HA(但是不提供自動提升從節點為主節點,因從節點變為主節點必須更新分片算法,重啟服務),數據就會丟失,因主節點的寫命令會丟失,除非再次 AOF 同步最后一條寫命令,二者如國管理員可以判斷其為網絡分裂,等待網絡恢復是主節點會向從節點同步寫命令數據 | 強一致性 1、 數據遷移過程中數據強一致性性,因遷移都是一個個 KEY 原子遷移,每次操作都是給 ZK 發送信息,通知 proxy ,同時所有操作都是上一把鎖,假如該期間有客戶端訪問,則提升訪問該KEY 的操作為優先操作,快速遷移至新節點,訪問轉移至新節點,不會訪問老的 KEY ,如期間也可以中斷正在同步的數據,也是不影響,因為 redis 沒有回滾機制,要么成功要么失敗 2、 網絡分裂:因為它的設計初衷就是不考慮 HA 自動切換(后面添加該功能),等到網絡恢復 Zookeeper 保證數據一致性,寫命令不會丟失 ,所有操作都要在zookeeper 上面注冊 | 不能保證強一致性 比如官網給出的兩種有可能丟失寫命令的情況如下 1、 客戶端向主節點 A 發送一條寫命令,主節點是首先立馬向客戶端返回命令回復,然后再把剛剛的執行寫命令同步至從節點,追求性能所致該設計 2、 網絡分裂(network partition) ,如果時間很長導致 A 節點的從節點轉換為主節點,然這中間可能存在客戶端正在和 A 節點通信也就被孤立了,這樣寫的命令將丟失,如當網絡恢復 A 又重新加入集群 |
數據的特殊安全 | 1、 比如某段時間業務數據一下爆表(內存寫滿),數據來不及遷移,這樣的話 redis 會根據 LRU 策略,會淘汰一部分老的 key ,這個沒辦法,所以運維中當內存使用 80% 時應該擴容 2、 主從切換過程中有一部分數據丟失(主掛了到從切換上來丟失的這部分數據) |
磁盤 IO | 基于 redis 本身的持久化( RDB 和 AOF ),肯定會存在數據丟失的情況 |
數據的遷移 | 不可在線遷移,并且遷移完之后需要修改配置文件的分片算法,再重新啟動 Twemproxy 服務,重新識別分片算法 | 采用 sharding 在線遷移數據,安全透明,可以自動平衡數據到其他節點,相當于可熱插撥,不會造成響應時延(因遷移時會另外有個進程來做,數據遷移還是原子的數據遷移指令,這樣遷移的話就會相當慢一些) | 在線遷移數據,動態遷移 KEY 值會造成響應時延(遷移數據是拷貝 RDB 數據文件,而且因為 redis 是單進程的),另外新節點 solt 又不自動,依賴 ruby(redis cluster 集群管理和分配腳本 )腳本來平衡數據,無中心設計如此 |
水平擴容縮容(增減節點) | Redis 存儲層操作,不提供自動的解決方案,并且要自己寫腳本支持數據的搬遷活動,然后更改 proxy 哈希算法,重啟服務 | Redis 存儲層,都是在線操作(擴容數據遷移,縮容的話先搬遷數據至別的節點,然后下線該節點) | 沒有代理和存儲之分,可以在線操作(擴容數據遷移,縮容的話先搬遷數據至別的節點,然后下線該節點) |
主從是否必須 | 1、 沒有數據復制不影響可用節點代替故障節點 2、 如果沒有做備份,故障節點 key 全部丟失 | 1、 故障節點如果沒有備份,則丟失掉該組的所有數據,但是不影響其他組的運行,不會導致整個集群壞掉 2、 如有備份節點,則把其升為主節點,集群沒有影響,正常運轉(需要管理員手動變更從節點為主節點,最新版本添加 HA 功能) | 沒有主從復制的節點一旦故障,將導致整個集群不可用,無法寫入或者讀入任何 key ,無法進行數據重新分片 官網建議:至少 3 主 3 從 |
主從特點 | 基于 redis 本身的主從方案(利用發布 / 訂閱機制,采用廣播形式), 采用異步復制( asynchronous replication )的方案,無論是 master 端還是 slave 端都不會引起阻塞,但是肯定是存在數據丟失的情況 |
集群設計 | 1、 proxy 部署高可用(多 proxy 結合 keepalived+haporxy ) 2、 redis 層設計多主多從部署 | 1、 proxy 部署(多 proxy+zookeeper 集群方案,并且結合 keepalived+haporxy ) 2、 codis-server 部署多組,每組部署一主多從架構 | 利用 redis 本身部署集群:至少 3 主 3 從 |
HA 方案 | Proxy 層已經有了,由上面的設計, redis 層基于自帶的 HA 解決方案(sentinel ),這里不闡述sentinel 機制 | Proxy 層已經有了,存儲層本來設計就沒有考慮自動HA 切換,后面根據用戶強烈的要求,目前添加 codis-ha解決 | 自主監控自動切換 ( 把 sentinel功能搬遷過來 ) |
故障監控 | 自帶監控并告警 | 自帶監控并告警 | 目前還沒有提供 |
故障檢測和故障轉移時間 | 1 、 proxy 配置文件設置: auto_eject_hosts: true timeout: 400 server_failure_limit: 3 當 proxy server 超時 400 毫且 3 次重試機會,則認為該 proxy 節點壞掉,這樣故障節點從 hash 環直接取下,并且清理該 Key 信息 故障轉移耗時:400*3=1200 毫秒 2 、如果存儲層加入 sentinel 做 HA (注意:底層 redis 轉移故障之后,因 proxy 層不知道該配置信息已經變動,此時需要引入第四方工具 redis-twemproxy-agent ( node.js ),更新Twemproxy 配置,并重啟) 故障轉移耗時: 每個 sentinel 以每秒發送一次 ping ,配置 down-after-milliseconds=2s,則主觀認為下線 3 秒,然數量 sentinel (配置文件可以配置)認可同意需要 1s ,再 sentinel 當選故障轉移主持節點需要 1秒,選出 slave 升級為 master 需要 0.5 秒,通過發布和訂閱推送更新配置至其他 sentinel 并且配置更新需要 1 秒,這樣 總共耗時 6.5 秒。 | 1、 proxy 層配置文件: backend_ping_period=5則表示 5 秒 zookeeper 沒有等到 pong 回應就認為 proxy已經壞掉 故障轉移耗時: 5 秒 2、 存儲層本來不設置自動故障遷移的 (后面添加 codis-ha 機制) 過程: codis-ha 通過dashboard監控每組的存活狀況,zookeeper 能夠快速知道存活的 proxy 節點,然后休眠3 秒再次監控至重試 3 次,大致 10 秒左右時間切換,但是官方建議,還是不希望使用該解決方案,因主節點有問題,立馬切換從節點為主節點可能導致數據丟失的情況。推薦大家使用手動切換,做好監控,確定好數據安全然后使用 web 界面或者命令手動操作(因用戶的強烈要求才加入該解決方案) | Redis cluster拓撲結構是一張完全圖:每個節點都持有 N-1 個輸入 TCP 和 N-1個輸出 TCP 。 這里不闡述故障監控和切換的流程(比如 FAIL狀態、 slave 選主時機和 cluster邏輯時鐘等) 故障轉移耗時(配置文件可以修改) Node_time=2 Fail_report_validity_mult=3 標記 master為 pfail 耗時 2秒,升級 pfail 為fail 狀態耗時為 2*3=6 秒,選主前隨機延期期望為1 秒,收集足夠多 master 投票為 max((2*node_time),2)=4 秒 這樣總共耗時13 秒。 |
功能限制 | 1、 不支持多 key 操作 2、 不支持 MULTI/EXEC 3、 不支持 EVAL | 比較多,可以查看官方文檔 | 1、 復雜的多KEY(set 求并求交集 ) 不能跨節點操作 2、 不支持 MULTI/EXEC 3、 寫丟失比較頻繁 |
提供支持 | 不在維護 | 目前活躍狀態 | 官網主打 |
客戶端driver工具 | 保持不變( redis 支持的都支持) | 保持不變( redis 支持的都支持) | 只能支持 cluster 協議的客戶端工具(目前官網上面說的是針對JAVA 的是 Jides,針對 PHP 的是 Predis ,而且不成熟) |
概括 | 1、 輕量級 2、 在 proxy 層實現一致性哈希 3、 快速的故障轉移 4、 可借助 sentinel 實現底層 HA 5、 每次變更必須重啟生效 | 1、 基于 zookeeper 的 proxy 高可用 ,zookeeper 會記錄整個集群的生存狀態,則需要維護好 zookeeper 2、 優勢為動態水平擴容,平衡數據,在遷移的時候不影響業務訪問和響應時間,這點很炫,也是它主打的方向 3、 Dashboard 操作降低人失誤率,圖形直觀查看信息 4、 強一致數據(也是設計的重點) | 1、 性能好(也是設計的原則) 2、 無中心組織結構,有利有弊 3、 故障轉移響應時間長 4、 有寫丟失,比較頻繁 |
總結: 沒有最好的架構,只有最合適的架構