redis叢集的搭建與管理
一、redis叢集的搭建
1、redis叢集中的資料分佈
(1)資料分割槽
分散式資料庫首先要解決把整個資料集按照分割槽規則對映到多個節點,每個節點負責整體資料的一個子集,常見的分割槽規則有雜湊分割槽和順序分割槽兩種,常見的雜湊分割槽規則有節點取餘分割槽、一致性雜湊分割槽和虛擬槽分割槽。Redis cluster使用的為雜湊分割槽中的虛擬操分割槽。
(2)redis cluster資料分割槽
Redis cluster採用虛擬槽分割槽,所有鍵根據雜湊函式對映到0~16383整數槽內,計算公式為:slot=CRC16(KEY)&16383,每個節點負責維護一部分槽以及槽所對映的鍵值資料。
(3)redis 虛擬槽分割槽的特點
1)解耦資料和節點之間的關係,簡化了節點擴容和收縮難度
2)節點自身維護槽的對映關係,不需要客戶端或者代理服務維護槽分割槽源資料
3)支援節點、槽、鍵之間的對映查詢,使用者線上路由,資料伸縮等場景。
(4)redis cluster缺點
1)key批量操作支援有限
2)key事務的操作支援有限,同理只支援key在同一節點上的事務操作
3)key作為資料分割槽的最小粒度,因此不能將一個大的鍵值物件如hash、list等對映到不同的節點
4)不支援多資料庫空間,叢集模式下只能使用一個數據庫空間。
5)複製結構只支援一層,不支援巢狀樹狀複製結構。
2、叢集的搭建
(1)準備節點
Redis cluster節點數量至少為6個才能保證完成高可用性叢集,每個節點需要配置”cluster-enabled yes”。由於在每臺機器上起了兩個redis節點,需要為每個節點統一規劃目錄,節點的準備如下:
角色 |
IP地址 |
埠 |
記憶體大小 |
備註 |
Redis master |
192.168.16.128 |
6379 |
16g |
主節點 |
Redis master |
192.168.16.129 |
6379 |
16g |
主節點 |
Redis master |
192.168.16.130 |
6379 |
16g |
主節點 |
Redis slave |
192.168.16.128 |
6380 |
16g |
16.129從節點 |
Redis slaver |
192.168.16.129 |
6380 |
16g |
16.130從節點 |
Redis slaver |
192.168.16.130 |
6380 |
16g |
16.128從節點 |
(2)節點的配置啟動
Redis cluster相關的主要配置如下(各個節點根據節點的具體需求進行配置):
# 埠
port 6379
# 開啟叢集模式
cluster-enabled yes
# 叢集的內部配置檔案
cluster-config-file nodes-6379.conf
# 節點的超時時間,單位毫秒
cluster-node-timeout 15000
# 資料存放目錄,不存在時需要建立,不然不能啟動
dir "/var/lib/redis/6379"
# 日誌存放檔案
logfile "/var/log/redis/redis_6379.log"
# 執行時產生的pid檔案存放目錄
pidfile "/var/run/redis_6380.pid"
redis配置完成後,需要啟動所有的節點,由於是一個機器上部署了兩個redis例項,佔用了不同的埠;啟動時通過命令”redis-server /etc/redis/6379/6379.conf”來啟動
# 啟動192.168.16.128上的兩個redis
]# redis-server /etc/redis/6380/6380.conf
]# redis-server /etc/redis/6379/6379.conf
# 檢視埠有沒有被監聽
]# ss -tanl | egrep "6379|6380"
LISTEN 0 128 *:16379 *:*
LISTEN 0 128 *:16380 *:*
LISTEN 0 128 *:6379 *:*
LISTEN 0 128 *:6380 *:*
Redis cluster啟動成功後,如果沒有cluster的配置檔案則會自動生成一份叢集的配置檔案,存放在redis資料目錄下,當叢集內節點資訊發生變化時,節點會自動儲存叢集狀態到配置檔案中。節點叢集配置檔案中最最要的為節點的ID,當各個節點啟動成功後,每個節點彼此不知道其他節點的存在,需要通過”握手”讓6個節點建立聯絡組成一個叢集。
(3)節點的握手
節點握手是指一批執行在叢集模式下的節點通過Gossip協議彼此通訊,達到感知對方的過程。節點握手時叢集彼此通訊的第一步,只需要在叢集內的任意節點上執行”cluster meet {ip} {port}”命令加入新節點,握手訊息會通過訊息在叢集內傳播,這樣其他節點會自動發現新節點併發起握手流程。
# 執行meet命令讓所有的節點互相握手
127.0.0.1:6379> cluster meet 192.168.16.128 6379
OK
127.0.0.1:6379> cluster meet 192.168.16.128 6380
OK
127.0.0.1:6379> cluster meet 192.168.16.129 6379
OK
127.0.0.1:6379> cluster meet 192.168.16.129 6380
OK
127.0.0.1:6379> cluster meet 192.168.16.130 6379
OK
127.0.0.1:6379> cluster meet 192.168.16.130 6380
OK
# 檢視叢集的狀態
127.0.0.1:6379> cluster nodes
d33ca65e915d9c0b2a84c288b3a492df0705fa24 192.168.16.130:6380 master - 0 1535907782856 5 connected
faeed9b174f5506ca205cd5864806f0716c969c2 192.168.16.129:6379 master - 0 1535907781336 0 connected
99a04a3a54fea878ca0bda40c0053e7f612a4941 192.168.16.129:6380 master - 0 1535907783362 3 connected
ad864130ea5472462b3406563fdf14386465f7da 192.168.16.128:6379 myself,master - 0 0 2 connected
174d5e01ff5fdaa5d10646483780afb34dd6b12b 192.168.16.130:6379 master - 0 1535907784374 4 connected
6a38614369457a50da47a6572d22e8c0befb004d 192.168.16.128:6380 master - 0 1535907782346 1 connected
節點握手後集群還不能正常工作,只有將槽分配到對應的節點後集群才能正常工作。
(4)分配槽
節點握手完成後,需要為節點分配槽,redis 叢集把所有的資料對映到16384個槽中,刻個key會對映一個固定的槽,只有當節點分配了槽,才能相應和槽關聯的命令,為節點分配槽時通過”cluster addslots”命令完成的。
# 為各主節點分配槽
]# redis-cli -h 192.168.16.128 -p 6379 cluster addslots {0..5461}
OK
]# redis-cli -h 192.168.16.129 -p 6379 cluster addslots {5462..10992}
OK
]# redis-cli -h 192.168.16.130 -p 6379 cluster addslots {10993..16282}
OK
# 分配完槽在檢視節點狀態時,各節點獲取了相應的槽,叢集進入線上狀態
cluster nodes
d33ca65e915d9c0b2a84c288b3a492df0705fa24 192.168.16.133:6380 master - 0 1535908778762 5 connected
faeed9b174f5506ca205cd5864806f0716c969c2 192.168.16.129:6379 master - 0 1535908779266 0 connected 5462-10992
99a04a3a54fea878ca0bda40c0053e7f612a4941 192.168.16.129:6380 master - 0 1535908777752 3 connected
ad864130ea5472462b3406563fdf14386465f7da 192.168.16.128:6379 myself,master - 0 0 2 connected 0-5461
174d5e01ff5fdaa5d10646483780afb34dd6b12b 192.168.16.133:6379 master - 0 1535908776737 4 connected 10993-16282
6a38614369457a50da47a6572d22e8c0befb004d 192.168.16.128:6380 master - 0 1535908779774 1 connected
再為主節點分配完槽後,還需要使用”cluster replicate {nodeId}”命令為每一個主節點分配一個從節點,該命令必須要在對應的從節點上執行,{nodId}為要複製的主節點的id。
# 讓192.168.16.128:6380成為192.168.16.129:6279的從節點
192.168.16.128:6380> cluster replicate faeed9b174f5506ca205cd5864806f0716c969c2
OK
# 讓192.168.16.129:6380成為192.168.16.130:6279的從節點
192.168.16.129:6380> cluster replicate 174d5e01ff5fdaa5d10646483780afb34dd6b12b
OK
# 讓192.168.16.130:6380成為192.168.16.128:6279的從節點
192.168.16.130:6380> cluster replicate ad864130ea5472462b3406563fdf14386465f7da
OK
# 再次檢視節點狀態時各主節點都有了從節點
127.0.0.1:6380> cluster nodes
6a38614369457a50da47a6572d22e8c0befb004d 192.168.16.128:6380 myself,slave faeed9b174f5506ca205cd5864806f0716c969c2 0 0 1 connected
faeed9b174f5506ca205cd5864806f0716c969c2 192.168.16.129:6379 master - 0 1535909496378 0 connected 5462-10992
99a04a3a54fea878ca0bda40c0053e7f612a4941 192.168.16.129:6380 slave 174d5e01ff5fdaa5d10646483780afb34dd6b12b 0 1535909495367 4 connected
174d5e01ff5fdaa5d10646483780afb34dd6b12b 192.168.16.133:6379 master - 0 1535909494358 4 connected 10993-16282
d33ca65e915d9c0b2a84c288b3a492df0705fa24 192.168.16.133:6380 slave ad864130ea5472462b3406563fdf14386465f7da 0 1535909493348 5 connected
ad864130ea5472462b3406563fdf14386465f7da 192.168.16.128:6379 master - 0 1535909491828 2 connected 0-5461
3、使用redis-trib.rb快速搭建叢集
當叢集內的節點數量多時,通過手動的方式搭建叢集費時費力,此時可通過redis-trib.rb來快速的搭建叢集。
Redis-trib.rb是採用ruby實現的redis叢集管理工具,內部通過Cluster相關命令幫助我們簡化叢集建立、檢查、槽遷移和均衡等常見的操作;使用redis-trib.rb之前需要安裝ruby依賴環境。
(1)安裝前準備
使用redis-trib.rb搭建叢集時由於機器有限將使用一臺新的機器,啟動6個redis例項完成叢集的搭建,各redis例項的安裝配置啟動同上面一樣。
角色 |
IP地址 |
埠 |
備註 |
Redis master |
192.168.16.134 |
6379 |
各主從節點是隨機分配的,在生產中建議使用多臺機器,主從節點不會分配在同一臺機器上 |
Redis master |
192.168.16.134 |
6380 |
|
Redis master |
192.168.16.134 |
6381 |
|
Redis slave |
192.168.16.134 |
6382 |
|
Redis slaver |
192.168.16.134 |
6383 |
|
Redis slaver |
192.168.16.134 |
6384 |
(2)安裝ruby及相關依賴
1)安裝ruby
# 下載安裝
# 安裝redis所需要的依賴
]# yum install zlib zlib-devel
]# wget http://cache.ruby-lang.org/pub/ruby/2.5/ruby-2.5.1.tar.gz
]# tar -xf ruby-2.5.1.tar.gz
]# cd ruby-2.5.1
]# ./configure --prefix=/usr/local/ruby
]# make && make install
# 建立快捷方式加入系統環境變數中或直接加環境變數
]# ln -s /usr/local/ruby/bin/ruby /usr/local/bin/
]# ln -s /usr/local/ruby/bin/gem /usr/local/bin/
2)安裝redis-trib.rb
# 安裝redis外掛,這一步安裝時有時會報錯,這次順利安裝
]# gem install redis
# 將redis原始碼包下的” redis-trib.rb”拷貝到系統環境變數下
]# cp /usr/local/src/redis-3.2.12/src/redis-trib.rb /usr/local/bin/redis-trib.rb
3)使用”redis-trib.rb”快速建立叢集
# 使用”redis-trib.rb快速建立叢集”
]# redis-trib.rb create --replicas 1 192.168.16.134:6379 192.168.16.134:6380 192.168.16.134:6381 192.168.16.134:6382 192.168.16.134:6383 192.168.16.134:6384
4)檢視叢集的狀態資訊
檢查叢集的狀態或檢視叢集的資訊通過任意一臺節點均可操作。操作命令分別如下:
檢查叢集的狀態:redis-trib.rb check <nodeip>:<nodeport>
檢視叢集的資訊:redis-trib.rb info <nodeip>:<nodeport>
# 檢查叢集的狀態
]# redis-trib.rb check 192.168.16.134:6379
>>> Performing Cluster Check (using node 192.168.16.134:6379)
M: 2411c6c80e9f9473ab8971eccf39a6f1e7ef3024 192.168.16.134:6379
slots:0-5460 (5461 slots) master
1 additional replica(s)
S: 10aff3883025046ceba675d4272c7bdfd524a0c4 192.168.16.134:6384
slots: (0 slots) slave
replicates 333995e83ce190a5e6c52f8a7c216a9b73ef76ad
S: 3695a2eb1f7c10dcee7a3a61eccab57a296298c5 192.168.16.134:6382
slots: (0 slots) slave
replicates 2411c6c80e9f9473ab8971eccf39a6f1e7ef3024
S: a906637c42295a1f29b2eef1273a8a6c27f545d1 192.168.16.134:6383
slots: (0 slots) slave
replicates 8b3f2a2b393d593e4d33057223545a4308762858
M: 333995e83ce190a5e6c52f8a7c216a9b73ef76ad 192.168.16.134:6381
slots:10923-16383 (5461 slots) master
1 additional replica(s)
M: 8b3f2a2b393d593e4d33057223545a4308762858 192.168.16.134:6380
slots:5461-10922 (5462 slots) master
1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
4、redis cluster節點通訊
Redis cluster各節點啟動後,會發現本地除了監聽配置檔案中的埠外,還會監聽另一個redis節點監聽的埠加”10000”的埠,此埠主要用於各節點之間的通訊。Redis各節點之間通訊採用的是p2p的Gossip(流言)協議,Gossip協議工作的原理就是節點彼此不斷通訊交換資訊,一段時間後所有節點都會知道叢集的資訊。
(1)Gossip訊息的型別
1)ping訊息:用於檢測節點是否線上和交換彼此狀態資訊
2)meet訊息:用於通知新節點的加入
3)pong訊息:當接收到ping、meet訊息時,作為響應訊息回覆給傳送方的確認訊息
4)fail訊息:當節點判定叢集內一個節點下線時,會向叢集內廣播一個fail訊息,其他節點接收到fail訊息時把對應的節點更新為下線狀態。
(2)通訊節點的選擇
叢集內每個節點維護定時任務預設每秒執行10次,每次會隨機選取5個節點找出最久沒有通訊的節點發送ping訊息,用於保證Gossip資訊交換的隨機性。
二、redis叢集的管理
1、擴容叢集
Redis叢集的擴容可以通過”準備節點”——>”讓節點加入叢集”——>”遷移槽和資料到新增節點”的流程完成叢集的擴容;遷移槽和資料到新節點過程手動操作時由於過程較多,容易出錯,這個過程可以通過”redis-trib”提供的槽重分片功能快速的完成槽的重新分片。
以下的操作均基於通過”redis-trib-rb”快速搭建的單機多例項的叢集中操作。
(1)準備新節點
角色 |
IP地址 |
埠 |
Redis master |
192.168.16.134 |
6385 |
Redis master |
192.168.16.134 |
6386 |
(2)讓節點加入叢集
# 讓新節點加入到叢集中
127.0.0.1:6379> CLUSTER MEET 192.168.16.134 6385
127.0.0.1:6379> CLUSTER MEET 192.168.16.134 6386
# 檢視新新增節點狀態時由於沒有分配槽,還不能正常工作
127.0.0.1:6379> cluster nodes
9e2e045b752b467313d4b21ecc42b8d9a4c1a3dc 192.168.16.134:6386 master - 0 1536001730850 0 connected
0bde7ccda11f686ffe3b5a2ad4020c282710018f 192.168.16.134:6385 master - 0 1536001727822 7 connected
……
除了使用”cluster meet”命令讓節點加入叢集,還可以使用”redis-trib.rb”工具讓新增節點加入叢集,如果使用”redis-trib.rb”讓節點加入叢集,則執行的命令為(在生產環境中建議使用”redis-trib.rb”命令加入新節點):
redis-trib.rb add-node 192.168.16.134:6385 192.168.16.134:6379
redis-trib.rb add-node 192.168.16.134:6385 192.168.16.134:6379
(3)手動遷移槽和資料
在手動遷移槽和資料前需要為新節點指定槽遷移計劃,確定原有槽的那些資料需要遷移到新節點;遷移計劃中要保證每個節點負責相似數量的槽,從而保證各節點資料的均勻。
遷移的流程如下:
1)對目標節點發送”cluster setslot {slot} importing {sourceNodeId}”命令,讓目標節點準備匯入槽資料
2)對源節點發送”cluster setslot {slot} migrating {targetNodeId}”命令,讓源節點準備遷出槽的資料。
3)源節點迴圈執行”cluster getkeysinslot {slot} {count}”命令,獲取count個屬於{slot}的鍵
4)在源節點上執行”migrate {targetIp} {gargetPort} “” 0 {timeout} keys {key…}”命令,把獲取到的鍵通過流水線(pipeline)機制批量遷移到目標節點;重複執行步驟3和4知道槽寫所有的鍵值資料都遷移到目標節點
5)向叢集內的所有節點發送”cluster setslot {slot} node {targetNodeId}”命令,通知槽分配給目標節點。
(4)使用槽重分片功能”redis-trib”
命令:redis-trib.rb reshard host:port –from <arg> --to <arg> --slots <arg> --yes –timeout <arg> --pipline <arg>
引數:
Host:port:叢集內任意幾點地址
--from:指定源節點的Id,如果有多個源節點,使用逗號分隔
--to:需要遷移的目標節點的id
--slots:需要遷移槽的總數量,在遷移過程中提示使用者輸入,
--yes:當打印出reshard執行計劃時,是否需要使用者輸入yes確認後在執行reshard
--timeout:控制每次migrate操作的超時時間,預設為60000毫秒
--pipeline:控制每次遷移鍵的數量,預設為10
# 使用redis-trib.rb完成資料的遷移和槽的重新分片
]# redis-trib.rb reshard 127.0.0.1:6379
在遷移的過程中要求輸入遷移的槽的數量,目標節點的id(只能輸入一個),源節點的id(根據自己的叢集環境輸入,輸出完成後輸入”done”回車完成輸入)
# 遷移完成後檢視新節點槽狀態,已經分配了槽,槽不連續不影響redis叢集的使用
127.0.0.1:6379> CLUSTER NODES
……
0bde7ccda11f686ffe3b5a2ad4020c282710018f 127.0.0.1:6385 master - 0 1536004597778 7 connected 0-1364 5461-6826 10923-12287
(5)為新新增的主節點新增從節點
# 為新增主節點新增從節點
192.168.16.134:6386> CLUSTER REPLICATE 0bde7ccda11f686ffe3b5a2ad4020c282710018f
# 檢視節點狀態時從節點已經開始複製主節點
192.168.16.134:6386> cluster nodes
……
9e2e045b752b467313d4b21ecc42b8d9a4c1a3dc 127.0.0.1:6386 myself,slave 0bde7ccda11f686ffe3b5a2ad4020c282710018f 0 0 0 connected
2、收縮叢集
Redis叢集能夠擴容,也就能夠收縮,收縮redis叢集的流程與擴容redis叢集的流程恰恰相反。
(1)遷移下線節點負責的槽及資料
在使用” redis-trib.rb reshard”命令遷移槽及資料到目標節點時,由於目標節點只能輸入一個,當有多個節點時需要執行多次” redis-trib.rb reshard”命令將要下線的節點的槽及資料遷移到其他節點。
下線計劃:下線節點192.168.16.134:6379,將此節點負責的槽及資料遷移到其他的三個節點上。
# 檢視節點192.168.16.134:6379負責的槽
127.0.0.1:6379> CLUSTER NODES
2411c6c80e9f9473ab8971eccf39a6f1e7ef3024 192.168.16.134:6379 myself,master - 0 0 1 connected 1365-5460
# 遷移4095個槽到192.168.16.124:6380
]# redis-trib.rb reshard 192.168.16.134:6379
……
# 輸入遷移槽數量
How many slots do you want to move (from 1 to 16384)? 1365
# 遷移到的目標節點192.168.16.134:6380的id
What is the receiving node ID? 8b3f2a2b393d593e4d33057223545a4308762858
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.
# 遷移到的源節點192.168.16.134:6379的id,輸入完成後輸入done結束
Source node #1:2411c6c80e9f9473ab8971eccf39a6f1e7ef3024
Source node #2:done
……
遷移完成後,按照上面的遷移方法,分別遷移1366、1365個槽到節點192.168.16.134:6381及節點192.168.16.134:6382。
# 遷移後的個主節點的槽分佈如下
127.0.0.1:6379> CLUSTER NODES
333995e83ce190a5e6c52f8a7c216a9b73ef76ad 192.168.16.134:6381 master - 0 1536006341658 9 connected 2730-4095 12288-16383
2411c6c80e9f9473ab8971eccf39a6f1e7ef3024 192.168.16.134:6379 myself,master - 0 0 1 connected
8b3f2a2b393d593e4d33057223545a4308762858 192.168.16.134:6380 master - 0 1536006345714 8 connected 1365-2729 6827-10922
0bde7ccda11f686ffe3b5a2ad4020c282710018f 127.0.0.1:6385 master - 0 1536006343700 10 connected 0-1364 4096-6826 10923-12287
(2)忘記節點
槽遷移完成後,為了讓其他節點不再與下線節點進行Gossip訊息交換,需要讓叢集內的所有節點忘記要下線的幾點。
命令:redis-trib.rb del-node {host:port} {downNodeId}
# 讓所有幾點忘記下線的節點192.168.16.134:6379及它的從節點192.168.16.134:6379:6382
]# redis-trib.rb del-node 192.168.16.134:6379 2411c6c80e9f9473ab8971eccf39a6f1e7ef3024
>>> Removing node 2411c6c80e9f9473ab8971eccf39a6f1e7ef3024 from cluster 192.168.16.134:6379
>>> Sending CLUSTER FORGET messages to the cluster...
>>> SHUTDOWN the node.
]# redis-trib.rb del-node 192.168.16.134:6382 3695a2eb1f7c10dcee7a3a61eccab57a296298c5
忘記節點後再次檢視節點狀態時,叢集中已經沒有下線節點192.168.16.134:6379及節點192.168.16.134:6382的資訊。
192.168.16.134:6380> CLUSTER NODES
0bde7ccda11f686ffe3b5a2ad4020c282710018f 192.168.16.134:6385 master - 0 1536006923917 10 connected 0-1364 4096-6826 10923-12287
a906637c42295a1f29b2eef1273a8a6c27f545d1 192.168.16.134:6383 slave 8b3f2a2b393d593e4d33057223545a4308762858 0 1536006921379 8 connected
8b3f2a2b393d593e4d33057223545a4308762858 192.168.16.134:6380 myself,master - 0 0 8 connected 1365-2729 6827-10922
333995e83ce190a5e6c52f8a7c216a9b73ef76ad 192.168.16.134:6381 master - 0 1536006926953 9 connected 2730-4095 12288-16383
10aff3883025046ceba675d4272c7bdfd524a0c4 192.168.16.134:6384 slave 333995e83ce190a5e6c52f8a7c216a9b73ef76ad 0 1536006924931 9 connected
9e2e045b752b467313d4b21ecc42b8d9a4c1a3dc 127.0.0.1:6386 slave 0bde7ccda11f686ffe3b5a2ad4020c282710018f 0 1536006925939 10 connected
3、連線叢集
(1)連線重定向
Redis在叢集模式下接受任何鍵相關命令時首先計算鍵對應的槽,再根據槽找出所對應的節點,如果節點時自身則處理請求命令,否則恢復move重定向錯誤,通知客戶端請求正確的節點。如果在使用”redis-cli”命令時加”-c”引數則會自動重定向。
(2)程式連線redis
smart客戶端支援叢集協議。
三、redis叢集故障的發現與恢復
1、故障的發現
(1)主觀下線(pfail)
某個節點認為一個節點不可用
(2)客觀下線(fail)
叢集內多個節點都認為某個節點不可用,從而達成共識標識該節點下線;如果該節點為主節點則要進行故障轉移
2、故障恢復
故障節點變為客觀下線後,如果下線節點時持有槽的主節點,則需要在它的從節點中選舉出一個替換它。選舉流程如下
(1)資格檢查
(2)準備選舉時間
(3)發起選舉
(4)選舉投票
(5)替換主節點
3、手動故障轉移
Redis支援手動故障轉移功能,指定從節點發起故障轉移流程,主從節點進行故障的切換。
手動故障轉移命令:cluster failover