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、 有寫丟失,比較頻繁 |
總結:沒有最好的架構,只有最合適的架構
參考資料:
http://www.cnblogs.com/verrion/p/redis_structure_type_selection.html