手動搭建高可用的Redis5.0分片集羣,從理論到實踐,超詳細

前言

前一篇 高可用的Redis主從複製集羣,從理論到實踐 發佈後,反響非常熱烈。所以今天繼續深入講解redis集羣的搭建和相關理論。
xmr
好吧,其實是因爲上篇搭建的主從複製集羣,還有一個實際問題不能解決,那就是容量問題。

一般來說,服務不會部署成單節點,主要是有三個原因

  • 容易出現單點故障,導致服務不可用
  • 單節點處理所有的請求,吞吐量有限
  • 單節點容量有限

前一篇搭建的主從複製集羣可以解決前兩個問題,但是無法解決第三個問題,因爲主從複製集羣中,三個節點中的數據都是一樣的。

基於此,本篇就在前一篇的基礎上,再來改進一下,搭建一個更吊的redis集羣。只關心集羣搭建,而不關心理論的同學可以直接跳到【實驗】部分。

在閱讀本篇之前,強烈建議先閱讀前一篇,本文采用的實驗環境和前一篇一致。並且本文是採用9個虛擬機節點搭建,而不是在一臺虛擬機改了不同的端口號。

問題

在考慮集羣容量的時候,前一篇所搭建的redis主從複製集羣,可以抽象成一個可讀可寫的高可用redis單實例。

本篇所要搭建的集羣,可以抽象成下圖所示。
redis集羣
這種分片(sharding)集羣中,三個分片中的數據已經完全不一樣。不同的數據存在了不同的分片,這樣做的好處非常明顯,可以完美的解決容量的問題。

但是隨之而來的問題也很多,比如:如何確定一個key應該放入哪個分片、增加節點時數據移動、聚合操作怎麼實現等等問題。

這些問題需要一個個去解決,可以說爲了解決一個問題,引入了好幾個新的問題,這也正是分佈式系統的難點之一。

分片

如何決定一個key應該放入哪個分片,實際上就是將key的特徵和分片的特徵綁定。也就是同一個key無論什麼時候通過分片算法來計算,都應該得到同樣的結果。而放入redis,都應該是放在一個固定的分片中(前提是集羣結構沒有改變)。這樣客戶端在請求這個key的時候,就可以根據同樣的分片算法,計算得到key所在的分片。

聰明的你肯定很快就想到了,Java集合框架中就有這樣的場景,那就是HashMapHashMap中的數組默認有16個(slot),相當於16個分片,key是如何確定自己在哪個(slot)的呢。首先計算keyhash值,再把hash值對槽的個數取模,計算結果就是key所在的槽。大致就是這樣hash(key) % length,當然HashMap採用了更高效的方式。

這種方式簡單實用,但是有一個致命的缺點,那就是HashMap擴容的時候,因爲數組長度length變了,原來在第3個槽的數據可能要轉移到第19個槽,這樣就需要移動大量的數據。如果redis分片也採用這種hash + 取模的方式,那麼增加redis節點數的時候,就需要移動大量的數據,同樣,減少redis節點數的時候,也需要移動大量的數據。動輒移動幾個G的數據,對redis來說無疑是致命的。

所以還有一種更吊的分片算法,那就是一致性hash算法。一致性hash算法不僅僅適用於redis的分片,分佈式系統中幾乎所有的需要分片場景,都可以使用一致性hash算法

一致性hash算法

一致性hash算法的核心就是一個邏輯上的hash環,從02^32-1,一共有2^32個遞增的數,現在把首尾相接,就像一條蛇咬住了自己的尾巴。
hash環
大費周章的構造一個邏輯上的hash環有什麼用呢。

答案還是取模
只不過之前的方法是對redis分片數量取模,而有了hash環之後,是對整個hash環取模。也就是對2^32取模。以上文三個節點爲例,對redis服務器的ip地址或者其他特徵,進行一致性hash計算後,可能分佈成如下的樣子
一致性hahs算法
如果一個key經過同樣的hash算法計算之後,肯定會落在環上的某個點。如果剛好落在某個redis分片所在的槽上,那自然不用說,直接就找到了對應的分片。

如果落在各個redis分片所在槽之間呢?

這個key會按照順時針方向尋找(這也是hash環上2^32個數的遞增順序),直到找到第一個redis分片所在槽。比如hash(key1)落在B和C之間,那麼就會順時針找到C。如圖所示,落在AB之間會找B,落在BC之間會找到C,落在CA之間會找到A。這樣就保證每個key都能找到自己對應的那個分片。

一致性hash算法相對於直接對分片數量取模的優勢在於,增加節分片時,不需要移動大量的數據。
一致性hash算法
如圖所示,當我們想集羣中增加分片D時,只需要把CD直接的數據重新定位到分片D中,刪除分片也是一樣。這樣一來集羣就有了很好的擴展性和穩定性。

看似天衣無縫的方案,實際上也隱藏着許多問題。

在向集羣中增加分片D之後,經過hash計算落在CD之間的key會在D分片中查找數據,而這部分數據是存在分片A中的,所以自然找不到。所以這種方案不適合將redis作爲數據庫來使用,而是適合將redis作爲緩存使用。如果緩存數據取不到,會從數據庫加載,然後存到緩存。

但是即使作爲緩存服務器也並不是萬無一失的,由於CD之間的緩存同時失效,大量請求直接落在數據庫上,可能會壓垮數據庫。

這就是常說的緩存雪崩。緩存雪崩,是指在某一個時間段,大量的key集中失效。

爲了解決這個問題,可以每次都取相鄰兩個分片的數據,也就是雖然key落在CD之間,但是同時取分片D和分片A的數據。但是這樣也會無形增加redis的壓力,所以是一個需要權衡的方案。
這個問題會隨着分片數量的增加而減緩,因爲分片數量越多,兩個分片之間的距離就越短,理論上存入的key就越少。

除此之外,還有一個更嚴重的問題,那就是當分片數量很少的時候,可能會造成數據傾斜
redis集羣
如圖所示,集羣中只有三個分片,明顯BC之間的距離最短,CA之間的距離最長。redis中的大量key經過hash運算後,會均勻的分佈在hash環上,這樣就會導致大量的key存在分片A中,而只有很少的key落在分片C中。這就是數據分佈不均勻,產生了傾斜。

爲了解決數據傾斜的問題,一致性hash算法引入了虛擬節點
一致性hash算法
如圖所示Va表示分片A的虛擬節點,原來的定位算法不需要改變,只是多了虛擬節點到真實節點的映射,當key經過計算後,需要存入分片Va時,實際上就會存入分片AVbVc類似。這樣即使在節點數很少的情況下,也不會發生數據傾斜

集羣選型

假設我們已經解決了集羣擴展數據傾斜等問題,redis集羣可以對外提供服務了。由於每一次客戶端請求的key,都可能在不同的分片,所以每個客戶端都必須能夠連接上每個分片。這樣一來必定會導致集羣的連接數非常大,並且會有很多連接一直處於浪費的狀態。
redis集羣
有經驗的同學可能立刻就想到了,利用第三方中間件來進行解耦
引入中間件之後,集羣結構會變成這樣
中間件
針對redis集羣,可選的中間件有以下幾種

感興趣的同學可以自己去實踐。

本篇主要講解redis自帶的分片集羣搭建方式,redis cluster。不需要第三方中間件。

redis cluster

redis cluster不需要第三方中間件解決了集羣擴展問題、數據傾斜問題和連接數問題。

Redis 集羣沒有使用一致性hash算法, 而是引入了哈希槽的概念.

Redis 集羣總共有16384個哈希槽,每個key通過CRC16校驗後對16384取模來決定放置哪個槽。集羣的每個節點負責一部分hash槽,舉個例子,比如當前集羣有3個節點,那麼:

  • 節點 A 包含 0 到 5500號哈希槽.
  • 節點 B 包含5501 到 11000 號哈希槽.
  • 節點 C 包含11001 到 16384號哈希槽.

這種結構很容易添加或者刪除節點,比如如果我想新添加個節點D,我需要從節點 A, B, C中把部分槽到分到D上。如果我想移除節點A,需要將A中的槽移到B和C節點上,然後將沒有任何槽的A節點從集羣中移除即可。由於從一個節點將哈希槽移動到另一個節點並不會停止服務,所以無論添加刪除或者改變某個節點的哈希槽的數量,都不會造成集羣不可用的狀態。

除此之外redis集羣通過內部轉發的方式解決了連接數過多的問題。如圖所示
redis集羣
客戶端可以連接任意一個分片,例如A。請求一個key時,如果經過hash取模運算,發現這個key在分片B上。於是就會把請求轉發給分片B,由B來完成請求響應。其他的分片也具有同樣的功能。這種轉發機制實現的前提就是,每個分片都需要知道自己能處理哪些key,還要知道哪些key應該轉發給哪個分片。也就是每個分片都維護了各個分片和槽的映射關係。

實驗

接下來要搭建的就是含有三個分片的集羣,每個分片都是一主兩從的主從複製集羣,整個架構圖如下
redis集羣
由於節點數比較多,所以操作的時候需要萬分小心,搭建這個集羣可以分爲以下幾步

  • 配置節點信息
  • 集羣握手
  • 分配哈希槽
  • 設置主從
  • 啓動哨兵

接下來開始集羣搭建的詳細過程,在搭建過程中遇到了問題,不妨先看看本文的【踩坑記錄】這小節。

配置節點信息

9個節點的配置信息都一樣,如下所示

bind 0.0.0.0

# 開啓集羣模式
cluster-enabled yes

# 打開集羣內部配置文件,記錄了集羣的信息,內容不需要手動修改
# 按此方法配置,路徑爲:/var/lib/redis/6379/nodes-6379.conf
cluster-config-file nodes-6379.conf

# 超時時間,單位毫秒
cluster-node-timeout 15000

# 集羣中所有的節點都可用,集羣才能對外提供服務,一般改成no
cluster-require-full-coverage no

如果覺得一個個配置太麻煩,可以考慮scp命令,把已經改好的配置文件複製到各個節點。比如把192.168.1.101上的配置文件複製到192.168.1.102

scp -r /etc/redis/6379.conf [email protected]:/etc/redis

配置完成後啓動9個節點。

redis-cli連接任意一個服務,可以查看集羣中節點信息

192.168.1.101:6379> cluster nodes
ce59eb718555f91d34ae5afca4115737864ef202 :6379@16379 myself,master - 0 0 0 connected 935 4998 9057 9189 13120

可以看到現在集羣中只有自己,是因爲集羣之間還沒有進行握手,節點不能感知其他節點的存在。
cluster info命令可以查看自己的信息,可以看到cluster_known_nodes數量爲1,也就是當前節點只知道自己這個節點。

192.168.1.101:6379> cluster info
cluster_state:fail
cluster_slots_assigned:0
cluster_slots_ok:0
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:1
cluster_size:1
cluster_current_epoch:0
cluster_my_epoch:0
cluster_stats_messages_sent:0
cluster_stats_messages_received:0

集羣握手

集羣握手是爲了讓節點與節點之間相互感知,由命令cluster meet完成,先看下該命令的描述

192.168.1.107:6379> help cluster meet

  CLUSTER MEET ip port
  summary: Force a node cluster to handshake with another node
  since: 3.0.0
  group: cluster

redis-cli任意連接一個節點(我這裏是192.168.1.101),用cluster meet命令和其他所有節點握手。只需要一個節點和其他所有節點握手即可,不需要節點之間兩兩握手。

cluster meet 192.168.1.102 6379
cluster meet 192.168.1.103 6379
cluster meet 192.168.1.104 6379
cluster meet 192.168.1.105 6379
cluster meet 192.168.1.106 6379
cluster meet 192.168.1.107 6379
cluster meet 192.168.1.108 6379
cluster meet 192.168.1.109 6379

執行完成後再次查看集羣中節點信息

192.168.1.101:6379> cluster nodes
9ff23b983ce2a875989d171a963e577d22ff890a 192.168.1.105:6379@16379 master - 0 1587793590000 1 connected
21516ba2836947cbeffcc7a654c99158f18a83db 192.168.1.101:6379@16379 myself,master - 0 1587793587000 6 connected
02b488aa2f1b1b816aabcddfca1de2beef59310f 192.168.1.107:6379@16379 master - 0 1587793591000 5 connected
4457a54cc5a37d7b1cd3b2e46ffa6b322d3ffc1f 192.168.1.106:6379@16379 master - 0 1587793589000 4 connected
977ac53d051fbfc9409fbba47014a7beb2f75e9b 192.168.1.103:6379@16379 master - 0 1587793589984 2 connected
99d0b470713c992d8e6b4a3540defa3439f4ef11 192.168.1.102:6379@16379 master - 0 1587793591997 7 connected
7e629a54cf2e606d5b7bf5b716215b594d557c2d 192.168.1.108:6379@16379 master - 0 1587793590991 8 connected
fa5d7df01a63e8b7e06f4b8af899fdf16ee4f0a6 192.168.1.104:6379@16379 master - 0 1587793588976 0 connected
619b55b7cad969f4b2105a2056273c8ee1e21483 192.168.1.109:6379@16379 master - 0 1587793589000 3 connected

可以看到現在192.168.1.101已經感知到了其他節點的存在。即使在其他的節點上執行,也能看到集羣中所有節點信息。

此時的集羣依然是不能對外提供服務的

192.168.1.101:6379> set hello world
(error) CLUSTERDOWN Hash slot not served

從提示也可以看到哈希槽(Hash slot)尚未分配。此時查看集羣信息

192.168.1.101:6379> cluster info
cluster_state:fail
cluster_slots_assigned:5
cluster_slots_ok:5
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:9
cluster_size:1
cluster_current_epoch:1
cluster_my_epoch:1
cluster_stats_messages_ping_sent:169
cluster_stats_messages_pong_sent:159
cluster_stats_messages_meet_sent:8
cluster_stats_messages_update_sent:42
cluster_stats_messages_sent:378
cluster_stats_messages_ping_received:159
cluster_stats_messages_pong_received:177
cluster_stats_messages_received:336

cluster_state 狀態爲fail

分配哈希槽

分配哈希槽由命令cluster addslots完成,該命令描述如下

192.168.1.107:6379> help cluster addslots

  CLUSTER ADDSLOTS slot [slot ...]
  summary: Assign new hash slots to receiving node
  since: 3.0.0
  group: cluster

因爲集羣中只有三個分片,分別是101、104、107,所以只需要給這三個節點分配哈希槽即可。

redis-cli -h 192.168.1.101 -p 6379 cluster addslots {0..5461}
redis-cli -h 192.168.1.104 -p 6379 cluster addslots {5462..10922}
redis-cli -h 192.168.1.107 -p 6379 cluster addslots {10923..16383}

分配完成後,再次查看集羣信息

192.168.1.101:6379> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:9
cluster_size:3
cluster_current_epoch:8
cluster_my_epoch:6
cluster_stats_messages_ping_sent:909
cluster_stats_messages_pong_sent:1124
cluster_stats_messages_meet_sent:18
cluster_stats_messages_update_sent:5
cluster_stats_messages_sent:2056
cluster_stats_messages_ping_received:1123
cluster_stats_messages_pong_received:927
cluster_stats_messages_meet_received:1
cluster_stats_messages_received:2051

可以看到現在的集羣狀態cluster_state變成了ok

設置主從

先看集羣信息

192.168.1.101:6379> cluster nodes
9ff23b983ce2a875989d171a963e577d22ff890a 192.168.1.105:6379@16379 master - 0 1587793786061 1 connected
21516ba2836947cbeffcc7a654c99158f18a83db 192.168.1.101:6379@16379 myself,master - 0 1587793783000 6 connected 0-5461
02b488aa2f1b1b816aabcddfca1de2beef59310f 192.168.1.107:6379@16379 master - 0 1587793785556 5 connected 10923-16383
4457a54cc5a37d7b1cd3b2e46ffa6b322d3ffc1f 192.168.1.106:6379@16379 master - 0 1587793784044 4 connected
977ac53d051fbfc9409fbba47014a7beb2f75e9b 192.168.1.103:6379@16379 master - 0 1587793785000 2 connected
99d0b470713c992d8e6b4a3540defa3439f4ef11 192.168.1.102:6379@16379 master - 0 1587793785000 7 connected
7e629a54cf2e606d5b7bf5b716215b594d557c2d 192.168.1.108:6379@16379 master - 0 1587793782000 8 connected
fa5d7df01a63e8b7e06f4b8af899fdf16ee4f0a6 192.168.1.104:6379@16379 master - 0 1587793782000 0 connected 5462-10922
619b55b7cad969f4b2105a2056273c8ee1e21483 192.168.1.109:6379@16379 master - 0 1587793785052 3 connected

只有101、104、107三個節點分配了槽,所以要把其餘的節點變成他們的slave節點,分配主從關係由命令cluster replicate完成,該命令描述如下

192.168.1.101:6379> help cluster replicate

  CLUSTER REPLICATE node-id
  summary: Reconfigure a node as a replica of the specified master node
  since: 3.0.0
  group: cluster

例如,要把192.168.1.102設置成192.168.1.101slave節點,只需要用redis-cli連上192.168.1.102,執行命令

## 後面的長字符串是192.168.1.101的node-id,也就是cluster nodes信息的第一列
cluster replicate 21516ba2836947cbeffcc7a654c99158f18a83db

其餘的主從關係也依次配置,完成後整個集羣節點信息如下

192.168.1.101:6379> cluster nodes
9ff23b983ce2a875989d171a963e577d22ff890a 192.168.1.105:6379@16379 slave fa5d7df01a63e8b7e06f4b8af899fdf16ee4f0a6 0 1587794070521 1 connected
21516ba2836947cbeffcc7a654c99158f18a83db 192.168.1.101:6379@16379 myself,master - 0 1587794069000 6 connected 0-5461
02b488aa2f1b1b816aabcddfca1de2beef59310f 192.168.1.107:6379@16379 master - 0 1587794071529 5 connected 10923-16383
4457a54cc5a37d7b1cd3b2e46ffa6b322d3ffc1f 192.168.1.106:6379@16379 slave fa5d7df01a63e8b7e06f4b8af899fdf16ee4f0a6 0 1587794070000 4 connected
977ac53d051fbfc9409fbba47014a7beb2f75e9b 192.168.1.103:6379@16379 slave 21516ba2836947cbeffcc7a654c99158f18a83db 0 1587794070000 6 connected
99d0b470713c992d8e6b4a3540defa3439f4ef11 192.168.1.102:6379@16379 slave 21516ba2836947cbeffcc7a654c99158f18a83db 0 1587794071000 7 connected
7e629a54cf2e606d5b7bf5b716215b594d557c2d 192.168.1.108:6379@16379 slave 02b488aa2f1b1b816aabcddfca1de2beef59310f 0 1587794070000 8 connected
fa5d7df01a63e8b7e06f4b8af899fdf16ee4f0a6 192.168.1.104:6379@16379 master - 0 1587794068502 0 connected 5462-10922
619b55b7cad969f4b2105a2056273c8ee1e21483 192.168.1.109:6379@16379 slave 02b488aa2f1b1b816aabcddfca1de2beef59310f 0 1587794068000 5 connected

啓動哨兵

三個哨兵的配置文件一樣,均配置如下信息。

# 三個集羣的名字隨意,只是下面幾個參數需要和此處保持一致
sentinel monitor sicimike-master-1 192.168.1.101 6379 2
sentinel monitor sicimike-master-2 192.168.1.104 6379 2
sentinel monitor sicimike-master-3 192.168.1.107 6379 2

sentinel down-after-milliseconds sicimike-master-1 30000
sentinel down-after-milliseconds sicimike-master-2 30000
sentinel down-after-milliseconds sicimike-master-3 30000

sentinel parallel-syncs sicimike-master-1 1
sentinel parallel-syncs sicimike-master-2 1
sentinel parallel-syncs sicimike-master-3 1

sentinel failover-timeout sicimike-master-1 180000
sentinel failover-timeout sicimike-master-2 180000
sentinel failover-timeout sicimike-master-3 180000

啓動哨兵,三個哨兵啓動成功後可以看到如下日誌

3074:X 25 Apr 2020 16:25:36.504 # Sentinel ID is c094922067b880e4f39abee8cd332df841203e52
3074:X 25 Apr 2020 16:25:36.504 # +monitor master sicimike-master-2 192.168.1.104 6379 quorum 2
3074:X 25 Apr 2020 16:25:36.504 # +monitor master sicimike-master-1 192.168.1.101 6379 quorum 2
3074:X 25 Apr 2020 16:25:36.504 # +monitor master sicimike-master-3 192.168.1.107 6379 quorum 2
3074:X 25 Apr 2020 16:25:36.509 * +slave slave 192.168.1.102:6379 192.168.1.102 6379 @ sicimike-master-1 192.168.1.101 6379
3074:X 25 Apr 2020 16:25:36.514 * +slave slave 192.168.1.103:6379 192.168.1.103 6379 @ sicimike-master-1 192.168.1.101 6379
3074:X 25 Apr 2020 16:25:36.517 * +slave slave 192.168.1.105:6379 192.168.1.105 6379 @ sicimike-master-2 192.168.1.104 6379
3074:X 25 Apr 2020 16:25:36.520 * +slave slave 192.168.1.106:6379 192.168.1.106 6379 @ sicimike-master-2 192.168.1.104 6379
3074:X 25 Apr 2020 16:25:36.522 * +slave slave 192.168.1.108:6379 192.168.1.108 6379 @ sicimike-master-3 192.168.1.107 6379
3074:X 25 Apr 2020 16:25:36.523 * +slave slave 192.168.1.109:6379 192.168.1.109 6379 @ sicimike-master-3 192.168.1.107 6379
3074:X 25 Apr 2020 16:25:37.882 * +sentinel sentinel 07703c8de60e1115552418a8b4305f85e1f4f20d 192.168.1.102 26379 @ sicimike-master-3 192.168.1.107 6379
3074:X 25 Apr 2020 16:25:37.888 * +sentinel sentinel 07703c8de60e1115552418a8b4305f85e1f4f20d 192.168.1.102 26379 @ sicimike-master-1 192.168.1.101 6379
3074:X 25 Apr 2020 16:25:37.938 * +sentinel sentinel 72d596ea3882e763cd3df0a939234385a25409c3 192.168.1.101 26379 @ sicimike-master-3 192.168.1.107 6379
3074:X 25 Apr 2020 16:25:37.949 * +sentinel sentinel 07703c8de60e1115552418a8b4305f85e1f4f20d 192.168.1.102 26379 @ sicimike-master-2 192.168.1.104 6379
3074:X 25 Apr 2020 16:25:38.146 * +sentinel sentinel 72d596ea3882e763cd3df0a939234385a25409c3 192.168.1.101 26379 @ sicimike-master-2 192.168.1.104 6379
3074:X 25 Apr 2020 16:25:38.219 * +sentinel sentinel 72d596ea3882e763cd3df0a939234385a25409c3 192.168.1.101 26379 @ sicimike-master-1 192.168.1.101 6379

可以看到哨兵監控了三套主從複製

至此,整個集羣搭建完成。

操作

普通操作

[root@localhost bin]# redis-cli -h 192.168.1.101 -p 6379
192.168.1.101:6379> set hello world
OK
192.168.1.101:6379> set hello1 world
(error) MOVED 11613 192.168.1.107:6379
192.168.1.101:6379>

根據操作可以看到,有些命令可以寫入成功,有些命令卻提示了error
bqb
根據提示信息可以知道,是因爲hello1這個key落到了分片192.168.1.107上,而連接方式採用的單節點連接,所以會返回錯誤。

集羣環境下,需要以集羣的方式連接

[root@localhost bin]> redis-cli -c -h 192.168.1.101 -p 6379
192.168.1.101:6379> set hello world
OK
192.168.1.101:6379> set hello1 world
-> Redirected to slot [11613] located at 192.168.1.107:6379
OK
192.168.1.107:6379> 

連接的時候加上參數-c,表示以操作集羣的方式連接,當hello1經過計算落到192.168.1.107分片上時,redis-cli會自動跳轉到192.168.1.107上,注意觀察命令提示符中的ip變化。

聚合操作

根據常識可以知道,數據一旦被分片之後,聚合操作就難以實現。因爲需要聚合的數據可能會分佈在不同的分片,爲了解決這個問題,redis集羣實現了Hashtag機制。可以把含有固定字符的key放入同一個分片中。這個用{}表示的固定字符就是Hashtag

[root@localhost bin]# redis-cli -c -h 192.168.1.101 -p 6379
192.168.1.101:6379> set {sicimike}hello world
OK
192.168.1.101:6379> set {sicimike}hello1 world
OK
192.168.1.101:6379> set {sicimike}hello2 world
OK
192.168.1.101:6379> set {sicimike}hello3 world
OK
192.168.1.101:6379> set {sicimike}hello4 world
OK
192.168.1.101:6379> keys *
1) "{sicimike}hello"
2) "{sicimike}hello1"
3) "{sicimike}hello3"
4) "{sicimike}hello2"
5) "{sicimike}hello4"

根據操作可以看到,含有相同tagkey,都放到了同一個分片中。即使切換到其他分片

[root@localhost bin]# redis-cli -c -h 192.168.1.104 -p
192.168.1.104:6379> set {sicimike}hello5 world
-> Redirected to slot [3722] located at 192.168.1.101:6379
OK
192.168.1.101:6379>

可以看到,含有{sicimike}這個tagkey依然被放到了192.168.1.101

可以說redis集羣並不是解決了這個問題,而是規避了這個問題。

reshard

因爲單點故障的問題,通過引入主從複製模型加哨兵就可以解決。所以對於分片集羣,更應該關注的是伸縮性。本集羣中含有三個分片。如果要新增一個分片,應該是怎樣操作呢?

redis-cli --cluster help命令可以查看redis集羣相關的操作命令,其中有一個叫reshard。可以在不重啓redis服務的情況下動態遷移哈希槽。

首先連接一個存活的節點,執行reshard

redis-cli --cluster reshard 192.168.1.101 6379

執行後會有如下提示
redis集羣reshard
執行過程中,會讓你填寫如下信息

  • 要移動多少個槽
  • 移動給哪個分片
  • 從哪(幾)個節點上移動,可以配置多個

執行完成後再次查看集羣信息
redis集羣
可以看到分片101上確實有200個槽移動到了分片107。如果分片107是新增的分片,就可以對外提供服務了。

分片數量減少時也是同樣的操作,先把要移除的分片上的槽reshard給其他分片,再移除即可。

這樣無論是集羣的擴展還是收縮,都變得很容易,真正滿足了實際生產中的要求。

踩坑記錄

  • 部分輸出信息和我不同也不要緊,因爲我搭建失敗了很多次,所以可能會有上一次搭建殘留的信息
  • 不要過早啓動sentinel,如果集羣不能一次性配置成功,可能需要重啓,如果重啓了master可能會導致故障自動轉移
  • 分配哈希槽的過程中可能會遇到(error) ERR Slot xxx is already busy錯誤,這是因爲上一次的配置沒有清理乾淨。用redis-cli連接到redis-server執行flushallcluster reset即可,執行失敗就交換順序執行
  • 設置主從的時候可能會遇到(error) ERR To set a master the node must be empty and without assigned slots.,意思是master想要變成slave,不能含有槽。產生的原因可能是上一次的配置沒有清理乾淨,或者不該分配槽的節點被分配了槽。用redis-cli連接到redis-server執行flushallcluster reset即可,執行失敗就交換順序執行

自動安裝

redis解壓目錄下/root/redis-5.0.8/utils/create-cluster有一個自動搭建集羣的腳本create-cluster。感興趣的同學自己去研究下。

總結

手動搭建集羣可以讓我們更好的理解redis集羣的工作原理。是一個磨鍊性子的活,一次不能成功很正常。搭建成功後,晚餐記得給自己加個雞腿。

參考

  • 《Redis開發與運維》
  • http://redis.cn/topics/cluster-tutorial.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章