redis cluster(6)- 集羣應用和問題總結

1、問題:


1、新加節點,如果沒有分配slot,沒有執行redis-trib.rb reshard,

java的java.lang.IllegalArgumentException: Node 10.31.145.246:7032 is unknown to cluster

解決:新加節點需要執行reshard

2、10.46.65.34[ERR] Not all 16384 slots are covered by nodes.

解決:redis.conf配置文件cluster-require-full-coverage 設置爲no,重啓集羣。

槽是否全覆蓋:cluster-require-full-coverage no。默認是yes,只要有結點宕機導致16384個槽沒全被覆蓋,整個集羣就全部停止服務,所以一定要改爲no。 如果將其設置爲yes,則默認情況下,如果key的空間的某個百分比未被任何節點覆蓋,則集羣停止接受寫入。 如果該選項設置爲no,則即使只處理關於keys子集的請求,羣集仍將提供查詢。

遇到個問題…. check節點的時候,會遇到下面的問題…..

>>> Check for open slots…
>>> Check slots coverage…
[ERR] Not all 16384 slots are covered by nodes.
oot@ubuntu:~# redis-cli -c -p 7000
127.0.0.1:7000> set a a
(error) CLUSTERDOWN The cluster is down

 

官方是推薦使用redis-trib.rb fix 來修復集羣…. ….  通過cluster nodes看到7001這個節點被幹掉了… 那麼 /redis-3.0.1/src/redis-trib.rb fix 127.0.0.1:7001  ,如果還是啓動不了的話,可以把相關的cluster-config-file節點同步信息刪掉。

 

2.應用案例收集


5.1 有道:Redis Cluster使用經驗

詳情請參見原文,關鍵內容摘錄如下:

5.1.1 兩個缺點

“redis cluster的設計在這塊有點奇葩,跟集羣相關的操作需要一個外部的ruby腳本來協助(當然可能是爲了讓主程序的代碼足夠簡潔?),然後那個腳本還只支持填實例的ip不支持host,還不告訴你不支持讓你用host之後各種莫名其妙。”

“第一個缺點就是嚴格依賴客戶端driver的成熟度。如果把redis cluster設計成類似Cassandra,請求集羣中任何一個節點都可以負責轉發請求,client會好寫一些。”

“第二個缺點完全是設計問題了,就是一個redis進程既負責讀寫數據又負責集羣交互,雖然設計者已經儘可能簡化了代碼和邏輯,但還是讓redis從一個內存NoSQL變成了一個分佈式NoSQL。分佈式系統很容易有坑,一旦有坑必須升級redis。”

5.1.2 去中心化 vs. Proxy

“關於redis cluster的設計,Gossip/P2P的去中心化架構本身不是問題,但一旦有了中心節點,能做的事情就多了,比如sharding不均勻是很容易自動rebalance的,而無中心的只能靠外界來搞。然後redis cluster又是slot的形式而非C*式的一致性哈希,新節點分slot又不自動,依賴外界(ruby腳本)來分配顯得不方便更不優美和諧。而且因爲是master-slave的系統而非W+R>N的那種,master掛掉之後儘快發現是比較重要的,gossip對於節點掛掉的發現終究沒有中心節點/zookeeper方便快速。”

“基於proxy做轉發意味着屏蔽了下層存儲,完全可以根據前綴/tag/冷熱程度,來把部分甚至大多數數據放在磁盤從而節約成本又保證一致性,這都是有中心節點所帶來的好處。”

5.2 奇虎360:Redis Cluster淺析和Bada對比

詳情請參見原文,關鍵內容摘錄如下:

5.2.1 負載均衡問題

“redis cluster的主備是以節點爲單位,而bada則是以partition爲單位,這樣,同樣是3個節點,1024個partition的情況下,redis cluster的主節點負責整個1024個partition的服務,而兩個從節點則只負責異步備份,導致集羣負載不均,再看bada,將1024個partition的主均分到3個節點中,每個節點各有主備,主對外提供服務,這樣均分了訪問壓力,有效的利用了資源。”

5.2.2 一致性的保證

“redis cluster與bada一樣,最終一致性,讀寫都只請求主節點,當一條寫請求在對應的主節點寫成功後,會立刻返回給客戶端成功,然後主節點通過異步的方式將新的數據同步到對應的從節點,這樣的方式減少了客戶端多個節點寫成功等待的時間,不過在某些情況下會造成寫丟失:

1)當主節點接受一條寫請求,寫入並返回給客戶端成功後不幸宕掉,此時剛纔的寫還未同步給其對應的從節點,而從節點在發現主節點掛掉並重新選主後,新的主節點則永久丟失了之前老的主節點向用戶確認的寫

2)當網絡發生割裂,將集羣分裂成少數派與多數派,這樣在客戶端不知情的情況下,會將寫繼續寫入到少數派中的某些主節點中,而當割裂超過一定時長後,集羣感知到異常,此時少數派中的所有主節點會停止響應所有的寫請求,多數派的其對應的從節點則會發起選舉成爲新的主節點,假設過了一會後割裂恢復,老的主節點發現有更新的主存在,自動變成其從節點,而新的主節點中則會永久丟失掉網絡割裂至集羣感知異常進行切主這個階段老主節點確認的所有寫

相對於redis cluster的永久丟失,bada通過binlog merge有效的解決了這一問題。所有partition的主節點在響應客戶端的寫請求時,都會在本地記錄binlog,binlog實質就是帶有時間戳的KV對。當老主以從節點的身份重新加入集羣時,會觸發binlog merge操作,新主會比較並且合併二者的binlog,這樣就可以將之前丟失掉得寫再補回來。”

5.2.3 請求重定向問題

“bada服務端節點在收到本不該由自己負責的Partition請求後,不會向客戶端返回重定向信息,而是通過代理的方式,直接在集羣內部向正確節點轉發客戶端的請求,並將結果同meta信息再轉發回客戶端。”

“再看multi key操作,redis cluster爲了追求高性能,支持multi key的前提是所有的key必須在同一個節點中, 不過這樣的處理需要交給用戶,對需要進行multi key操作的所有key,在寫入前人爲的加上hash tags。當redis cluster進行resharding的時候,也就是將某些slot從一個節點遷移到另一個節點時,此時的multi key操作可能會失敗,因爲在遷移的slot中的key此時存在於兩個節點。

bada怎麼做呢?用戶如果對multi key操作性能很在乎時,可以採用與redis cluster同樣的方式,給這些key加上hash tags來讓它們落在同一個節點,如果可以接受性能的稍微損耗而解放用戶的處理邏輯,則可以像single key操作一樣,請求任一bada節點,它會代理所有的key請求並將結果返回給用戶。並且在multi key操作在任何時候都可以,即使在進行partition的遷移,bada也會提前進行切主,保證服務的正常提供。”

5.3 芒果TV:Redis服務解決方案

詳情請參見原文,關鍵內容摘錄如下:

芒果TV在Redis Cluster基礎上進行開發,主要增加了兩個組件:

  • 監控管理:以Python爲主要開發框架的Web應用程序Redis-ctl
  • 請求代理:以C++11爲開發語言的輕量數據代理程序cerberus。其作用和優點爲: 
    • 集羣代理程序的自動請求分發/重試機制使得應用不必修改自身代碼或更新Redis庫
    • 代理節點爲所有Redis節點加上統一管理和狀態監測, 可以查閱歷史數據, 或在發生任何問題之後快速響應修復
    • 代理進程的無狀態性使之可在故障後快速恢復, 不影響後端集羣數據完整性

這兩個組件都已開源到GitHub上,大家可以關注一下!


6.Pros & Cons總結

關於Redis Cluster帶來的種種優勢就不說了,在這裏主要是“雞蛋裏挑骨頭”,總結一下現階段集羣功能的欠缺之處和可能的“坑”。

6.1 無中心化架構

6.1.1 Gossip消息

Gossip消息的網絡開銷和時延是決定Redis Cluster能夠線性擴展的因素之一。關於這個問題,在《redis cluster百萬QPS的挑戰》一文中有所提及。

6.1.2 結點粒度備份

此外,Redis Cluster也許是爲了簡化設計採用了Master-Slave複製的數據備份方案,並沒有採取如Cassandra或IMDG等對等分佈式系統中常見的Slot粒度(或叫Partition/Bucket等)的自動冗餘和指派。

這種設計雖然避免比較複雜的分佈式技術,但也帶來了一些問題:

  • Slave完全閒置:即便是讀請求也不會被重定向到Slave結點上,Slave屬於“冷備”
  • 寫壓力無法分攤:Slave閒置導致的另一個問題就是寫壓力也都在Master上

6.2 客戶端的挑戰

由於Redis Cluster的設計,客戶端要擔負起一部分責任:

  • Cluster協議支持:不管Dummy還是Smart模式,都要具備解析Cluster協議的能力
  • 網絡開銷:Dummy客戶端不斷重定向的網絡開銷
  • 連接維護:Smart客戶端對連接到集羣中每個結點Socket的維護
  • 緩存路由表:Smart客戶端Slot路由表的緩存和更新
  • 內存消耗:Smart客戶端上述維護的信息都是有內存消耗的
  • MultiOp有限支持:對於MultiOp,由客戶端通過KeyTag保證所有Key都在同一Slot。而即便如此,遷移時也會導致MultiOp失敗。同理,對Pipeline和Transaction的支持也受限於必須操作同一Slot內的Key。

6.3 Redis實現問題

儘管屬於無中心化架構一類的分佈式系統,但不同產品的細節實現和代碼質量還是有不少差異的,就比如Redis Cluster有些地方的設計看起來就有一些“奇葩”和簡陋:

  • 不能自動發現:無Auto Discovery功能。集羣建立時以及運行中新增結點時,都要通過手動執行MEET命令或redis-trib.rb腳本添加到集羣中
  • 不能自動Resharding:不僅不自動,連Resharding算法都沒有,要自己計算從哪些結點上遷移多少Slot,然後還是得通過redis-trib.rb操作
  • 嚴重依賴外部redis-trib:如上所述,像集羣健康狀況檢查、結點加入、Resharding等等功能全都抽離到一個Ruby腳本中了。還不清楚上面提到的缺失功能未來是要繼續加到這個腳本里還是會集成到集羣結點中?redis-trib也許要變成Codis中Dashboard的角色
  • 無監控管理UI:即便未來加了UI,像遷移進度這種信息在無中心化設計中很難得到
  • 只保證最終一致性:寫Master成功後立即返回,如需強一致性,自行通過WAIT命令實現。但對於“腦裂”問題,目前Redis沒提供網絡恢復後的Merge功能,“腦裂”期間的更新可能丟失

6.4 性能損耗

由於之前手頭沒有空閒的物理機資源,所以只在虛擬機上做了簡單的單機測試,在單獨的一臺壓力機使用YCSB測試框架向虛擬機產生讀寫負載。虛擬機的配置爲8核Intel Xeon CPU [email protected],16GB內存,分別搭建了4結點的單機版Redis和集羣版Redis,測試一下Redis Cluster的性能損耗。由於不是最近做的測試,所以Jedis用的2.6.2版本。注:當然Redis Cluster可以通過多機部署獲得水平擴展帶來的性能提升,這裏只是由於環境有限所以做的簡單單機測試。

由於YCSB本身僅支持Redis單機版,所以需要我們自己增加擴展插件,具體方法請參照《YCSB性能測試工具使用》。通過YCSB產生2000w隨機數據,Value大約100Byte左右。然後通過YCSB測試Read-Mostly(90% Read)和Read-Write-Mixed(50% Read)兩種情況:

  • 數據加載:吞吐量上有約18%的下降。
  • Read-Mostly:吞吐量上有約3.5%~7.9%的下降。
  • Read-Write-Mixed:吞吐量上有約3.3%~5.5%下降。
  • 內存佔用:Jedis客戶端多佔用380MB內存。

6.5 最後的總結

從現階段看來,相比Sentinel或Codis等方案,Redis Cluster的優勢還真是有限,個人覺得最大的優點有兩個:

  1. 官方提供的Slot實現而不用像Codis那樣去改源碼了;
  2. 不用額外的Sentinel集羣或類似的代碼實現了。

同其他分佈式系統,如Cassandra,或內存型的IMDG如Hazelcast和GridGain,除了性能方面外,從功能上Redis Cluster簡直被爆得體無完膚… 看看我之前總結過的GridGain介紹《開源IMDG之GridGain》

  • 結點自動發現和Rebalance
  • 分區粒度的備份
  • 故障時分區角色自動調整
  • 結果聚合(不會重定向客戶端)
  • “腦裂”恢復後的Merge(Hazelcast支持多種合併策略)
  • 多Primary分區寫操作(見Replicated模式)

這些都是Redis Cluster沒有或者要手動完成的。當然這也不足爲奇,因爲這與Redis的設計初衷有關,畢竟作者都已經說了,最核心的設計目標就是性能、水平伸縮和可用性。

 

Redis集羣根據上述說明,可以瞭解到,框架是採用P2P的模式,完全去中心化,數據存儲模塊和分佈式的邏輯模塊耦合在一起。這樣帶來的好處是部署非常簡單,一體式部署,相對Codis而言,沒有太多的其他概念、組件和依賴。但缺點也是比較明顯,譬如分佈式邏輯出現bug,只能回滾重啓整個集羣。

同時,我們通過上述可以瞭解到,Redis集羣對協議進行了較大的修改,對客戶端的交互升級不少,見上述“MOVED重定向”的客戶端實現。由於歷史原因,歷史的應用均使用傳統的Redis API,若業務更換Redis Client,存在不少問題,例如升級工作、數據遷移及測試,所以業內暫未被大規模使用。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章