redis 系列26 Cluster高可用 (1)
一.概述
Redis集群提供了分布式數據庫方案,集群通過分片來進行數據共享,并提供復制和故障轉移功能。在大數據量方面的高可用方案,cluster集群比Sentinel有優勢。但Redis集群并不支持處理多個keys的命令,因為這需要在不同的節點間移動數據,而達不到像Redis那樣的性能,在高負載的情況下可能會導致不可預料的錯誤。學習集群同樣先了解一些原理方面包括:節點、槽指派、命令執行、重新分片,轉向、故障轉移、消息。后面再操作集群演示。關于集群搭建后面會列出實現步驟,也可參考Redis官網的實現步驟:http://www.redis.cn/topics/cluster-tutorial.html
?
1.1 節點
一個Redis集群通常由多個節點(node)組成,開始每個節點都是相互獨立的,需要將獨立的節點連接起來,構成一個包含多節點的集群。連接各節點的工作使用cluster meet命令來完成,格式如下:
cluster meet ip port向一個節點發送該命令,可以讓發送的節點與指定的節點進行握手,握手成功時,指定的節點就會添加到發送節點當前所在的集群中。例如:有三個獨立的節點,端口分別為:7000, 7001,7002。首先使用客戶端連接上節點7000, 通過發送cluster nodes命令可以看到,集群目前只包含7000自己一個節點,通過cluster nodes查看信息如下:
/usr/local/redis/bin[root@hsr bin]# ./redis-cli -c -p 7000 -a 123456127.0.0.1:7000> cluster nodes 142116fa16006f39865ebe604d1580c119fa0fea :7000@17000 myself,master - 0 0 0 connected通過向節點7000發送以下命令,可以將節點7001 添加到7000所在的集群中:
127.0.0.1:7000> cluster meet 127.0.0.1 7001OK繼續向節點7000發送以下命令,可以將節點7002也添加到7000和7001所在的集群中:
127.0.0.1:7000> cluster meet 127.0.0.1 7002OK三個節點握手成功,使三個節點都處于同一個集群中,再次查看集群節點情況,三個節點都connected連接成功:
127.0.0.1:7000> cluster nodes0eed9cc9122d2724365550b70965c2a8e281043d 127.0.0.1:7002@17002 master - 0 1545632759414 2 connectedaeaaeacb8b4d4c4a3bca3c6f52fc4b363e68f083 127.0.0.1:7001@17001 master - 0 1545632758405 0 connected142116fa16006f39865ebe604d1580c119fa0fea 127.0.0.1:7000@17000 myself,master - 0 1545632756000 1 connected? cluster nodes由以下字段組成,表格如下:
| 字段名 | 描述 | 節點7002的字段值 |
| id | 節點 ID,一個40個字符的隨機字符串 | 0eed9cc9122d2724365550b70965c2a8e281043d |
| ip:port | 客戶端應該聯系節點以運行查詢的節點地址 | 127.0.0.1:7002 |
| flags | 逗號列表分隔的標志,myself,master,slave,fail等 | master |
| master | 如果節點是從屬節點,并且主節點已知,則節點ID為主節點,否則為“ - ”字符 | - |
| ping-sent | 毫秒為單位的當前激活的ping發送的unix時間 | 1545632759414 |
| config-epoch | 當前節點的配置時期,每次發生故障切換時,都會創建一個新的,唯一的 | 2> |
| link-state | 用于節點到節點集群總線的鏈路狀態。我們使用此鏈接與節點進行通信 | connected |
| slot | 在connected后面還會顯示槽號范圍 | 分配槽后顯示 |
(1)? 啟動節點
一個節點就是一個運行在集群模式下的Redis服務器,Redis服務器在啟動時會根據cluster-enabled 配置選項是否為yes來決定是否開啟服務器的集群模式。每個節點還是與普通redis服務一樣,具備所有功能比如:支持RDB、AOF持久化、發布與訂閱、保存鍵值對、復制 等等。對于集群模式才會用到的數據,內部保存在cluster.h/clusterState結構中。
(2)?集群數據結構
內部clusterNode結構保存了一個節點的當前狀態,比如節點的創建時間、節點的名字、節點當前的配置紀元、節點的IP、Port等等。每個節點都會使用一個clusterNode結構來記錄自己的狀態,并為集群中的所有其它節點(包括主從)都會創建一個相應的clusterNode結構, 以此來記錄其它節點的狀態。該結構中的屬性不再介紹,詳細請查看"redis設計與實現"書。
(3) cluster meet 命令的實現
上面講到通過cluster meet 命令,可以使節點與指定的節點進行握手形成集群。假設有節點A和B 握手的步驟包括:
(1) 在客戶端向節點A發送一條 cluster meet? B命令時,節點A會為節點B創建一個ClusterNode結構,并將該結構添加到自己的ClusterState.nodes字典中。
(2) 向節點B發送meet后,如果順利節點B將接收到節點A消息,節點B會為節點A創建一個ClusterNode結構, 并將該結構添加到自己的ClusterState.nodes字典中。
(3) 節點B 將向節點A返回一條PONG消息。
(4) 節點A接收B返回的消息,能過這條PONG消息節點A知道節點B已經成功接收到了自己發送的MEET消息。
(5) 節點A將向B返回一條PING消息。
(6) 節點B將接收A的消息,通過這條PING消息節點B知道節點A已經成功接收到了自己返回的PONG消息,握手成功。
之后節點A會將節點B的信息通過Gossip協議傳播給集群中的其他節點,讓其他節點也與節點B進行握手,最終節點B會被集群中所有節點認識。
?
1.2 ?槽指派
? Redis集群通過分片的方式來保存數據庫中的鍵值對:集群的整個 數據庫被分為16384個槽(slot), 數據庫中的每個鍵都屬于這16384 個slot其中一個,集群中的每個節點可以處理0個或最多16384個slot。當數據庫中的16384個slot都有在節點中分配時,此時集群處于上線狀態(OK),相反如果任何一個slot沒有得到分配,那么集群處于下線狀態(fail)。
在節點7000的客戶端通過cluster info可以查看,因為集群中的三個節點都沒有在處理任何slot,所以處于下線狀態。能過cluster info來查看集群為fail狀態,如下所示:
127.0.0.1:7000> cluster infocluster_state:failcluster_slots_assigned:0cluster_slots_ok:0cluster_slots_pfail:0cluster_slots_fail:0cluster_known_nodes:3通向節點發送cluster addslots命令,可以將一個或多個slot指派給某節點負責。例如將slot 0 到5000指派給節點7000負責,手動添加槽時,一定要退出redis客戶端,命令如下:
[root@hsr bin]# ./redis-cli -h 127.0.0.1 -p 7000 -a 123456 cluster addslots {0..5000}OK在登到redis客戶端,查看集群節點的槽分配情況,可以看到7000節點已分配了0-5000的槽范圍:
[root@hsr bin]# ./redis-cli -c -p 7000 -a 123456127.0.0.1:7000> cluster nodes0eed9cc9122d2724365550b70965c2a8e281043d 127.0.0.1:7002@17002 master - 0 1545635637429 2 connectedaeaaeacb8b4d4c4a3bca3c6f52fc4b363e68f083 127.0.0.1:7001@17001 master - 0 1545635638436 0 connected142116fa16006f39865ebe604d1580c119fa0fea 127.0.0.1:7000@17000 myself,master - 0 1545635635000 1 connected 0-5000為了讓7000、7001、7002三個節點所在的集群進入上線狀態,繼續將slot? 5001~10000指派給節點7001。 將slot 10001~16383指派給7002。當三個cluster addslots 命令都執行后,數據庫中的16383個slot都已經指派給了相應的節點,集群進入上線狀態。
[root@hsr bin]# ./redis-cli -h 127.0.0.1 -p 7001 -a 123456 cluster addslots {5001..10000}OK[root@hsr bin]# ./redis-cli -h 127.0.0.1 -p 7002 -a 123456 cluster addslots {10001..16383}OK此時已經進入集群進入上線狀態:如下所示:
127.0.0.1:7000> cluster info cluster_state:okcluster_slots_assigned:16384cluster_slots_ok:16384cluster_slots_pfail:0cluster_slots_fail:0cluster_known_nodes:3cluster_size:2 127.0.0.1:7000> cluster nodesa9e82a7870ac31c221a4d13b28ba9897bb12257c 127.0.0.1:7000@17000 myself,master - 0 1545704528000 0 connected 0-50003b10786d21bbeb66e3517e8d3daa3ee2ce16705e 127.0.0.1:7001@17001 master - 0 1545704529806 1 connected 5001-100007bd0cbd26392d1e98ffe9d46ae153c944d8f398d 127.0.0.1:7002@17002 master - 0 1545704529000 2 connected 10001-16383一個節點除了會將自己負責處理的slot外,還會將自己的slot數組通過消息發送給集群中的其他節點,以此來告知其他節點自己目前處理哪些slot。例如:當節點A? 通過消息從節點B那里接收到節點B的slot數組時,節點A會在自己的ClusterState.nodes字典中查找節點B對應的ClusterState結構,并對結構中的slots數組進行保存或更新。這樣下來集群中的每個節點都會知道數據庫中的16384個slot分別被指派給了集群中的哪些節點。
下圖是集群中各節點的ClusterState.nodes字典,里面記錄了slot與各節點的分配關系:
1.3 ?在集群中執行命令
? 在對數據庫中的16384個slot都進行了指派之后,集群進入上線狀態,這時客戶端就可以向集群中的節點發送數據命令了。當客戶端向節點發送鍵有關的命令時,接收的節點會計算出命令要處理的鍵屬于哪個slot,并檢查這個slot是否派給了節點自己:
(1)如果鍵所在的slot正好就指派給了當前節點,那么節點直接執行這個命令。
(2)如果鍵所在的slot并沒有指派給當前節點,那么節點會向客戶端返回一個moved錯誤,指引客戶端轉向到正確的節點,并再次發送之前想要的執行命令。
自動分配節點和槽號,示例如下所示:
-- 在節點7000寫入一個鍵值對,發現自動分配到7001的14041槽號中。127.0.0.1:7000> set cluster "hello 7000"-> Redirected to slot [14041] located at 127.0.0.1:7001OK--節點7000,讀取該鍵,自動重定向到7001節點中出讀取127.0.0.1:7000> get cluster-> Redirected to slot [14041] located at 127.0.0.1:7001"hello 7000"--節點7000, 修改該鍵,自動重定向到7001節點中出修改127.0.0.1:7000> set cluster "hello 7001"-> Redirected to slot [14041] located at 127.0.0.1:7001OK(1)?計算鍵屬于哪個slot槽
redis 集群共有16384個哈希槽, 每個key通過CRC16校驗后對16384個槽取模來決定放置到哪個節點的槽號。使用cluster keyslot? key命令可以查看一個指定的鍵屬于哪個slot,例如下面讀取cluster鍵,對應槽號為14041。如下所示:
127.0.0.1:7000> cluster keyslot cluster(integer) 14041(2)?moved錯誤(Redirected重定向 )
當節點發現鍵所在的槽并非由自己負責處理的時候,節點就會向客戶端返回一個moved錯誤,指引客戶端轉向到正在負責槽的節點。moved錯誤格式為:moved slot ip :port。 其中slot為鍵所在的槽,而ip和port則是負責處理槽slot的節點的ip地址和端口號。
在集群模式下客戶端接收到moved錯誤時,并不會打印出moved錯誤,而是根據moved錯誤自動進行節點轉向,并打印出轉向日志Redirected to slot 信息。只有在單機模式下,才會打印moved信息,因為單機模式下的redis-cli客戶端不清楚moved錯誤的作用,所以會直接將moved信息打印出來,則不是進行節點轉向。
(3)?節點數據庫的實現
集群節點保存鍵值對以及鍵值對 過期的方式與單機redis服務方式完全相同,節點與單機服務器在數據庫方面的一個區別是:節點只能使用0號數據庫,而單機redis服務則沒有這一限制。
1.4 重新分片
Redis集群的重新分片操作可以將任意數量已經指派給某個節點(源節點)的槽改為指派給另一個節點,并且相關槽所屬的鍵值對也會從源節點被移動到目標節點。重新分片操作可以在線online進行,重新分片過程中,集群不需要下線,并且源節點和目標節點都可以繼續處理命令請求。
例如:在原有節點7000,7001,7002三個節點的集群上,新添加一個節點,端口為7003,然后通過重新分片操作,將原本指派給節點7002的10001~16383的槽,將其中的14042-16383重新分給節點7003。
-- 配置好7003的redis.conf, 啟動7003的redis服務 [root@hsr cluster-test]# pwd/usr/local/redis/cluster-test[root@hsr cluster-test]# ./redis-server ./7003/redis.conf-- 將7003加入集群中127.0.0.1:7000> cluster meet 127.0.0.1 7003OK-- 查看集群信息時,有兩個槽(4808,14041)已經自動分配到了7003節點127.0.0.1:7000> cluster nodes399051ed127fbd1df8a0455858da9c103bf4864a 127.0.0.1:7003@17003 master - 0 1545705387000 3 connected 4808 14041a9e82a7870ac31c221a4d13b28ba9897bb12257c 127.0.0.1:7000@17000 myself,master - 0 1545705386000 0 connected 0-4807 4809-50003b10786d21bbeb66e3517e8d3daa3ee2ce16705e 127.0.0.1:7001@17001 master - 0 1545705387741 1 connected 5001-100007bd0cbd26392d1e98ffe9d46ae153c944d8f398d 127.0.0.1:7002@17002 master - 0 1545705387000 2 connected 10001-14040 14042-16383通過setslot來簡單演示下重新分配槽:
在遷移(目的節點)執行cluster setslot <slot> IMPORTING <node ID>命令,指明需要遷移的slot和遷移源節點。
下面登錄到7003目的節點,使用cluster setslot將參數14042槽號以及所在的源節點ID,導入到當前7003節點中。
127.0.0.1:7003> cluster setslot 14042 importing 7bd0cbd26392d1e98ffe9d46ae153c944d8f398dOK-- 查看cluster nodes ,7003節點信息如下:399051ed127fbd1df8a0455858da9c103bf4864a 127.0.0.1:7003@17003 myself,master - 0 1545707846000 3 connected 4808 14041[14042-<-7bd0cbd26392d1e98ffe9d46ae153c944d8f398d]
取消遷移操作,可在遷移源節點和遷移目的節點上執行cluster setslot <slot> STABLE。下篇介紹使用redis-trib.rb來進行重新分片,redis-trib.rb自動實現了setslot的完整的遷移流程。
posted on 2019-01-06 22:39 NET未來之路 閱讀(...) 評論(...) 編輯 收藏
轉載于:https://www.cnblogs.com/lonelyxmas/p/10230804.html
總結
以上是生活随笔為你收集整理的redis 系列26 Cluster高可用 (1)的全部內容,希望文章能夠幫你解決所遇到的問題。