Redis數據量日益增大,使用的公司愈來愈多,不只用於作緩存,同時趨向於存儲這一塊,這樣必促使集羣的發展,各個公司也在收集適合本身的集羣方案,目前行業用的比較多的是下面幾種集羣架構,大部分都是採用分片技術,保證單實例內存增大帶來的一系列問題,下面所列出的codis方案目前正在不斷測試過程當中,測試過程沒有展現出來,主要從如下幾點出發。node
測試架構和性能:web
一、keepalived+haproxy故障測試redis
二、Zookeeper集羣節點測試算法
三、Codis-proxy集羣節點測試數據庫
四、Codis-server集羣節點測試瀏覽器
五、腳本寫入大量測試數據並模擬數據遷移緩存
六、性能測試安全
下面具體介紹codis和其餘幾大集羣方案ruby
集羣方案:網絡
一、 主從高可用(該方案就是單實例形式,只是爲了保證數據的安全,對於用戶數據少,業務的前期能夠採用,目前我司緩存架構就是採用該方案)
二、 客戶端分片(典型表明:Jedis。自主寫分片算法,代碼掌握在本身手中,可控性強,可是須要專業的開發運維人員維護,技術要求和維護成本高)
三、代理分片(典型表明:Twemproxy,redis集羣沒有正式推出以前官網推薦的方案,也是目前使用最多的)
四、 Redis cluster(3版本推出的集羣方案,歷時四年之多的開發)
五、 Codis集羣(豌豆莢15年開源的解決方案,開源以前其已經用了2年之多,與其同期官網推出redis cluster)
六、 各大互聯網公司自主研發的集羣架構,可是尚未開源,可能也不會開源
根據以上的簡單介紹,下面主要解釋後面三種集羣方案的特色,以及針對業務的具體狀況,斟酌選擇合適的架構思考。
codis架構圖
簡單說明:一、codis-proxy提供鏈接集羣redis的服務入口
二、codis-config管理工具,支持包括添加/刪除redis/proxy節點,發起數據遷移等操做,自帶一個dashboard工具,瀏覽器能夠直觀查看集羣的運行狀態
三、codis-server-group實現redis讀寫的水平擴展、高性能
四、codis-server實現redis實例服務,經過codis-ha實現服務的高可用
五、Zookeeper/etcd存放數據路由表和codis-proxy節點的元信息,codis-config發起的命令經過其同步到各個存活的codis-proxy,則zookeeper若是出問題則可能致使數據不一致的狀況或者嚴重的會對外提供服務形成影響
說明:一切知識點來源於官方,本人通過測試一步步驗證,大體總結以上幾點
Twemproxy架構圖
簡單說明:一、proxy提供分片算法和redis服務入口,支持高可用
二、Redis提供實現實例,而且經過sentinel支持高可用
三、Redis-Twemporxy提供通知底層HA切換至proxy
四、每一個層結構出現問題或者變動節點信息等全部操做都須要從新規劃分片算法,則須要重啓服務
Redis cluster架構圖
簡單說明:一、redis cluster自己集羣方案,客戶端能夠任一鏈接一個節點
二、redis-trib.rb腳本爲集羣的管理工具,好比自動添加節點,規劃槽位,遷移數據等一系列操做(ruby語言)
三、每一個節點都和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獨特之處 |
不支持 |
一、 有中心節點,邏輯問題交由proxy處理,codis還有個特色下層存儲能夠根據數據的冷熱程度把冷數據暫時保存至磁盤,待其爲熱數據的時候又能夠上線(這點我尚未測試) 二、 提供數據在線遷移的工具 好比需求要從redis或者twemproxy遷移數據至codis或者之後redis數據庫中,又不想直接預熱,能夠藉助其提供的redis-port命令行工具 |
不支持 |
開發語言 |
C語言 |
Go語言、C語言 |
C語言 |
服務啓動方式 |
單進程 |
多進程 |
單進程 |
性能問題 |
一、 單點的話比起原子redis下降20%左右; 二、 增長PIPELINE管道提升性能 只要是代理的設計性能瓶頸確定在其,因redis實在太快 |
一、 至關於單redis實例40%性能丟失(從最開始的版本比Twemproxy慢20%至目前比其快100%); 二、 彌補:增長proxy數量和支持多核,比起Twemproxy仍是好一點,因Twemproxy最好的狀況跑滿一個CPU; 三、 彌補:增長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 |
數據一致性 |
不能保證強一致性 一、 如redis cluster第一種狀況沒有,設計不同 二、 網絡分裂,這種狀況其有監控工具能夠通知管理員某個主節點宕機,這時若是管理員切換HA(可是不提供自動提高從節點爲主節點,因從節點變爲主節點必須更新分片算法,重啓服務),數據就會丟失,因主節點的寫命令會丟失,除非再次AOF同步最後一條寫命令,兩者如國管理員能夠判斷其爲網絡分裂,等待網絡恢復是主節點會向從節點同步寫命令數據 |
強一致性 一、 數據遷移過程當中數據強一致性性,因遷移都是一個個KEY原子遷移,每次操做都是給ZK發送信息,通知proxy,同時全部操做都是上一把鎖,假如該期間有客戶端訪問,則提高訪問該KEY的操做爲優先操做,快速遷移至新節點,訪問轉移至新節點,不會訪問老的KEY,如期間也能夠中斷正在同步的數據,也是不影響,由於redis沒有回滾機制,要麼成功要麼失敗 二、 網絡分裂:由於它的設計初衷就是不考慮HA自動切換(後面添加該功能),等到網絡恢復Zookeeper保證數據一致性,寫命令不會丟失,全部操做都要在zookeeper上面註冊 |
不能保證強一致性 好比官網給出的兩種有可能丟失寫命令的狀況以下 一、 客戶端向主節點A發送一條寫命令,主節點是首先立馬向客戶端返回命令回覆,而後再把剛剛的執行寫命令同步至從節點,追求性能所致該設計 二、 網絡分裂(network partition),若是時間很長致使A節點的從節點轉換爲主節點,然這中間可能存在客戶端正在和A節點通訊也就被孤立了,這樣寫的命令將丟失,如當網絡恢復A又從新加入集羣 |
數據的特殊安全 |
一、 好比某段時間業務數據一下爆表(內存寫滿),數據來不及遷移,這樣的話redis會根據LRU策略,會淘汰一部分老的key,這個沒辦法,因此運維中當內存使用80%時應該擴容 二、 主從切換過程當中有一部分數據丟失(主掛了到從切換上來丟失的這部分數據) |
||
磁盤IO |
基於redis自己的持久化(RDB和AOF),確定會存在數據丟失的狀況 |
||
數據的遷移 |
不可在線遷移,而且遷移完以後須要修改配置文件的分片算法,再從新啓動Twemproxy服務,從新識別分片算法 |
採用sharding在線遷移數據,安全透明,能夠自動平衡數據到其餘節點,至關於可熱插撥,不會形成響應時延(因遷移時會另外有個進程來作,數據遷移仍是原子的數據遷移指令,這樣遷移的話就會至關慢一些) |
在線遷移數據,動態遷移KEY值會形成響應時延(遷移數據是拷貝RDB數據文件,並且由於redis是單進程的),另外新節點solt又不自動,依賴ruby(redis cluster集羣管理和分配腳本)腳原本平衡數據,無中心設計如此 |
水平擴容縮容(增減節點) |
Redis存儲層操做,不提供自動的解決方案,而且要本身寫腳本支持數據的搬遷活動,而後更改proxy哈希算法,重啓服務 |
Redis存儲層,都是在線操做(擴容數據遷移,縮容的話先搬遷數據至別的節點,而後下線該節點) |
沒有代理和存儲之分,能夠在線操做(擴容數據遷移,縮容的話先搬遷數據至別的節點,而後下線該節點) |
主從是否必須 |
一、 沒有數據複製不影響可用節點代替故障節點 二、 若是沒有作備份,故障節點key所有丟失 |
一、 故障節點若是沒有備份,則丟失掉該組的全部數據,可是不影響其餘組的運行,不會致使整個集羣壞掉 二、 若有備份節點,則把其升爲主節點,集羣沒有影響,正常運轉(須要管理員手動變動從節點爲主節點,最新版本添加HA功能) |
沒有主從複製的節點一旦故障,將致使整個集羣不可用,沒法寫入或者讀入任何key,沒法進行數據從新分片 官網建議:至少3主3從 |
主從特色 |
基於redis自己的主從方案(利用發佈/訂閱機制,採用廣播形式), 採用異步複製(asynchronous replication)的方案,不管是master端仍是slave端都不會引發阻塞,可是確定是存在數據丟失的狀況 |
||
集羣設計 |
一、 proxy部署高可用(多proxy結合keepalived+haporxy) 二、 redis層設計多主多從部署 |
一、 proxy部署(多proxy+zookeeper集羣方案,而且結合keepalived+haporxy) 二、 codis-server部署多組,每組部署一主多從架構 |
利用redis自己部署集羣:至少3主3從 |
HA方案 |
Proxy層已經有了,由上面的設計,redis層基於自帶的HA解決方案(sentinel),這裏不闡述sentinel機制 |
Proxy層已經有了,存儲層原本設計就沒有考慮自動HA切換,後面根據用戶強烈的要求,目前添加codis-ha解決 |
自主監控自動切換(把sentinel功能搬遷過來) |
故障監控 |
自帶監控並告警 |
自帶監控並告警 |
目前尚未提供 |
故障檢測和故障轉移時間 |
一、proxy配置文件設置:auto_eject_hosts: true timeout: 400 server_failure_limit: 3 當proxy server超時400毫且3次重試機會,則認爲該proxy節點壞掉,這樣故障節點從hash環直接取下,而且清理該Key信息 故障轉移耗時:400*3=1200毫秒 二、若是存儲層加入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秒。 |
一、 proxy層配置文件: backend_ping_period=5 則表示5秒zookeeper沒有等到pong迴應就認爲proxy已經壞掉 故障轉移耗時:5秒 二、 存儲層原本不設置自動故障遷移的 (後面添加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秒。
|
功能限制 |
一、 不支持多key操做 二、 不支持MULTI/EXEC 三、 不支持EVAL |
比較多,能夠查看官方文檔 |
一、 複雜的多KEY(set求並求交集)不能跨節點操做 二、 不支持MULTI/EXEC 三、 寫丟失比較頻繁 |
提供支持 |
不在維護 |
目前活躍狀態 |
官網主打 |
客戶端driver工具 |
保持不變(redis支持的都支持) |
保持不變(redis支持的都支持) |
只能支持cluster協議的客戶端工具(目前官網上面說的是針對JAVA的是Jides,針對PHP的是Predis,並且不成熟) |
歸納 |
一、 輕量級 二、 在proxy層實現一致性哈希 三、 快速的故障轉移 四、 可藉助sentinel實現底層HA 五、 每次變動必須重啓生效 |
一、 基於zookeeper的proxy高可用,zookeeper會記錄整個集羣的生存狀態,則須要維護好zookeeper 二、 優點爲動態水平擴容,平衡數據,在遷移的時候不影響業務訪問和響應時間,這點很炫,也是它主打的方向 三、 Dashboard操做下降人失誤率,圖形直觀查看信息 四、 強一致數據(也是設計的重點) |
一、 性能好(也是設計的原則) 二、 無中心組織結構,有利有弊 三、 故障轉移響應時間長 四、 有寫丟失,比較頻繁 |