Redis 高可用方案:sentinel(哨兵模式)和集羣
一. redis 高可用方案–sentinel(哨兵模式)
當我們搭建好 redis 主從複製方案後會發現一個問題,那就是當主服務器宕機後,需要手動把一臺從服務器切換爲主服務器,這就需要人工干預,費事費力,同時在手動切過程中也會導致 redis 服務器寫入功能不可用。所以需要一種方法可以完成 Master 故障後可以自動的將一個 Slave 切換爲 Master,這個時候就有了 sentinel 哨兵模式。
哨兵模式簡介:
sentinel 是官方提供的高可用方案,其原理是哨兵通過發送命令,等待 Redis 服務器響應,從而監控運行的多個 Redis 實例。同時 sentinel 是一個分佈式系統,可以在一個架構中運行多個 Sentinel 進程,可以做到 sentinel 的高可用。
sentinel 工作過程:
-
通過向主服務器和從服務器發送 ping 命令,讓服務器返回運行狀態。
-
當哨兵監測到 master 宕機,會自動將一個 slave 切換成 master,然後通過發佈訂閱模式通知其他的從服務器,修改配置文件,讓它們切換主機。
關於 sentinel 的三個定時任務:
-
每 1 秒每個 sentinel 對其他 sentinel 和 redis 節點執行 ping 操作,心跳檢測。
-
每 10 秒每個 sentinel 會對 master 和 slave 執行 info 命令,目的是發現 slave 結點,確定主從關係。
-
每 2 秒每個 sentinel 通過 master 節點的 channel 交換信息(pub/sub)。master 節點上有一個發佈訂閱的頻道 (sentinel:hello)。sentinel 節點通過
__sentinel__:hello
頻道進行信息交換 (對節點的 "看法" 和自身的信息),達成共識.
sentinel 網絡:
sentinel 是一個分佈式系統,可以在一個架構中運行多個 Sentinel 進程。所以監控同一個 Master 的 Sentinel 會自動連接,組成一個分佈式的 Sentinel 網絡,互相通信並交換彼此關於被監視服務器信息。
sentinel 網絡故障修復原理:
1. 主觀下線:
當主服務器發生故障時,此時一個 sentinel 發現了故障,系統並不會馬上進行 failover 過程(這個現象稱爲主觀下線),它會向網絡中的其他 Sentinel 進行確認。
2. 客觀下線:
接着其他 Sentinel 也陸續發現故障,這個時候其中一個 Sentinel 就會發起投票。一定數量的哨兵 (在配置文件中指定) 確認 Master 被標記爲主觀下線,此時將 Master 標記爲客觀下線。
3.sentinel 的 leader 選舉:
要想完成故障切換(將故障 master 剔除,並將一個 slave 提升爲 master)就必須先選舉一個 leader。最先發現故障的 sentinel 向其他哨兵發起請求成爲 leader,其他哨兵在沒有同意別的哨兵的 leader 請求時,就會把票投給該 sentinel。當半數以上的 sentinel 投票通過後就認定該 sentinel 爲 leader。接下來的故障切換有該 leader 完成。
4.master 選舉:
leader 選好後將故障 master 剔除,從 slave 中挑選一個成爲 master。遵照的原則如下:
-
slave 的優先級
-
slave 從 master 那同步的數據量,那個 slave 多就優先。
5. 新 Master 再通過發佈訂閱模式通知所有 sentinel 更新監控主機信息。
6. 故障的主服務器修復後將成爲從服務器繼續工作。
故障發生
故障切換
Master 重新上線後
哨兵模式配置
本實驗在一臺機器上完成,創建不同端口的 redis 實例。
1. 創建 redis 實例
[root@redis ~]# nohup redis-server --port 6380 >> /data/redis/log/6380.log 2>&1 &
[root@redis ~]# nohup redis-server --port 6381 >> /data/redis/log/6381.log 2>&1 &
[root@redis ~]# nohup redis-server --port 6382 >> /data/redis/log/6382.log 2>&1 &
[root@redis ~]# ps -ef |grep redis
root 16421 16314 0 03:01 pts/1 00:00:00 redis-server *:6380
root 16427 16314 0 03:01 pts/1 00:00:00 redis-server *:6381
root 16431 16314 0 03:01 pts/1 00:00:00 redis-server *:6382
root 16436 16314 0 03:01 pts/1 00:00:00 grep --color=auto redis
2. 連接數據庫並設置主從複製
[root@redis ~]# redis-cli -p 6380
127.0.0.1:6380>
[root@redis ~]# redis-cli -p 6381
127.0.0.1:6381> SLAVEOF 127.0.0.1 6380 #將6380設置爲master
OK
[root@redis ~]# redis-cli -p 6382
127.0.0.1:6382> SLAVEOF 127.0.0.1 6380
OK
3. 搭建哨兵模式集羣
創建 sentinel 配置文件
[root@redis conf]# cat sentinel1.conf
port 26300 #指定sentinel進程端口號
sentinel monitor redis1 127.0.0.1 6380 2 #Sentinel monitor <name> <ip> <port> <quorum>
[root@redis conf]# cat sentinel2.conf
port 26301
sentinel monitor redis1 127.0.0.1 6380 2
-
name
:redis 主服務名稱,可以自行命名,但是在一個 sentinel 網絡中,一個 redis 主服務只能有一個名稱; -
ip和port
:redis 主服務的 IP 地址和端口號. -
quorum
:表示要將這個主服務器判斷爲失效並下線至少需要 2 個 sentinel 同意 -
protected-mode
:關閉保護模式(默認情況下,redis node 和 sentinel 的 protected-mode 都是 yes,在搭建集羣時,若想從遠程連接 redis 集羣,需要將 redis node 和 sentinel 的 protected-mode 修改爲 no,若只修改 redis node,從遠程連接 sentinel 後,依然是無法正常使用的,且 sentinel 的配置文件中沒有 protected-mode 配置項,需要手工添加。依據 redis 文檔的說明,若 protected-mode 設置爲 no 後,需要增加密碼證或是 IP 限制等保護機制,否則是極度危險的。)
啓動 sentinel
[root@redis ~]# nohup redis-sentinel /data/redis/conf/sentinel1.conf >> /data/redis/log/sentinel1.log 2>&1 &
[1] 16522
[root@redis ~]# nohup redis-sentinel /data/redis/conf/sentinel2.conf >> /data/redis/log/sentinel2.log 2>&1 &
[2] 16526
[root@redis ~]# ps -ef |grep sentinel
root 16522 16440 0 03:55 pts/2 00:00:00 redis-sentinel *:26300 [sentinel]
root 16526 16440 0 03:55 pts/2 00:00:00 redis-sentinel *:26301 [sentinel]
4. 測試。模擬主節點故障,查看故障後主從環境改變
關閉主節點
[root@redis ~]# ps -ef |grep redis-server
root 16604 16440 0 04:12 pts/2 00:00:02 redis-server *:6381
root 16608 16440 0 04:12 pts/2 00:00:03 redis-server *:6382
root 16702 16314 0 04:46 pts/1 00:00:00 redis-server *:6380
[root@redis ~]# kill 16702
此時查看 6381 和 6382 的日誌文件,在 6382 的日誌文件中發現瞭如下內容,說明此時已經將 6381 切換爲主節點。
再次啓動 6380 時,6380 成爲 slave,6381 時 master
最後查看一下 sentinel 配置文件:
cat /data/redis/conf/sentinel2.conf
port 26301
sentinel myid 74cdfbb5ae55a77ad4d05d5d9d50fd64725e192a
# Generated by CONFIG REWRITE
dir "/root"
protected-mode no
sentinel deny-scripts-reconfig yes
sentinel monitor redis1 127.0.0.1 6381 1 #主節點
sentinel config-epoch redis1 1
sentinel leader-epoch redis1 1
sentinel known-replica redis1 127.0.0.1 6382 #從節點
sentinel known-replica redis1 127.0.0.1 6380
sentinel known-sentinel redis1 127.0.0.1 26300 9539652da78b0385479a827e753deceaef864989
sentinel current-epoch 1
二. redis 高可用方案–集羣
使用哨兵模式,解決了主節點故障自動切換的問題,但是卻不可以動態擴充 redis。所以在 redis3.0 之後提出了集羣模式。
redis 集羣設計:
redis 集羣採用無中心結構,每個節點保存數據和整個集羣狀態, 每個節點都和其他所有節點連接。
特點:
-
所有的 redis 節點彼此互聯 (PING-PONG 機制), 內部使用二進制協議優化傳輸速度和帶寬。
-
節點的失效是通過集羣中超過半數的節點檢測失效時才生效。
-
集羣是一個整體,客戶端與 redis 節點直連, 不需要中間 proxy 層. 客戶端不需要連接集羣所有節點, 連接集羣中任何一個可用節點即可。
-
Redis 集羣預分好 16384 個桶,當需要在 Redis 集羣中放置一個 key-value 時,根據 CRC16(key) mod 16384 的值,決定將一個 key 放到哪個桶中。
redis 集羣節點分配和數據分配
節點分配:
Redis 集羣預分好 16384 個桶,採用哈希槽 (hash slot) 的方式來平均分配 16384 個 slot 。以三個節點爲例,
-
節點 1:0-5460;
-
節點 2:5461-10922;
-
節點 3:10923-16383.
若存入一個值,按照哈希槽算法得到 6587,那麼就會將數據存入節點 2。取數據時也是從節點 2 上取。
當新增一個節點時:
採用從各個節點的前面各拿取一部分槽到新節點上,如添加節點 4,哈希槽就爲,0-1364,5461-6826,10923-12287。
redis 集羣的主從模式
爲了保證數據高可用,集羣應建立在主從基礎之上。一個主節點對應一個從節點。主節點提供數據存取,從節點提供數據讀取,當主節點故障後,就會有這個從節點選取一個來充當主節點,從而保證集羣正常運行。
但是在一個集羣中,一對主從節點同時故障,那麼集羣將失去服務能力。
redis 集羣搭建:
redis 集羣中至少應該有奇數個節點,所以至少有三個節點,每個節點至少有一個備份節點,所以本次實驗使用 6 個節點(主節點、備份節點由 redis-cluster 集羣確定)。
實驗在兩臺機器進行,每臺機器啓動三個基於不同端口 redis 實例,6 個實例兩兩對應主從。
1. 創建一個目錄 redis_cluster, 用來存放每個實例所用的配置文件.
[root@redis redis]# mkdir redis_cluster
[root@redis redis]# mkdir -p redis_cluster/7001
[root@redis redis]# cp -r conf/redis.conf redis_cluster/
2. 修改配置文件,將修改好的文件複製 5 份分別放置不同 redis 配置目錄下。
修改配置文件
vim 7001/redis.conf修改一下幾項
bind 192.168.126.162 (本機IP)
port 7001 #redis端口
daemonize yes #redis在後臺啓動
logfile "/data/redis/log/logs"
pidfile /var/run/redis_7001.pid
cluster-enabled yes #開啓集羣功能
cluster-config-file nodes-7001.conf #集羣配置文件
cluster-node-timeout 5000 #姐點之間通訊時間
appendonly yes #開啓AOF持久化方式
創建目錄 7002 到 7006,其中 7004 到 7005 創建在192.168.126.161
上。再把配置文件複製到700*
目錄下,修改配置文件中端口號和 ip。
[root@redis redis_cluster]# cp -rp 7001 7002
[root@redis redis_cluster]# cp -rp 7001 7003
[root@redis redis_cluster]# vim 7002/redis.conf #修改端口爲7002
[root@redis redis_cluster]# vim 7003/redis.conf
將配置文件目錄拷貝到192.168.126.161上
[root@redis redis_cluster]# scp -rp 7001 192.168.126.161:/usr/local/redis/redis_cluster/
修改配置文件(端口號和ip)
[root@centosm redis_cluster]# ls
7004 7005 7006
3. 啓動 redis,可以使用腳本啓動
[root@redis redis_cluster]# ls
7001 7002 7003 start.sh
[root@redis redis_cluster]# cat start.sh #另一臺機器相同操作
cd 7001
redis-server redis.conf
cd ../7002
redis-server redis.conf
cd ../7003
redis-server redis.conf
#192.168.126.162
[root@redis redis_cluster]# ps -ef |grep redis
root 1757 1 2 12:36 ? 00:00:00 redis-server 192.168.126.162:7001 [cluster]
root 1762 1 1 12:36 ? 00:00:00 redis-server 192.168.126.162:7002 [cluster]
root 1767 1 1 12:36 ? 00:00:00 redis-server 192.168.126.162:7003 [cluster]
#192.168.126.161
[root@centosm redis_cluster]# ps -ef |grep redis
root 11906 1 0 23:07 ? 00:00:00 redis-server 192.168.126.161:7004 [cluster]
root 11911 1 0 23:07 ? 00:00:00 redis-server 192.168.126.161:7005 [cluster]
root 11913 1 0 23:07 ? 00:00:00 redis-server 192.168.126.161:7006 [cluster]
4. 開始創建集羣
搭建集羣的話,如果 redis 版本小於 5.0 就需要使用一個工具 redis-trib(腳本文件),這個工具在 redis 解壓文件的源代碼裏。因爲這個工具是一個 ruby 腳本文件,所以這個工具的運行需要 ruby 的運行環境,所以需要安裝 ruby
yum install ruby -y
yum install rubygems -y
gem install redis
當前 redis 版本大於 5.0,所以不用 ruby,可以直接創建。
redis-cli --cluster create 192.168.126.162:7001 192.168.126.162:7002 192.168.126.162:7003 192.168.126.161:7004 192.168.126.161:7005 192.168.126.161:7006 --cluster-replicas 1
–cluster-replicas 1
:主從比例爲 1:1
[root@redis redis_cluster]# redis-cli --cluster create 192.168.126.162:7001 192.168.126.162:7002 192.168.126.162:7003 192.168.126.161:7004 192.168.126.161:7005 192.168.126.161:7006 --cluster-replicas 1
>>> Performing hash slots allocation on 6 nodes... #對6個節點進行哈希槽位分配,實際分配三個主節點即可。
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 192.168.126.161:7006 to 192.168.126.162:7001 #三個主節點7001 7004 7002
Adding replica 192.168.126.162:7003 to 192.168.126.161:7004 #三個從節點7006 7005 7003
Adding replica 192.168.126.161:7005 to 192.168.126.162:7002
M: fb89e991f2fca476964195f496428c0de3e57f76 192.168.126.162:7001
slots:[0-5460] (5461 slots) master
M: 54788eed17c99719f0d9e49b4933f8fc6e900cd9 192.168.126.162:7002
slots:[10923-16383] (5461 slots) master
S: 0d4d849e80a4f12e546fa3df7fcec42cb65951b2 192.168.126.162:7003
replicates 4fbffafb9088e65f60526147f4bff5260ea897f0
M: 4fbffafb9088e65f60526147f4bff5260ea897f0 192.168.126.161:7004
slots:[5461-10922] (5462 slots) master
S: 6f44fa89577fd53ff8d703390e3908b7db5cb88c 192.168.126.161:7005
replicates 54788eed17c99719f0d9e49b4933f8fc6e900cd9
S: 3f224e631bffba6d3978412df83c11b9d53f5799 192.168.126.161:7006
replicates fb89e991f2fca476964195f496428c0de3e57f76
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
......
>>> Performing Cluster Check (using node 192.168.126.162:7001)
M: fb89e991f2fca476964195f496428c0de3e57f76 192.168.126.162:7001
slots:[0-5460] (5461 slots) master
1 additional replica(s)
S: 0d4d849e80a4f12e546fa3df7fcec42cb65951b2 192.168.126.162:7003
slots: (0 slots) slave
replicates 4fbffafb9088e65f60526147f4bff5260ea897f0
M: 54788eed17c99719f0d9e49b4933f8fc6e900cd9 192.168.126.162:7002
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
S: 6f44fa89577fd53ff8d703390e3908b7db5cb88c 192.168.126.161:7005
slots: (0 slots) slave
replicates 54788eed17c99719f0d9e49b4933f8fc6e900cd9
S: 3f224e631bffba6d3978412df83c11b9d53f5799 192.168.126.161:7006
slots: (0 slots) slave
replicates fb89e991f2fca476964195f496428c0de3e57f76
M: 4fbffafb9088e65f60526147f4bff5260ea897f0 192.168.126.161:7004
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
[OK] All nodes agree about slots configuration. #所有節點同意分配hash槽
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered. #分配完畢,創建完成
最後集羣主從對應關係
可以看出主從節點在兩個節點隨機分配,且一對對應主從服務不會分配到同一臺機器上。即使一臺機器損壞,也不會影響 redis 繼續提供服務。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/SCCgm0nmFTCe0vge5s-B_g