Redis叢集
- 1. Redis叢集介紹
- 2. Redis 叢集的資料分片
- 3. Redis 叢集的主從複制模型
- 4. Redis 一緻性保證
- 5. 搭建并使用Redis叢集
- 配置檔案
- 配置叢集
- docker啟動
- 叢集用戶端
- 建立叢集
- 使用
- 6. 叢集指令 -- cluster
- info
- nodes
- replocas
- slaves
- slots
- count-failure-reports
- countkeysinslot
- getkeysinslot
- keyslot
- failover
- delslots
- addslots
- saveconfig
- reset
- set-config-epoch
- meet
- setSlot
- migrating
- importing
- stable
- node
- replicate
- forget
- 7. 叢集指令--redis-cli
- create
- info
- check
- fix
- reshard
- rebalance
- del-node
- add-node
- import
1. Redis叢集介紹
Redis 叢集是一個提供在多個Redis間節點間共享資料的程式集。
Redis叢集并不支援處理多個keys的指令,因為這需要在不同的節點間移動資料,進而達不到像Redis那樣的性能,在高負載的情況下可能會導緻不可預料的錯誤.
Redis 叢集通過分區來提供一定程度的可用性,在實際環境中當某個節點當機或者不可達的情況下繼續處理指令. Redis 叢集的優勢:
- 自動分割資料到不同的節點上。
- 整個叢集的部分節點失敗或者不可達的情況下能夠繼續處理指令。
2. Redis 叢集的資料分片
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節點從叢集中移除即可. 由于從一個節點将哈希槽移動到另一個節點并不會停止服務,是以無論添加删除或者改變某個節點的哈希槽的數量都不會造成叢集不可用的狀态.
3. Redis 叢集的主從複制模型
為了使在部分節點失敗或者大部分節點無法通信的情況下叢集仍然可用,是以叢集使用了主從複制模型,每個節點都會有N-1個複制品.
在我們例子中具有A,B,C三個節點的叢集,在沒有複制模型的情況下,如果節點B失敗了,那麼整個叢集就會以為缺少5501-11000這個範圍的槽而不可用.
然而如果在叢集建立的時候(或者過一段時間)我們為每個節點添加一個從節點A1,B1,C1,那麼整個叢集便有三個master節點和三個slave節點組成,這樣在節點B失敗後,叢集便會選舉B1為新的主節點繼續服務,整個叢集便不會因為槽找不到而不可用了
不過當B和B1 都失敗後,叢集是不可用的.
4. Redis 一緻性保證
Redis 并不能保證資料的強一緻性. 這意味這在實際中叢集在特定的條件下可能會丢失寫操作.
第一個原因是因為叢集是用了異步複制. 寫操作過程:
- 用戶端向主節點B寫入一條指令.
- 主節點B向用戶端回複指令狀态.
- 主節點将寫操作複制給他得從節點 B1, B2 和 B3.
主節點對指令的複制工作發生在傳回指令回複之後, 因為如果每次處理指令請求都需要等待複制操作完成的話, 那麼主節點處理指令請求的速度将極大地降低 —— 我們必須在性能和一緻性之間做出權衡。 注意:Redis 叢集可能會在将來提供同步寫的方法。 Redis 叢集另外一種可能會丢失指令的情況是叢集出現了網絡分區, 并且一個用戶端與至少包括一個主節點在内的少數執行個體被孤立。
舉個例子 假設叢集包含 A 、 B 、 C 、 A1 、 B1 、 C1 六個節點, 其中 A 、B 、C 為主節點, A1 、B1 、C1 為A,B,C的從節點, 還有一個用戶端 Z1 假設叢集中發生網絡分區,那麼叢集可能會分為兩方,大部分的一方包含節點 A 、C 、A1 、B1 和 C1 ,小部分的一方則包含節點 B 和用戶端 Z1 .
Z1仍然能夠向主節點B中寫入, 如果網絡分區發生時間較短,那麼叢集将會繼續正常運作,如果分區的時間足夠讓大部分的一方将B1選舉為新的master,那麼Z1寫入B中得資料便丢失了.
注意, 在網絡分裂出現期間, 用戶端 Z1 可以向主節點 B 發送寫指令的最大時間是有限制的, 這一時間限制稱為節點逾時時間(node timeout), 是 Redis 叢集的一個重要的配置選項.
5. 搭建并使用Redis叢集
搭建叢集的第一件事情我們需要一些運作在 叢集模式的Redis執行個體. 這意味這叢集并不是由一些普通的Redis執行個體組成的,叢集模式需要通過配置啟用,開啟叢集模式後的Redis執行個體便可以使用叢集特有的指令和特性了.
配置檔案
下面是一個最少選項的叢集的配置檔案:
port 7000
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
檔案中的 cluster-enabled 選項用于開執行個體的叢集模式, 而 cluster-conf-file 選項則設定了儲存節點配置檔案的路徑, 預設值為 nodes.conf.節點配置檔案無須人為修改, 它由 Redis 叢集在啟動時建立, 并在有需要時自動進行更新。

在之前的redis的哨兵模式中,沒有實作叢集,今天,在哨兵模式的基礎上繼續。
首先,從redis的github上下載下傳代碼,主要是擷取redis.conf
然後上傳到伺服器中:
然後拷貝兩份配置檔案(防止redis,conf被污染),并給與權限
配置叢集
接下來,修改配置檔案
開啟叢集模式
指定配置檔案
叢集節點逾時時間
這裡有一個比較坑的地方,
cluster-config-file
這裡不配置,因為我們使用docker啟動,在啟動的時候會指定配置檔案的,否則會抛出異常:Unrecoverable error: corrupted cluster config file.
docker啟動
接着,使用docker啟動
docker run -d -p 6379:6379 -v /redis/redis_1.conf:/usr/local/etc/redis/redis.conf --name=master_c_1 redis redis-server /usr/local/etc/redis/redis.conf
接下來建立從節點
叢集用戶端
在redis 5.x之後,就不推薦使用
redis-trib.rb
了,而是使用
redis-cli --cluster
的指令。
但是redis高版本,可以使用create-cluster腳本
檢視其REDAME:
将腳本放到伺服器中(這個腳本是個linux的腳本)
建立叢集
因為目錄結構已經不正确了,是以,我們研究下這個腳本裡面都幹了什麼吧
和我們之前在docker那裡的指令一模一樣。
建立叢集使用docker容器裡面的redis-cli。
docker run -it --rm redis redis-cli --cluster create 10.0.228.117:6379 10.0.228.117:6380 10.0.228.117:6381 10.0.228.117:6382 --cluster-replicas 1
提示6379,也就是master_c_1不是叢集模式啟動的?
明明是叢集模式啟動的啊。
想想,應該是配置不對吧。
應該是ip綁定了,不應該綁定ip.
果真如此,不僅僅綁定了IP,還使用了保護模式。。。。。太粗心了。綁定0.0.0.0表示任何IP都可以通路
重新開機,重試。
至少需要6台機器,我擦
(因為redis叢集使用流言協定進行交換資料,流言協定的裁定需要使用過半原則。是以最少是3台master(1個無法實作流言協定,2個無法實作過半原則),指定1個副本,就是至少6台機器)
在增加一個主節點和一個從節點吧。
重新建立叢集
又沒成功,從輸出來看,應該是容器内無法解析IP,那麼隻能在啟動的時候制動hostname了
我真是太能折騰了。。
docker ps|grep redis|awk '{print $1}'|xargs docker rm
docker run -d --rm --network=host -v /redis/redis_1.conf:/usr/local/etc/redis/redis.conf --hostname=master_c_1 --name=master_c_1 redis redis-server /usr/local/etc/redis/redis.conf --port 6379
docker run -d --rm --network=host -v /redis/redis_2.conf:/usr/local/etc/redis/redis.conf --hostname=master_c_2 --name=master_c_2 redis redis-server /usr/local/etc/redis/redis.conf --port 6380
docker run -d --rm --network=host -v /redis/redis_3.conf:/usr/local/etc/redis/redis.conf --hostname=master_c_3 --name=master_c_3 redis redis-server /usr/local/etc/redis/redis.conf --port 6381
docker run -d --rm --network=host -v /redis/slave_1.conf:/usr/local/etc/redis/redis.conf --hostname=slave_1 --name=slave_1 redis redis-server /usr/local/etc/redis/redis.conf --port 6382
docker run -d --rm --network=host -v /redis/slave_2.conf:/usr/local/etc/redis/redis.conf --hostname=slave_2 --name=slave_2 redis redis-server /usr/local/etc/redis/redis.conf --port 6383
docker run -d --rm --network=host -v /redis/slave_3.conf:/usr/local/etc/redis/redis.conf --hostname=slave_3 --name=slave_3 redis redis-server /usr/local/etc/redis/redis.conf --port 6384
然後建立叢集
終于成功了(都快哭了)
這裡必須使用docker的host網絡模式,因為redis叢集不支援docker的port mapping.
使用這個指令看看吧
使用
嘗試插入不同的資料:
出現(error) MOVED xxxxxx
原因:redis-cli需要以叢集模式啟動
6. 叢集指令 – cluster
info
檢視叢集資訊
cluster info
-
:cluster_state
狀态表示叢集可以正常接受查詢請求。ok
狀态表示,至少有一個哈希槽沒有被綁定(說明有哈希槽沒有被綁定到任意一個節點),或者在錯誤的狀态(節點可以提供服務但是帶有FAIL 标記),或者該節點無法聯系到多數master節點。.fail
-
: 已配置設定到叢集節點的哈希槽數量(不是沒有被綁定的數量)。16384個哈希槽全部被配置設定到叢集節點是叢集正常運作的必要條件.cluster_slots_assigned
-
: 哈希槽狀态不是cluster_slots_ok
和FAIL
的數量.PFAIL
-
: 哈希槽狀态是cluster_slots_pfail
的數量。隻要哈希槽狀态沒有被更新到PFAIL
狀态,這些哈希槽仍然可以被正常處理。FAIL
狀态表示我們目前不能和節點進行互動,但這種狀态隻是臨時的錯誤狀态。PFAIL
-
: 哈希槽狀态是cluster_slots_fail
的數量。如果值不是0,那麼叢集節點将無法提供查詢服務,除非FAIL
被設定為cluster-require-full-coverage
.no
-
: 叢集中節點數量,包括處于cluster_known_nodes
狀态還沒有成為叢集正式成員的節點.握手
-
: 至少包含一個哈希槽且能夠提供服務的master節點數量.cluster_size
-
: 叢集本地cluster_current_epoch
變量的值。這個值在節點故障轉移過程時有用,它總是遞增和唯一的。Current Epoch
-
: 目前正在使用的節點的cluster_my_epoch
值. 這個是關聯在本節點的版本值.Config Epoch
-
: 通過node-to-node二進制總線發送的消息數量.cluster_stats_messages_sent
-
: 通過node-to-node二進制總線接收的消息數量.cluster_stats_messages_received
nodes
檢視節點資訊
cluster nodes
每行組成:
<id> <ip:port> <flags> <master> <ping-sent> <pong-recv> <config-epoch> <link-state> <slot> <slot> ... <slot>
每項的含義如下:
-
: 節點ID,是一個40位元組的随機字元串,這個值在節點啟動的時候建立,并且永遠不會改變(除非使用id
指令)。CLUSTER RESET HARD
-
: 用戶端與節點通信使用的位址.ip:port
-
: 逗号分割的标記位,可能的值有: flags
, myself
, master
, slave
, fail?
, fail
, handshake
, noaddr
noflags
:
各flags的含義 (上面所說資料項3):
-
: 目前連接配接的節點.myself
-
: 節點是master.master
-
: 節點是slave.slave
-
: 節點處于fail?
狀态。 目前節點無法聯系,但邏輯上是可達的 (非PFAIL
狀态).FAIL
-
: 節點處于fail
狀态. 大部分節點都無法與其取得聯系将會将改節點由FAIL
狀态更新至PFAIL
狀态。FAIL
-
: 還未取得信任的節點,目前正在與其進行握手.handshake
-
: 沒有位址的節點(No address known for this node).noaddr
-
: 連個标記都沒有(No flags at all).noflags
-
: 如果節點是slave,并且已知master節點,則這裡列出master節點ID,否則的話這裡列出”-“。master
-
: 最近一次發送ping的時間,這個時間是一個unix毫秒時間戳,0代表沒有發送過.ping-sent
-
: 最近一次收到pong的時間,使用uni`x時間戳表示.pong-recv
-
: 節點的epoch值(or of the current master if the node is a slave)。每當節點發生失敗切換時,都會建立一個新的,獨特的,遞增的epoch。如果多個節點競争同一個哈希槽時,epoch值更高的節點會搶奪到。config-epoch
-
: node-to-node叢集總線使用的連結的狀态,我們使用這個連結與叢集中其他節點進行通信.值可以是 link-state
和 connected
.disconnected
-
: 哈希槽值或者一個哈希槽範圍. 從第9個參數開始,後面最多可能有16384個 數(limit never reached)。代表目前節點可以提供服務的所有哈希槽值。如果隻是一個值,那就是隻有一個槽會被使用。如果是一個範圍,這個值表示為slot
,節點将處理包括起始槽和結束槽在内的所有哈希槽。起始槽-結束槽
replocas
cluster replicas <node-id>
該指令會列出指定主節點的輔助副本節點,輸出格式同指令
CLUSTER NODES
.
若特定節點狀态未知,或在接收指令節點的節點資訊表中,該節點不是主節點,則指令失敗.
slaves
cluster slaves <node-id>
該指令會列出指定master節點所有slave節點,格式同
CLUSTER NODES
當指定節點未知或者根據接收指令的節點的節點資訊表指定節點不是主節點,指令執行錯誤。
slots
cluster slots
CLUSTER SLOTS
指令傳回哈希槽和Redis執行個體映射關系。這個指令對用戶端實作叢集功能非常有用,使用這個指令可以獲得哈希槽與節點(由IP和端口組成)的映射關系,這樣,當用戶端收到(使用者的)調用指令時,可以根據(這個指令)傳回的資訊将指令發送到正确的Redis執行個體.
(嵌套對象)結果數組每一個(節點)資訊:
- 哈希槽起始編号
- 哈希槽結束編号
- 哈希槽對應master節點,節點使用IP/Port表示
- master節點的第一個副本
每個結果包含該哈希槽範圍的所有存活的副本,沒有存活的副本不會傳回.
(每個節點資訊的)第三個(行)對象一定是IP/Port形式的master節點。之後的所有IP/Port都是該哈希槽範圍的Redis副本。
如果一個叢集執行個體中的哈希槽不是連續的(例如1-400,900,1800-6000),那麼哈希槽對應的master和replica副本在這些不同的哈希槽範圍會出現多次。
count-failure-reports
cluster count-filure-reports <node-id>
這個指令傳回指定節點的故障報告個數,故障報告是Redis Cluster用來使節點的
PFAIL
狀态(這意味着節點不可達)晉升到
FAIL
狀态而的方式,這意味着叢集中大多數的主節點在一個事件視窗内同意節點不可達。
因為redis使用流言模式,是以需要記錄報告的異常次數。
- 一個節點會用
标記一個不可達時間超過配置中的逾時時間的節點,這個逾時時間是 Redis Cluster 配置中的基本選項。PFAIL
- 處于
狀态的節點會将狀态資訊提供在心跳包的流言(gossip)部分。PFAIL
- 每當一個節點處理來自其他節點的流言(gossip)包時,該節點會建立故障報告(如果需要會重新整理TTL),并且會記住發送消息包的節點所認為處于
狀态下的其他節點。PFAIL
- 每個故障報告的生存時間是節點逾時時間的兩倍。
- 如果在一段給定的事件内,一個節點被另一個節點标記為
狀态,并且在相同的時間内收到了其他大多數主節點關于該節點的故障報告(如果該節點是主節點包括它自己),那麼該節點的故障狀态會從PFAIL
晉升為PFAIL
,并且會廣播一個消息,強制所有可達的節點将該節點标記為FAIL
。FAIL
countkeysinslot
cluster countkeysinslot slot
count keys in sloot
查詢指定slot中key的數量
這個指令和keyslot配合使用。
如果指定的hash slot不在用戶端連接配接的節點上,傳回0.
getkeysinslot
擷取指定hash slot中全部的key.
cluster getkeysinslot slot count
keyslot
cluster keyslot key
查詢指定key的hash slot
可以和countkeysinslot配合使用。
failover
cluster failover [Force|Takeover]
該指令隻能在群集slave節點執行,讓slave節點進行一次人工故障切換。
人工故障切換是預期的操作,而非發生了真正的故障,目的是以一種安全的方式(資料無丢失)将目前master節點和其中一個slave節點(執行cluster-failover的節點)交換角色。
流程如下:
- 目前slave節點告知其master節點停止處理來自用戶端的請求
- master 節點将目前replication offset回複給該slave節點
- 該slave節點在未應用至replication offset之前不做任何操作,以保證master傳來的資料均被處理。
- 該slave 節點進行故障轉移,從群集中大多數的master節點擷取epoch,然後廣播自己的最新配置
- 原master節點收到配置更新:解除用戶端的通路阻塞,回複重定向資訊,以便用戶端可以和新master通信。
當該slave節點(将切換為新master節點)處理完來自master的所有複制,用戶端的通路将會自動由原master節點切換至新master節點.
-
FORCE 選項:slave節點不和master協商(master也許已不可達),從上如4步開始進行故障切換。當master已不可用,而我們想要做人工故障轉移時,該選項很有用。
但是,即使使用FORCE選項,我們依然需要群集中大多數master節點有效,以便對這次切換進行驗證,同時為将成為新master的salve節點生成新的配置epoch。
-
TAKEOVER 選項: 忽略群集一緻驗證的的人工故障切換
有時會有這種情況,群集中master節點不夠,我們想在未和群集中其餘master節點驗證的情況下進行故障切換。 實際用途舉例:群集中主節點和從節點在不同的資料中心,當所有主節點down掉或被網絡分區隔離,需要用該參數将slave節點 批量切換為master節點。
選項 TAKEOVER 實作了FORCE的所有功能,同時為了能夠進行故障切換放棄群集驗證。當slave節點收到指令
CLUSTER FAILOVER TAKEOVER
會做如下操作:
- 獨自生成新的
,若本地配置epoch非最大的,則取目前有效epoch值中的最大值并自增作為新的配置epochconfigEpoch
- 将原master節點管理的所有哈希槽配置設定給自己,同時盡快分發最新的配置給所有目前可達節點,以及後續恢複的故障節點,期望最終配置分發至所有節點
注意:TAKEOVER 違反Redis群集最新-故障轉移-有效 原則,因為slave節點産生的配置epoch 會讓正常産生的的配置epoch無效
- 使用TAKEOVER産生的配置epoch 無法保證時最大值,因為我們是在少數節點見生成epoch,并且沒有使用資訊互動來保證新生成的epoch值最大。
- 如果新生成的配置epoch 恰巧和其他執行個體生成的發生沖突(epoch相同),最終我們生成的配置epoch或者其他執行個體生成的epoch,會通過使用配置epoch沖突解決算法舍棄掉其中一個。
因為這個原因,選擇TAKEOVER需小心使用.
delslots
cluster delslots <hash-slots>
在Redis Cluster中,每個節點都會知道哪些主節點正在負責哪些特定的哈希槽
DELSLOTS
指令使一個特定的Redis Cluster節點去忘記一個主節點正在負責的哈希槽,這些哈希槽通過參數指定。
說白了就是使指定的hash slot從叢集中解綁
在已經接收到
DELSLOTS
指令的節點環境中,并且是以已經去除了指定哈希槽的關聯,我們認為這些哈希槽是未綁定的 。請注意,當一個節點還沒有被配置去負責他們(可以通過
ADDSLOTS
完成槽的配置設定)并且如果該節點沒有收到關于誰擁有這些哈希槽的消息時(節點通過心跳包或者更新包擷取消息),這些未綁定的哈希槽是自然而然本來就存在的。
如果一個節點認為一些哈希槽是未綁定的,但是從其他節點接收到一個心跳包,得知這些哈希槽已經被其他節點負責,那麼會立即确立其關聯關系。而且,如果接收到一個心跳包或更新包的配置紀元比目前節點的大,那麼會重建立立關聯。
- 指令隻在參數指定的哈希槽已經和某些節點關聯時有效。
- 如果同一個哈希槽被指定多次,該指令會失敗。
- 指令執行的副作用是,因為不在負責哈希槽,節點可能會進入下線狀态。
10000這個hash slot已經從叢集中解綁了.
請注意,如果解綁的hash slot在一定時間内沒有被重新配置設定,那麼會因叢集間心跳包傳輸,目前節點重新獲得移除的hash slot.
此指令和addslots配合使用,實作人工配置設定hash slot.
addslots
cluster addslots <hash-slots>
指定指令接收節點,配置設定指定的slot集合
這個指令是用于修改某個節點上的叢集配置。具體的說它把一組hash slots配置設定給接收指令的節點。 如果指令執行成功,節點将指定的hash slots映射到自身,節點将獲得指定的hash slots,同時開始向叢集廣播新的配置。
需要注意:
- 該指令隻有當所有指定的slots在接收指令的節點上還沒有配置設定得的情況下生效。節點将 拒絕接納已經配置設定到其他節點的slots(包括它自己的)。
- 同一個slot被指定多次的情況下指令會失敗。
- 執行這個指令有一個副作用,如果slot作為其中一個參數設定為
,一旦節點向自己配置設定該slot(以前未綁定)這個狀态将會被清除。importing
saveconfig
cluster saveconfig
強制儲存配置
nodes.conf
至磁盤。
該指令主要用于
nodes.conf
節點狀态檔案丢失或被删除的情況下重新生成檔案。當使用
CLUSTER
指令 對群集做日常維護時,該指令可以用于保證新生成的配置資訊會被持久化到磁盤。當然,這類指令應該設定定時調用 将配置資訊持久化到磁盤,保證系統重新開機之後狀态資訊還是正确的。
reset
cluster reset [HARD|SOFT]
根據reset的類型配置hard或者soft ,Reset 一個Redis群集節點可以選擇十分極端或極端的方式。 注意該指令在主節點hold住一個或多個keys的時候無效,在這種情況下,如果要徹底reset一個master, 需要将它的所有key先移除,如先使用
FLUSHALL
,在使用
CLUSTER RESET
節點上的效果如下:
- 群集中的節點都被忽略
- 所有已分派/打開的槽會被reset,以便slots-to-nodes對應關系被完全清除
- 如果節點是slave,它會被切換為(空)master。它的資料集已被清空,是以最後也會變成一個空master。
- Hard reset only:生成新的節點ID
- 變量
和currentEpoch
被設定為0configEpoch
- 新配置被持久化到節點磁盤上的群集配置資訊檔案中
當需要為一個新的或不同的群集提供一個新的群集節點是可使用該指令,同時它也在Redis群集測試架構中被廣泛使用,它用于 在每個新的測試單元啟動是初始化群集狀态。
如果reset類型沒有指定,使用預設值soft
hard:
soft
沒看出這兩個有什麼差別。
reset會清楚master中的資料:
因為reset改變了id,是以,在其他redis節點中,原有的兩個被辨別為未知的了。(流言開始)
如果過一段時間,流言得到确認,就會移除未知節點。
set-config-epoch
cluster set-config-epoch <config-epoch>
該指令為一個全新的節點設定指定的config epoch,僅在如下情況下有效:
- 節點的節點資訊表為空
- 節點的目前config epoch為0
這些先決條件是需要的,因為通常情況下,人工修改一個節點的配置epoch是不安全的,我們想保證一點:在 擷取哈希槽的所有權時,擁有更高配置epoch值的節點獲勝。
但是該規則也有一個例外,在群集建立的時候,Redis群集配置epoch沖突解決算法會解決 群集啟動時新的節點配置成相同配置epoch的問題,但是這個處理過程很慢,為了保證不管發生任何情況,都不會有兩個節點擁有相同的配置epoch。
是以,當一個新群集建立的時候,使用指令
CONFIG SET-CONFIG-EPOCH
為每個一個節點分派漸進的配置epoch,然後再加入群集。
meet
cluster meet <ip> <port>
CLUSTER MEET
指令被用來連接配接不同的開啟叢集支援的 Redis 節點,以進入工作叢集。
基本的思想是每個節點預設都是互相不信任的,并且被認為是未知的節點,以便萬一因為系統管理錯誤或位址被修改,而不太可能将多個不同的叢集節點混成一個叢集。
請注意,Redis Cluster 需要形成一個完整的網絡(每個節點都連接配接着其他每個節點),但是為了建立一個叢集,不需要發送形成網絡所需的所有
CLUSTER MEET
指令。發送
CLUSTER MEET
消息以便每個節點能夠到達其他每個節點隻需通過一條已知的節點鍊就足夠了。由于在心跳包中會交換 gossip 資訊,将會建立節點間缺失的連結。
是以,如果我們通過
CLUSTER MEET
連結節點 A 和節點 B ,并且節點 B 和 C 有連結,那麼節點 A 和節點 C 會發現他們握手和建立連結的方法。
實作細節:MEET 和 PING 包**
當一個給定的節點接收到一個
CLUSTER MEET
消息時,指令中指定的節點仍然不知道我們發送了指令,是以為了使節點強制将接收指令的節點将它作為信任的節點接受它,它會發送
MEET
包而不是
PING
包。兩個消息包有相同的格式,但是
MEET
強制使接收消息包的節點确認發送消息包的節點為可信任的。
我們新增一個redis執行個體,然後用meet加入叢集:
然後加入
setSlot
-
子指令:将一個哈希槽設定為migrating 狀态(導出)MIGRATING
-
子指令:将一個哈希槽設定為importing 狀态(倒入)IMPORTING
-
子指令:從哈希槽中清除導入和遷移狀态STABLE
-
子指令:将一個哈希槽綁定到另一個不同的節點NODE
migrating
cluster setslot <slot> migrating <dest-node-id>
該子指令将一個槽設定為migrating狀态.為了可以将一個哈希槽設定成這種狀态,收到指令的節點必須是該哈希槽的所有者,否則報錯
importing
cluster setslot <slot> importing <source-node-id>
該子指令是
MIGRATING
的反向操作,将keys從指定源節點導入目标節點。該指令僅能在目标節點不是指定槽的所有者時生效。
stable
cluster setslot <slot> stable
該子指令僅用于清理槽中遷移中/導入中的狀态。它主要用于修複群集在使用·redis-trip fix· 卡在一個錯誤狀态的問題。
node
cluster setslot <slot> node <node-id>
子指令
NODE
使用方法最複雜,它後接指定節點的哈希槽,該指令僅在特定情況下有效,并且不同的槽狀态會有不同的效果.
如果slot是migrating,那麼該操作是将指令接收者的slot配置設定出去
如果slot是importing,那麼該操作是将其他slot配置設定給指令接受者
replicate
cluster replcate <node-id>
該指令重新配置一個節點成為指定master的salve節點。 如果收到指令的節點是一個empty master,那麼該節點的角色将由master切換為slave。
一旦一個節點變成另一個master節點的slave,無需通知群集内其他節點這一變化:節點間交換 資訊的心跳包會自動将新的配置資訊分發至所有節點。
我們在新增一個節點:
此時6386是master,我們要讓6386成為6385的slave
得益于redis叢集的通信,其他節點也得到了相同的資訊
forget
cluster forget <node-id>
該指令可以從收到指令的Redis群集節點的節點資訊清單中移除指定ID的節點。 換句話說,從收到指令的Redis群集節點的nodes table中删除指定節點。
該指令不是将待删除節點的資訊簡單從内部配置中簡單删除,它同時實作了禁止清單功能:不允許已删除 的節點再次被添加進來,否則已删除節點會因為處理其他節點心跳包中的gossip section時被再次添加。
指令
CLUSTER FORGET
為每個節點實作了包含逾時時間的禁止清單
是以我們指令實際的執行情況如下:
- 從收到指令節點的節點資訊清單中删除待删除節點的節點資訊。
- 已删除的節點的節點ID被加入禁止清單,保留1分鐘
- 收到指令的節點,在處理從其他節點發送過來的gossip sections 會跳過所有在禁止清單中的節點。
這樣,我們就有60秒的時間視窗來通知群集中的所有節點,我們想要删除某個節點。
7. 叢集指令–redis-cli
create
redis-cli --cluster create <ip1:port1> ... --cluster-replicas <args>
建立叢集
見第5小節。。
info
redis-cli --cluster info <叢集内任一ip:port>
擷取叢集資訊
check
redis-cli --cluster check <叢集内任一ip:port>
檢查叢集
報錯提示我們的叢集内每一個節點的配置檔案不同。
還記得我們啟動的指令嗎:
docker run -d --rm --network=host -v /redis/redis_cluster.conf:/usr/local/etc/redis/redis.conf --hostname=master_c_4 --name=master_c_4 redis redis-server /usr/local/etc/redis/redis.conf --port 6385
我們傳入了一個配置檔案,但是我們在配置檔案中指定的配置檔案是
nodes.conf
我們将這個配置定為同樣的配置:
建立每個節點的nodes.conf的目錄
然後重新建立全部的叢集節點:
docker ps|grep redis|awk '{print $1}'|xargs docker stop
docker run -d --rm --network=host -v /redis/master_c_1/:/redis/cluster/ -v /redis/redis_cluster.conf:/usr/local/etc/redis/redis.conf --hostname=master_c_1 --name=master_c_1 redis redis-server /usr/local/etc/redis/redis.conf --port 6379
docker run -d --rm --network=host -v /redis/master_c_2/:/redis/cluster/ -v /redis/redis_cluster.conf:/usr/local/etc/redis/redis.conf --hostname=master_c_2 --name=master_c_2 redis redis-server /usr/local/etc/redis/redis.conf --port 6380
docker run -d --rm --network=host -v /redis/master_c_3/:/redis/cluster/ -v /redis/redis_cluster.conf:/usr/local/etc/redis/redis.conf --hostname=master_c_3 --name=master_c_3 redis redis-server /usr/local/etc/redis/redis.conf --port 6381
docker run -d --rm --network=host -v /redis/slave_1/:/redis/cluster/ -v /redis/redis_cluster.conf:/usr/local/etc/redis/redis.conf --hostname=slave_1 --name=slave_1 redis redis-server /usr/local/etc/redis/redis.conf --port 6382
docker run -d --rm --network=host -v /redis/slave_2/:/redis/cluster/ -v /redis/redis_cluster.conf:/usr/local/etc/redis/redis.conf --hostname=slave_2 --name=slave_2 redis redis-server /usr/local/etc/redis/redis.conf --port 6383
docker run -d --rm --network=host -v /redis/slave_3/:/redis/cluster/ -v /redis/redis_cluster.conf:/usr/local/etc/redis/redis.conf --hostname=slave_3 --name=slave_3 redis redis-server /usr/local/etc/redis/redis.conf --port 6384
docker run -d --rm --network=host -v /redis/master_c_4/:/redis/cluster/ -v /redis/redis_cluster.conf:/usr/local/etc/redis/redis.conf --hostname=master_c_4 --name=master_c_4 redis redis-server /usr/local/etc/redis/redis.conf --port 6385
docker run -d --rm --network=host -v /redis/slave_4/:/redis/cluster/ -v /redis/redis_cluster.conf:/usr/local/etc/redis/redis.conf --hostname=slave_4 --name=slave_4 redis redis-server /usr/local/etc/redis/redis.conf --port 6386
建立叢集:
檢測:
fix
redis-cli --cluster fix <叢集内任一ip:port>
檢測出錯了,可以使用這個指令處理
修複的結果就是将全部的slot配置設定給第一個機器
reshard
redis-cli --cluster reshared <叢集内任一ip:port>
可選參數:
--cluster-from
--cluster-to
--cluster-slots
--cluster-yes
--cluster-timeout
--cluster-pipeline
--cluster-replace
[root@master1 ~]# redis-cli --cluster reshard 192.168.100.41:6379
How many slots do you want to move (from 1 to 16384)? 4096 '//要遷移多少個槽'
What is the receiving node ID? 99521b7fd126b694bcb9a22ffa5a490f31f66543 '//遷移到哪個節點,資料節點id'
Please enter all the source node IDs.
Type 'all' to use all the nodes as source nodes for the hash slots.
Type 'done' once you entered all the source nodes IDs.
'//要求輸入源節點的id,這裡因為原本有三個節點,輸入done表示結束'
Source node #1: 7f112f82bcf28a5d0627ea81b48cb76f4ea8605d
Source node #2: df195a34a91d756157a0fda7c71e99d5bd8fad09
Source node #3: a233a23541f431107fed79908318394d8bb30b51
Source node #4: done
'//最後會有一個遷移方案,輸入yes表示同意,遷移開始。輸入no表示不同意,重新設定遷移方案。'
'//确認是否遷移成功'
[root@master1 ~]# redis-cli -h 192.168.100.41 -p 6379
192.168.100.41:6379> cluster nodes
...省略内容
遷移slot
發現隻有一個機器,不夠用,現在每一個機器都是隔離的:
我們将其連接配接起來
我們設定主從節點
遷移slot
rebalance
redis-cli --cluster rebalance <叢集内任一ip:port>
自動平衡hash slot
del-node
redis-cli --cluster del-node <叢集内ip:port> <node>
删除節點
add-node
redis-cli --cluster add-node <叢集外的ip:port> <叢集内任一ip:port>
不知道為什麼
--cluster-master-id
沒生效
import
redis-cli --cluster import <叢集外ip:port>
将redis執行個體倒入叢集(倒入資料)
[ERR] The source node should not be a cluster node.
因為6386也是一個叢集節點,
cluster-enabled=true
建立一個redis執行個體,使用預設配置。