Redis 主從復制、哨兵模式、集群
1、單機模式
持久化是最簡單的高可用方法(有時甚至不被歸為高可用的手段),主要作用是數據備份,即將數據存儲在硬盤,保證數據不會因進程退出而丟失。
缺點
單機故障,無法保證數據的安全
讀寫操作無法負載均衡
容量瓶頸,存儲能力受到限制
2、主從復制
復制是高可用 Redis 的基礎,哨兵和集群都是在復制基礎上實現高可用的。復制主要實現了數據的多機備份(容災備份),以及對于讀操作的負載均衡(寫操作仍然在主機)和簡單的故障恢復。
master:寫操作
slave:讀操作(負載均衡),不能寫

配置
公共配置(端口,文件保存路徑,根據環(huán)境配置)
bind 0.0.0.0
port 6000
daemonize yes
pidfile "/home/eric/redis-masterslave/redis6000/redis_6000.pid"
logfile "/home/eric/redis-masterslave/redis6000/redis.log"
dbfilename "dump.rdb"
dir "/home/eric/redis-masterslave/redis6000"
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb配置主機地址與密碼(配從不配主)
masterauth:主要是針對 master 對應的 slave 節(jié)點設置的,在 slave 節(jié)點數據同步的時候用到。
requirepass:對登錄權限做限制,redis 每個節(jié)點的 requirepass 可以是獨立、不同的。
replicaof 127.0.0.1 6000
masterauth 123456 # 如果主機設置密碼的話,需要填寫(主機使用 requirepass, 從機使用 masterauth)
查看節(jié)點信息
127.0.0.1:6000> info replication
配置建議
主機通常不配置 RDB 和 AOF 持久化
save ""
appendonly no
工作流程

建立連接
設置 master 的地址和端口,發(fā)送 slaveof ip port 指令,master 會返回響應客戶端,根據響應信息保存 master 的 run id 和 ip port 信息(連接測試)
根據保存的信息創(chuàng)建連接 master 的 socket
周期性發(fā)送 ping,master 會相應 pong
發(fā)送指令 auth password(身份驗證),master 驗證身份
發(fā)送 slave 端口信息,master 保存 salve 端口號
數據同步

slave 發(fā)送指令 psync2(psync2 run_id -1)
主機返回當前的 runid 和 offset 給 salve
salve 保存主機的相關信息
master 執(zhí)行 bgsave
在第一個 salve 連接時,創(chuàng)建命令緩存區(qū)
生產 RDB 文件,通過 socket 發(fā)送給 slave
slave 接收 RDB 文件,清空數據,執(zhí)行 RDB 文件恢復過程
發(fā)送命令告知 RDB 恢復已經完成(告知全量復制完成)
master 發(fā)送復制緩沖區(qū)信息
slave 接收信息,執(zhí)行重寫后恢復數據
注意 master 會保存 slave 從我這里拿走了多少數據,保存 slave 的偏移量
全量復制消耗
bgsave 時間
RDB 文件網絡傳輸
從節(jié)點請求數據時間
從節(jié)點加載 RDB 的時間
可能的 AOF 重寫時間
# 查看 runid
127.0.0.1:6001> info server
# Server
...
run_id:ac11dde108fa5288af0f7d72c6c0f20e4611157d
...
# 查看 offset
127.0.0.1:6002> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=6000,state=online,offset=3482,lag=1
slave1:ip=127.0.0.1,port=6001,state=online,offset=3482,lag=1
master_repl_offset:3482
...
命令傳播
slave 心跳:replconf ack (offset)匯報 slave 自己的 offset,獲取最新的數據指令
命令傳播階段出現斷網:
網絡閃斷、閃連:忽略
短時間斷網:增量
長時間斷網:全量
全量復制核心三個要素
服務器運行ID
用于服務器之間通信驗證身份,master 首次連接 slave 時,會將自己的 run id 發(fā)送給 slave,slave 保存此 ID
主服務器積壓的命令緩沖區(qū)
先進先出隊列
主服務器的復制偏移量
用于比對偏移量,然后判斷出執(zhí)行全量還是增量
切換主從命令
將當前服務器轉變?yōu)橹付ǚ掌鞯膹膶俜掌?/span>
slaveof 127.0.0.1 6000
將從屬服務器用作新的主服務器
slaveof no noe
缺點
存儲能力受到單機的限制
缺陷是故障恢復無法自動化
寫操作無法負載均衡
3、哨兵模式
在 Redis 2.8 版本開始引入,在主從復制的基礎上,哨兵實現了自動化的故障恢復。通俗的來說哨兵模式的出現時為了解決主從復制模式中需要人為操作的東西,變?yōu)樽詣硬僮?/span>

功能
監(jiān)控(Monitoring):哨兵會不斷的檢查主節(jié)點和從節(jié)點是否正常工作
自動故障轉移(Automatic Failover):當主節(jié)點不能正常工作時,哨兵會開始自動故障轉移操作,它會選擇失效的主節(jié)點里其中一個從節(jié)點升級為新的主節(jié)點,并讓其他從節(jié)點改為復制新的主節(jié)點中的數據
配置提供者(Configuration Provider):客戶端在初始化時,通過連接哨兵來獲取當前 Redis 服務的地址
通知(Notification):哨兵可以將故障轉移的結果發(fā)送給客戶端
其中,監(jiān)控和自動故障轉移功能,使得哨兵可以及時發(fā)現主節(jié)點的故障并完成轉移,而配置提供者和通知功能,則需要在與客戶端交互中才能體現
架構
哨兵節(jié)點:哨兵系統(tǒng)由一個或多個哨兵節(jié)點組成,哨兵節(jié)點是特殊的 Redis 節(jié)點,不存儲數據
數據節(jié)點:主節(jié)點和從節(jié)點都是數據節(jié)點
配置
配置哨兵
復制 sentinel.conf 至目標目錄下,并進行修改
bind 0.0.0.0
port 8000
daemonize yes
pidfile /home/eric/redis-sentinel/redis8000/redis-sentinel-8000.pid
logfile "/home/eric/redis-sentinel/redis8000/sentinel-8000.log"
dir /home/eric/redis-sentinel/redis8000
sentinel monitor mymaster 127.0.0.1 7000 2
# sentinel auth-pass <master-name> <password>
其中 sentinel monitor mymaster 127.0.0.1 7000 2 的含義是:該節(jié)點監(jiān)控 127.0.0.1 7000 這個主節(jié)點,該主節(jié)點的名稱定義為 mymaster,最后的 2 的含義與主節(jié)點故障判定有關,即至少需要 2 個哨兵同意(認為該主機點已經不能提供服務),才能判斷該主節(jié)點發(fā)生故障并進行故障轉移。
配置數據(主從)節(jié)點
同主從配置
啟動
啟動數據(主從)節(jié)點
哨兵系統(tǒng)的主從節(jié)點與普通的主從節(jié)點配置完全相同,并不需要做額外的處理
replicaof <masterip> <masterport>
啟動哨兵
redis-sentinel ./redis8000/sentinel.conf
redis-sentinel ./redis8001/sentinel.conf
redis-sentinel ./redis8002/sentinel.conf
當發(fā)送故障轉移的時候,哨兵會自己修改配置文件中的 sentinel monitor 配置
客戶端(Jedis)訪問哨兵系統(tǒng)
Set<String> set = new HashSet<>();
set.add("127.0.0.1:8000");
set.add("127.0.0.1:8001");
set.add("127.0.0.1:8002");
JedisSentinelPool jedisSentinelPool= new JedisSentinelPool("mymaster", set, "pwd");
Jedis jedis = jedisSentinelPool.getResource();
jedis.set("key", "value");
原理
相關概念
主觀下線:在心跳檢測的定時任務中,如果其他節(jié)點超過一定的時間沒有響應,哨兵節(jié)點就會將其進行主觀下線,顧名思義,主觀下線是一個哨兵節(jié)點“主觀的”判斷下線,與其對應的是客觀下線
客觀下線:哨兵節(jié)點在對主節(jié)點進行主觀下線后,會通過 sentinel is-maste-down-by-addr 命令詢問其他哨兵節(jié)點該主節(jié)點的狀態(tài),如果判斷主節(jié)點下線的哨兵達到一定數量后,則對該主節(jié)點進行客觀下線
需要注意的是:客觀下線是主節(jié)點才有的概念,如果哨兵發(fā)現從節(jié)點故障,被哨兵主觀下線后,不會再有后續(xù)的客觀下線和故障轉移操作。
定時任務:每個哨兵節(jié)點維護了 3 個定時任務,定時任務的功能分別如下:
每 10 秒通過向該主節(jié)點發(fā)送 info 命令獲取最新的主從結構
發(fā)現 slave 節(jié)點
確定主從關系
每 2 秒通過發(fā)布/訂閱功能獲取其他哨兵的信息
每 1 秒通過向其他節(jié)點發(fā)送 ping 命令,進行心跳檢測,判斷是否下線(Monitor)
選舉領導者哨兵節(jié)點
當主節(jié)點被判斷客戶下線后,各個哨兵會協(xié)商,選舉出一個領導者哨兵節(jié)點,并由改領導者節(jié)點對其進行故障轉移操作。
監(jiān)視改主節(jié)點的哨兵都有可能成為領導者,選舉使用的算法是 Raft 算法,Raft 算法的思路是先到先得,即在一輪選舉中,哨兵 A 向哨兵 B 發(fā)送稱為領導者的申請,如果哨兵 B 沒有同意過其他哨兵,則會同意哨兵 A 成為領導者,選舉的過程很快,通常,誰先完成客觀下線,一般就能成為領導者,成為領導者后,就可以開始進行故障轉移,即選舉新的主節(jié)點
選舉主節(jié)點原則
首先過濾掉不健康的從節(jié)點(ping 不通,或延遲比較久)
過濾掉響應慢的從節(jié)點
過濾掉與 master 斷開時間最久的從節(jié)點
優(yōu)先原則
優(yōu)先選擇優(yōu)先級最高(replica-priority)的從節(jié)點
如果優(yōu)先級無法區(qū)分,則選擇復制偏移量最大的從節(jié)點(偏移量越大,表示與主機數據越接近)
如果仍無法區(qū)分,則選擇 runid 最小的從節(jié)點
實踐建議
哨兵節(jié)點數量應不止一個,一方面增加哨兵節(jié)點的冗余,避免哨兵節(jié)點成為高可用的瓶頸,另一方面減少對客觀下線的誤判,此外哨兵節(jié)點通常放再不同的物理主機上
哨兵節(jié)點數量最好是奇數,以便于哨兵通過投票選出“領導者”以及對客觀下線的“決策”
各個哨兵節(jié)點配置應保持一致,包括硬件、網絡等參數,此外應保證時間的準確性
缺點
存儲能力受到單機的限制
寫操作無法負載均衡
4、Redis Cluster 高可用集群
通過集群,Redis 解決了寫操作無法負載均衡,以及存儲能力受到單機限制的問題,實現了較為完善的高可用方案

Redis Cluster 集群是一個由多個主從節(jié)點群組成的分布式服務器群(至少要有 3 個主節(jié)點),它具有復制、高可用和分片特性。Redis Custer 集群不需要 sentinel 哨兵也能完成節(jié)點移除和故障轉移的功能。需要將每個節(jié)點設置成集群模式,這種集群模式沒有中心節(jié)點,可水平擴展,據官方文檔稱可以線性擴展到 1000 節(jié)點。Redis Cluster 集群的性能和高可用性均優(yōu)于之前版本的哨兵模式,且集群配置非常簡單
集群搭建
redis-cli --cluster help
原生搭建
基本配置文件
bind 0.0.0.0
port 7000
daemonize yes
pidfile /home/eric/redis-cluster/redis7000/redis_7000.pid
logfile "/home/eric/redis-cluster/redis7000/redis_7000.log"
dir /home/eric/redis-cluster/redis7000/
masterauth 123456
requirepass 123456
配置開啟 cluster 節(jié)點(集群配置)
cluster-enabled yes(啟動集群模式)
cluster-config-file nodes-7000.conf(節(jié)點配置文件,這里 7000 最好和 port 對應上)
cluster-require-full-coverage no (主機宕機了,且沒有從機可進行故障轉移,那么整個集群是否可以繼續(xù)使用)# 替換配置文件
sed 's/7000/7001/g' redis7000/redis.conf > redis7001/redis.conf
sed 's/7000/7002/g' redis7000/redis.conf > redis7002/redis.conf
...
sed 's/7000/7005/g' redis7000/redis.conf > redis7005/redis.conf
# 啟動
redis-server ./redis7000/redis.conf
redis-server ./redis7001/redis.conf
redis-server ./redis7002/redis.conf
redis-server ./redis7003/redis.conf
redis-server ./redis7004/redis.conf
redis-server ./redis7005/redis.conf
# 檢查進程啟動情況
ps -ef | grep redis
eric 252 1 0 13:32 ? 00:00:00 redis-server 0.0.0.0:7000 [cluster]
eric 257 1 0 13:32 ? 00:00:00 redis-server 0.0.0.0:7001 [cluster]
eric 262 1 0 13:32 ? 00:00:00 redis-server 0.0.0.0:7002 [cluster]
eric 267 1 0 13:32 ? 00:00:00 redis-server 0.0.0.0:7003 [cluster]
eric 272 1 0 13:32 ? 00:00:00 redis-server 0.0.0.0:7004 [cluster]
eric 277 1 0 13:32 ? 00:00:00 redis-server 0.0.0.0:7005 [cluster]
eric 282 7 0 13:32 tty1 00:00:00 grep --color=auto redis
# 測試連接
redis-cli -h 127.0.0.1 -p 7000 -a 123456
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:7000> set k1 v1
(error) CLUSTERDOWN Hash slot not served // 沒有分配槽位,所以不能添加數據
127.0.0.1:7000> cluster nodes
7b777e4abce4e3427dd9a7a42721e46bdc42af88 :7000@17000 myself,master - 0 0 0 connected
meet
讓所有的集群相互認識(通訊)
cluster meet ip port
cluster meet 127.0.0.1 7001
cluster meet 127.0.0.1 7002
指派槽
查看 crc16 算法算出 key 的槽位命令 cluster keyslot key
cluster keyslot key
16384/3 0-5461 5462-10922 10923-16383
16384/4 4096
cluster addslots slot(槽位下標)
分配主從
cluster replicate node-id
使用 redis-cli 配置集群
Redis Cluster 集群需要至少要三個 master 節(jié)點,我們這里搭建三個 master 節(jié)點,并且給每個 master 再搭建一個 slave 節(jié)點,總共 6 個 Redis 節(jié)點。
由于節(jié)點數較多,這里采用在一臺機器上創(chuàng)建 6 個 Redis 實例,并將這 6 個 Redis 實例配置成集群模式,所以這里搭建的是偽集群模式,當然真正的分布式集群的配置方法幾乎一樣
查看集群命令:
redis-cli --cluster help
1、分配主機
create host1:port1 ... hostN:portN --cluster-replicas <arg>
redis-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 --cluster-replicas 1 -a 123456
其中--cluster-replicas 1 表示 6 個節(jié)點按 1:1 分配,那么就是 3 個 master 節(jié)點,3 個 slave 節(jié)點,如果 --cluster-replicas 2 則 6 個節(jié)點表示按照 1:2 分配,那么就會使 2 個 master 節(jié)點,4 個 slave 節(jié)點,如果這樣依賴,則不滿足最少 3 個 master 節(jié)點,就會失敗
主節(jié)點:取最前面的
從節(jié)點:依次取后面的,做為主節(jié)點的從節(jié)點,隨機分配
槽位:根據主機數量,平均分配
查看節(jié)點狀態(tài)
redis-cli -h 127.0.0.1 -p 7000 -a 123456 cluster nodes
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
7fd64ce350df005c963ab355e7e5551b00c6dc7e 127.0.0.1:7002@17002 master - 0 1599406449000 2 connected 5461-10922
fe9183edd29a1c1c9a34eccc1b638f46a1c59aab 127.0.0.1:7005@17005 slave 87e7956a0513ea3da005c78224d728e3cd77f609 0 1599406448000 3 connected
87e7956a0513ea3da005c78224d728e3cd77f609 127.0.0.1:7003@17003 master - 0 1599406450945 3 connected 10923-16383
4f9d051cb178f5078df51eb6e52f1be3ae30a2d2 127.0.0.1:7001@17001 myself,master - 0 1599406449000 1 connected 0-5460
43d57aff953c58a223a528c689ec6a397eb85481 127.0.0.1:7006@17006 slave 4f9d051cb178f5078df51eb6e52f1be3ae30a2d2 0 1599406449938 1 connected
3f468212653a046626e2869aeff46ee9bcb61c4a 127.0.0.1:7004@17004 slave 7fd64ce350df005c963ab355e7e5551b00c6dc7e 0 1599406451954 2 connected以集群方式登錄
-C 代表以集群方式登錄,寫值成功后會自動跳轉到所屬主機,否則就是以正常方式登錄,當寫數據時,可能會提示 hash 計算的槽位,并不屬于當前主機
redis-cli -h 127.0.0.1 -p 7000 -a 123456 -c
127.0.0.1:7000> set k1 v1
-> Redirected to slot [12706] located at 127.0.0.1:7002
OK
127.0.0.1:7002> keys *
1) "k1"
2、擴容和縮容
啟動需要加入集群的節(jié)點
redis-server ./redis7006/redis.conf
redis-server ./redis7007/redis.conf
添加節(jié)點
add-node new_host:new_port existing_host:existing_port --cluster-slave --cluster-master-id <arg>
添加 master 節(jié)點
redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7000 -a 123456
添加 slave 節(jié)點
redis-cli --cluster add-node 127.0.0.1:7007 127.0.0.1:7000 --cluster-slave --cluster-master-id master的ID -a 123456
分配槽位
reshard host:port --cluster-from <arg> --cluster-to <arg> --cluster-slots <arg> --cluster-yes --cluster-timeout <arg> --cluster-pipeline <arg> --cluster-replace
利用導航模式分配,根據提示一步一步完成
要分配的槽位數 -> 接收槽位的 node id -> 分配策略(all / 指定要分出槽位的 node id)-> done -> yes
all:所有節(jié)點平均分配
輸入要分配的 node id -> 繼續(xù)輸入要分配的 node id -> ... -> done
redis-cli --cluster reshard 127.0.0.1:7000 -a 123456刪除節(jié)點
1、先對槽位進行縮容
redis-cli --cluster reshard 127.0.0.1:7000
--cluster-from 要遷移的節(jié)點ID --cluster-to 要接收的節(jié)點ID --cluster-slots 要遷出的槽位數量
2、再進行刪除
刪除的時候,通常都是先刪除從節(jié)點,然后再刪除主節(jié)點,否則會進行故障轉移,發(fā)生不必要的資源浪費
redis-cli --cluster del-node 127.0.0.1:7000 要刪除的節(jié)點ID -a 123456
source: https://www.yuque.com/nashihuakai/qlwgtg/zk5qz7

喜歡,在看
