一:主從模式Windows下搭建
1:基本介紹
主從復制中一個 主節點(master)可以擁有多個 從節點(slave),但是一個slave只能對應一個master。這樣,當某個slave宕機是不會影響其它slave的讀取和master的讀取和寫入;但是之前宕機的slave重新啟動服務后,數據會從自動master上同步過來(前提是在配置文件上配置的主從復制,若是通過命令的方式設置的主從復制,不管哪一台宕機重啟后會都會變為一個普通的單機的Redis,默認都是master)。在主從模式下,只有一個主節點可以寫和讀,而從節點只能讀,所以通常主節點負責寫,從節點負責讀(因為讀取的操作最頻繁)。但是,當唯一的master掛了以后,雖然不影響slave的讀操作,但影響當前主從復制Redis服務的寫操作,需要將master重啟后,redis才重新對外提供寫服務(前提是配置文件配置的主從復制)
2:主從復制優缺點
優點:
①:支持主從復制,主機(Master)會自動將數據同步到從機(Slave),可以進行讀寫分離
②:為了分載Master的讀操作壓力,Slave服務器可以為客戶端提供只讀操作的服務,寫服務仍然必須由Master來完成
③:Slave同樣可以接受其它Slaves的連接和同步請求,這樣可以有效的分載Master的同步壓力。
④:Master Server是以非阻塞的方式為Slaves提供服務。所以在Master-Slave同步期間,客戶端仍然可以提交查詢或修改請求。
⑤:Slave Server同樣是以非阻塞的方式完成數據同步。在同步期間,如果有客戶端提交查詢請求,Redis則返回同步之前的數據
缺點:
①:Redis不具備自動容錯和恢復功能,主機和從機的宕機都會導致前端部分讀寫請求失敗,需要等待機器重啟或者手動切換前端的IP才能恢復。
②:主機宕機,宕機前有部分數據未能及時同步到從機,切換IP后還會引入數據不一致的問題,降低了系統的可用性。
③:Redis較難支持在線擴容,在集群容量達到上限時在線擴容會變得很復雜。
3:配置主從模式
為了方便在 windows 下操作主從復制(Linux和這里Windows操作基本一致后,都是解壓后復制三個出來)
注:要是不會Redis下如何搭建單據Redis請參考 Redis基本操作
環境:
Redis:解壓三份Redis應用(這里我以6.2.5為例)
解壓后的文件夾:
redis6379 用來配置主機Master
redis6380 用來配置從機Slave①
redis6381 用來配置從機Slave②
修改redis6379、redis6380、redis6381下的Redis配置
注:Redis配置文件在Windows下一般為 "redis.windows.conf" 注:Redis配置文件在Windows下一般為 "redis.conf"
①:redis6379主節點(Master)配置文件修改
Redis中的各種配置不明白的請參考 ”“
進入redis6379主節點Master文件夾下修改基本配置
①:指定Redis主節點端口(端口不可沖突)
port:6379
②:指定新的PID文件路徑 (windows下沒有)
pidfile /var/run/redis_6379.pid
③:日志文件位置,當指定為 "空字符串" 為標准輸出。如 redis 以守護進程運行,日志將會輸出到 "/dev/null"
logfile "redisLog_6379.log"
④:RDB持久化快照的的文件名
dbfilename dump6379.rdb
⑤:設置redis連接密碼
requirepass 1234
⑥:保護模式,默認開啟,拒絕外部訪問,建議關閉 -- 設置為:no
protected-mode yes
②:redis6380從節點(Slave①)配置文件修改
進入redis6380從節點Slave①文件夾下修改基本配置
①:指定Redis主節點端口(端口不可沖突)
port:6380
②:指定新的PID文件路徑 (windows下沒有)
pidfile /var/run/redis_6380.pid
③:日志文件位置,當指定為 "空字符串" 為標准輸出。如 redis 以守護進程運行,日志將會輸出到 "/dev/null"
logfile "redisLog_6380.log"
④:RDB持久化快照的的文件名
dbfilename dump6380.rdb
⑤:設置redis連接密碼
requirepass 1234
⑥:保護模式,默認開啟,拒絕外部訪問,建議關閉 -- 設置為:no
protected-mode yes
配置主Master地址
①:主從復制,使用replicaof來指明出Master主節點地址 ,默認關閉
replicaof 127.0.0.1 6379
②:如果Master需要密碼認證,則在這里設置,默認不設置
masterauth 1234
③:redis6381從節點(Slave②)配置文件修改
進入redis6381從節點Slave②文件夾下修改基本配置
①:指定Redis主節點端口(端口不可沖突)
port:6381
②:指定新的PID文件路徑 (windows下沒有)
pidfile /var/run/redis_6381.pid
③:日志文件位置,當指定為 "空字符串" 為標准輸出。如 redis 以守護進程運行,日志將會輸出到 "/dev/null"
logfile "redisLog_6381.log"
④:RDB持久化快照的的文件名
dbfilename dump6381.rdb
⑤:設置redis連接密碼
requirepass 1234
⑥:保護模式,默認開啟,拒絕外部訪問,建議關閉 -- 設置為:no
protected-mode yes
配置主Master地址
①:主從復制,使用replicaof來指明出Master主節點地址 ,默認關閉
replicaof 127.0.0.1 6379
②:如果Master需要密碼認證,則在這里設置,默認不設置
masterauth 1234
4:啟動主從模式
開始三個Redis服務端
注:配置文件和服務放在一個目錄下
創建bat腳本文件:redis服務啟動.bat
@echo off rem 設置我們redis目錄位置 開啟Redis服務端 set redis_home=C:\Users\xiaof\Desktop\redis start cmd /k "cd /d %redis_home%\redis6379 && redis-server.exe redis.windows.conf" start cmd /k "cd /d %redis_home%\redis6380 && redis-server.exe redis.windows.conf" start cmd /k "cd /d %redis_home%\redis6381 && redis-server.exe redis.windows.conf" exit
創建bat腳本文件:redis客戶端啟動.bat
@echo off rem 設置我們redis目錄位置 開啟Redis客戶端 set redis_home=C:\Users\xiaof\Desktop\redis start cmd /k "cd /d %redis_home%\redis6379 && redis-cli.exe -h 127.0.0.1 -p 6379 -a 1234" start cmd /k "cd /d %redis_home%\redis6380 && redis-cli.exe -h 127.0.0.1 -p 6380 -a 1234" start cmd /k "cd /d %redis_home%\redis6381 && redis-cli.exe -h 127.0.0.1 -p 6381 -a 1234" exit
創建bat腳本文件:redis服務端客戶端關閉.bat
@echo off
start cmd /k "taskkill /f /t /im redis-server.exe && taskkill /f /t /im cmd.exe"
exit
5:測試主從復制
到這我們就算成功搭建了主從復制了,在主機上使用set命令也會同步到其它從機,但是從機上不會有寫命令
info replication屬性說明:
role
當前Redis服務器角色(會有Master和slave)
connected_slaves
當前Redis服務器下連接的從機數
slave(N)
從機的連接狀態信息 state=online 代表狀態在線
master_failover_state
主節點的故障轉移狀態,可選值如下:
no-failover:當前沒有正在協調中的故障轉移。
waiting-for-sync:主節點正在等待副本來獲取它的副本數據偏移值。
failover-in-progress:主節點已經降級了,並試圖將所有權移交給目標副本。
master_replid
每次重啟redis產生一個40位的ID,用於主從復制.識別增量的一個標識
master_host、master_port
連接主節點的IP+端口號
master_link_status
連接主節點的狀態 up代表連接 down代表未連接

Master主機配置查看: 127.0.0.1:6379> info replication # Replication role:master connected_slaves:2 slave0:ip=127.0.0.1,port=6381,state=online,offset=438,lag=0 slave1:ip=127.0.0.1,port=6380,state=online,offset=438,lag=0 master_failover_state:no-failover master_replid:e96c06dc1ffde9d13cb7791bdfba36dd26b89794 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:438 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:438 Slave從機配置查看: 127.0.0.1:6380> info replication # Replication role:slave master_host:127.0.0.1 master_port:6379 master_link_status:up master_last_io_seconds_ago:11 master_sync_in_progress:0 slave_repl_offset:410 slave_priority:100 slave_read_only:1 replica_announced:1 connected_slaves:0 master_failover_state:no-failover master_replid:e96c06dc1ffde9d13cb7791bdfba36dd26b89794 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:410 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:410
6:使用命令方式配置主從復制
不推薦使用此方式配置主從,只可用於測試,因為這種方式的配置主從不會持久化,每次關閉再啟動就會變為一個單機
用上邊配置文件搭建案例來說,關閉Redis服務后注釋主機和從機的配置文件配置的 replicaof、masterauth、requirepass
這時候利用腳本啟動的Redis服務都是單機的Master主機
這時候我們可以看出Master原來的主節點里沒有任何從機,下面我將6380、6381設置為從機
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:0
master_failover_state:no-failover
master_replid:a0b02f9a1a0e6a2b24c90a19a7d9c2e5e1f2c96c
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
把Redis6380設置為從節點Slave①: 127.0.0.1:6380> slaveof 127.0.0.1 6379 把Redis6381設置為從節點Slave②: 127.0.0.1:6381> slaveof 127.0.0.1 6379 這時候就設置好主從了 6379為Master主節點;6380、6381為Slave從節點 若其中一台從機想斷開和主機連接則執行:slaveof no one 若主節點宕機則不影響從機的讀取,但是缺少主節點就代表沒有寫功能 若從機宕機后重啟則之前配置為從機的配置被初始化,啟動后默認為單個主機
7:簡單介紹主從復制原理
全量同步:一般發生在Slave連接主機后初始化階段,這時Slave需要將Master上的所有數據都復制一份
①:從服務器連接到主服務器,首先發送一個SYNC命令;
②:主服務器接收到SYNC命名后,主服務器開始執行 bgsave 命令生成RDB文件並使用緩沖區記錄此后執行的所有寫命令;
③:主服務器 bgsave 命令執行完后,向所有從服務器發送快照文件,並在發送期間繼續記錄主服務器被執行的寫命令;
④:從服務器收到快照文件后丟棄所有舊數據,載入收到的快照;
⑤:主服務器快照發送完畢后開始向從服務器發送緩沖區中的寫命令;
⑥:從服務器完成對快照的載入,開始接收命令請求,並執行來自主服務器緩沖區的寫命令;
完成上面幾個步驟后就完成了從服務器數據初始化的所有操作,從服務器此時可以接收來自用戶的讀請求。
增量同步:Redis增量復制是指Slave初始化后開始正常工作時主服務器發生的寫操作同步到從服務器的過程。
增量復制的過程主要是主服務器每執行一個寫命令就會向從服務器發送相同的寫命令,從服務器接收並執行收到的寫命令。
二:主從復制Linux下搭建
通過上面的在Windows下的搭建操作,這里我就不多啰嗦了,直接上手操作搭建
若連在Linux如何搭建單機Redis不怎么熟悉的請參考:Redis入門及環境搭建
具體搭建完主從復制是這個樣子的:
如果想按照我這個目錄快速搭建主從復制可以直接復制下面代碼:
具體步驟: ①:把 redis-6.2.6.tar.gz 壓縮包放到home目錄下解壓 rz -y tar -zxvf redis-6.2.6.tar.gz ②:解壓后進入redis目錄里進行編譯安裝, cd redis-6.2.6/ make && make PREFIX=/home/redis6379 install ③:復制成三份(主從復制 6379主,6380、6381從) cp -r redis6379 redis6380 cp -r redis6379 redis6381 ④:為每個redis創建配置文件目錄和拷貝redis配置文件 mkdir /home/redis6379/conf mkdir /home/redis6380/conf mkdir /home/redis6381/conf cp /home/redis-6.2.6/redis.conf /home/redis6379/conf/redis6379.conf cp /home/redis-6.2.6/redis.conf /home/redis6380/conf/redis6380.conf cp /home/redis-6.2.6/redis.conf /home/redis6381/conf/redis6381.conf ⑤:去編輯每個Redis目錄下的 redis63*.conf 配置文件 具體參考上面Windows下搭建主從復制的第3小節文件配置 ⑥:編寫啟動腳本:startRedis.sh和stopRedis.sh cd /home/ cat > startRedis.sh <<EOF #!/bin/sh /home/redis6379/bin/redis-server /home/redis6379/conf/redis6379.conf 2>&1 & /home/redis6380/bin/redis-server /home/redis6380/conf/redis6380.conf 2>&1 & /home/redis6381/bin/redis-server /home/redis6381/conf/redis6381.conf 2>&1 & echo "redis is start" EOF cat > stopRedis.sh <<EOF #!/bin/sh #stop redis ps -ef|grep redis |grep -v grep|awk '{print }'|xargs kill echo "redis is stop" EOF chmod 744 startRedis.sh stopRedis.sh
接下來就是啟動測試了,測試就按照上面測試即可,啟動則啟動下那個命令即可!
Redis客戶端啟動: /home/redis6379/bin/redis-cli -h 127.0.0.1 -p 6379 -a 1234 /home/redis6380/bin/redis-cli -h 127.0.0.1 -p 6380 -a 1234 /home/redis6381/bin/redis-cli -h 127.0.0.1 -p 6381 -a 1234
然后通過:info replication 命令來查看具體主從服務
通過 tail -f xxx.conf 來實時刷新日志查看
三:哨兵模式Linux下搭建
1:基本介紹
介紹了主從復制后,我們知道slave成為master的從節點后,一旦master主節點宕機,我們可以選擇一個正常的slave成為新的主節點,其它從節點再去連接這個新的主節點,實現手動的故障恢復。但是,人工干預效率低、易出錯,並且故障感知滯后,不具備生產實用性。一個能夠自動感知系統故障、自動故障轉移的可靠組件,肯定是生產環境中最需要的。為此,Redis官方提供一個高可用的解決方案----哨兵(Sentinel),使用它可以搭建一個即使無人干預也能抵抗某些類型失敗的高可用的Redis分布式系統。
哨兵是Redis的一種運行模式,它專注於對Redis實例(主節點、從節點)運行狀態的監控,並能夠在主節點發生故障時通過一系列的機制實現選主及主從切換,實現故障轉移,確保整個Redis系統的可用性。
Redis Sentinel官方文檔
Redis官方中說明了Redis哨兵具備如下幾個功能:
監控(Monitoring):
持續監控Redis主節點、從節點是否處於預期的工作狀態。
通知(Notification):
哨兵可以把Redis實例的運行故障信息通過API通知監控系統或者其他應用程序。
自動故障恢復(Automatic failover):
當主節點運行故障時,哨兵會啟動自動故障恢復流程:某個從節點會升級為主節點,其它從節點會使用新的主節點進行主從復制,
通知客戶端使用新的主節點進行。
配置中心(Configuration provider):
哨兵可以作為客戶端服務發現的授權源,客戶端連接到哨兵請求給定服務的Redis主節點地址。如果發生故障轉移,哨兵會通知新的地址。
這里要注意:哨兵並不是Redis代理,只是為客戶端提供了Redis主從節點的地址信息。
Sentinel的分布式特性:
Redis Sentinel是一個分布式系統,它被設計為基於一套配置,並在多個哨兵實例的配合下工作。多實例共同協作有以下優勢:
①:主節點的系統故障是在多個實例共同認可的情況下完成的,大大降低了誤報的概率。
②:即使不是所有的哨兵實例都正常運行哨兵集群也能正常工作(除非哨兵實例全宕機),這大大增加了系統的穩定性和健壯性。
2:哨兵模式的作用
哨兵服務(sentinel)通過發送命令讓Redis服務器(主服務器和從服務器)返回當前運行狀態;當哨兵監測到master宕機后,哨兵服務會自動將Slave切換成Master ,然后通過發布訂閱模式通知其他的從服務器,修改配置文件,讓它們切換主機;然而一個哨兵進程服務對Redis服務器進行監控,也可能會出現宕機問題,為此,我們可以使用多個哨兵進行監控。各個哨兵之間還會進行監控,這樣就形成了多哨兵模式,就算一個哨兵進程宕機,后面的哨兵還能繼續工作
優點:
哨兵模式是基於主從模式的,所有主從的優點,哨兵模式都具有
主從可以自動切換,系統更健壯,可用性更高
缺點:
Redis較難支持在線擴容,在集群容量達到上限時在線擴容會變得很復雜
3:故障切換過程
假設Master服務器宕機,哨兵A先檢測到這個結果,並不會馬上進行failover(故障轉移)過程,僅僅是哨兵A主觀上認為Master服務器不可用,這個現象成為主觀下線(不能肯定是Master宕機了)。當后面的哨兵B,哨兵C,哨兵D....也檢測到Master服務器不可用,並且隨着多個哨兵服務主觀認為Master宕機且主觀認為的數量達到一定值時,那么哨兵之間就會進行一次投票,投票的結果由一個哨兵發起,進行failover(故障轉移)操作。切換成功后,就會通過發布訂閱模式,讓各個哨兵把自己監控的從服務器實現切換主機,這個過程稱為客觀下線(Master確實是宕機了)。這樣對於客戶端而言,一切都是透明的。
4:哨兵模式的工作方式
①:每個Sentinel(哨兵)進程以每秒鍾一次的頻率向整個集群中的主服務器(Master)、從服務器(Slave)、哨兵(Sentinel)進程
發送一個PING命令。 ②:如果一個實例(instance)距離最后一次有效回復PING命令的時間超過 down-after-milliseconds 選項所指定的值(默認30秒),
這個實例會被Sentinel進程標記為主觀下線(SDOWN) ③:如果一個Master被標記為主觀下線(SDOWN),則正在監視這個Master的所有 Sentinel進程要以每秒一次的頻率確認Master
是否的確進入了主觀下線狀態 ④:當有足夠數量的Sentinel進程(大於等於配置文件指定的值)在指定的時間范圍內確認Master進入了主觀下線狀態(SDOWN),
則主Master會被標記為客觀下線(ODOWN) ⑤:在一般情況下, 每個Sentinel進程會以每10秒一次的頻率向集群中的所有Master主服務器、Slave從服務器發送INFO命令,
目的是發現slave結點,確定主從關系。 ⑥:當Master被Sentinel進程標記為客觀下線(ODOWN)時,Sentinel進程向下線的Master的所有Slave發送INFO命令的頻率會從
10秒一次改為每秒一次。 ⑦:若沒有足夠數量的Sentinel進程同意Master下線,Master的客觀下線狀態就會被移除。若之前被標記的Master重新又向Sentinel進程
發送PING命令返回有效回復,Master主服務器的主觀下線狀態就會被移除。
5:搭建哨兵模式
哨兵模式是基於主從復制模式之上的,所以自己得准備一個基本的一主二從的主從模式環境 注:這里主從搭建完全使用第二小節的:主從復制Linux下搭建里的目錄配置 這里哨兵模式我使用多哨兵模式(都在127.0.0.1機器里): ./redisSentinel26379 此文件夾下存放哨兵A 端口:26379 ./redisSentinel26380 此文件夾下存放哨兵B 端口:26380 ./redisSentinel26381 此文件夾下存放哨兵C 端口:26381 ①:創建文件夾專門存放哨兵模式 mkdir /home/sentinel ②:拷貝3份Redis程序當哨兵程序並復制哨兵配置文件(這里我直接拷貝6379原主從復制主機) cp -r /home/redis6379 /home/sentinel/redisSentinel26379 cp -r /home/redis6379 /home/sentinel/redisSentinel26380 cp -r /home/redis6379 /home/sentinel/redisSentinel26381 rm -rf /home/sentinel/redisSentinel26379/conf/* rm -rf /home/sentinel/redisSentinel26380/conf/* rm -rf /home/sentinel/redisSentinel26381/conf/* cp /home/redis-6.2.6/sentinel.conf /home/sentinel/redisSentinel26379/conf/sentinel26379.conf cp /home/redis-6.2.6/sentinel.conf /home/sentinel/redisSentinel26380/conf/sentinel26380.conf cp /home/redis-6.2.6/sentinel.conf /home/sentinel/redisSentinel26381/conf/sentinel26381.conf ③:編寫哨兵啟動腳本 cd /home/sentinel cat > startRedisSentinel.sh << EOF #!/bin/sh /home/sentinel/redisSentinel26379/bin/redis-sentinel /home/sentinel/redisSentinel26379/conf/sentinel26379.conf 2>&1 & /home/sentinel/redisSentinel26380/bin/redis-sentinel /home/sentinel/redisSentinel26380/conf/sentinel26380.conf 2>&1 & /home/sentinel/redisSentinel26381/bin/redis-sentinel /home/sentinel/redisSentinel26381/conf/sentinel26381.conf 2>&1 & echo "redis sentinel is start" EOF chmod 744 startRedisSentinel.sh
6:更改配置文件
注:每個哨兵的配置文件都必須一致,處理端口和日志文件存在差別,其它一樣都監控某一台主機
①:保護模式,默認開啟,拒絕外部訪問,建議關閉 -- 設置為:no protected-mode no ②:指定新的PID文件路徑 (windows下沒有) pidfile /var/run/redis-sentinel26379.pid ③:日志文件位置 logfile "./redisSentinelLog26379.log" ④:工作目錄(存儲運行時的文件) dir /home/sentinel ⑤:配置監聽的主服務器,這里 sentinel monitor 代表監控 -- mymaster代表服務器名稱,可以自定義 -- 127.0.0.1 6379代表監控的主服務器IP和端口 -- 2代表只有兩個或者兩個以上的哨兵認為主服務器不可用的時候,才會做故障轉移操作 sentinel monitor mymaster 127.0.0.1 6379 2 ⑥:定義連接Master服務的密碼(搭建的主從服務密碼必須一致,要不然有問題) -- mymaster服務名稱(和上面對應) 1234 為密碼 sentinel auth-pass mymaster 1234
7:啟動哨兵測試
注:必須先啟動主從復制機器,確認沒問題后再次啟動多哨兵機器
執行之前腳本啟動:./startRedisSentinel.sh
啟動哨兵日志打印:
啟動26379、26380、26381三台哨兵服務(以26379日志來說,三個日志一樣)
~# oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
~# Redis version=6.2.6, bits=64, commit=00000000, modified=0, pid=9099, just started
~# Configuration loaded
~* Increased maximum number of open files to 10032 (it was originally set to 1024).
~* monotonic clock: POSIX clock_gettime
~* Running mode=sentinel, port=26379.
~# WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
~# Sentinel ID is ae12e9902494e32aa77172ad7900dafb83b29ea4
~# +monitor master mymaster 127.0.0.1 6379 quorum 2 ~* +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379 ~* +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379 ~* +sentinel sentinel dbeba218078a3400c04c0fb2247861be0167e2b8 127.0.0.1 26381 @ mymaster 127.0.0.1 6379 ~* +sentinel sentinel 335d08176477f79734a60420f0b1890303c9aec1 127.0.0.1 26380 @ mymaster 127.0.0.1 6379
使用客戶端連接哨兵服務:
/home/sentinel/redisSentinel26379/bin/redis-cli -h 127.0.0.1 -p 26379
哨兵基本命令:
ping
回復PONG.
sentinel masters
顯示被監控的所有master以及它們的狀態
sentinel master <master name>
顯示指定被監控的master的信息和狀態;如我們設置的名稱為mymaster
sentinel slaves <master name>
顯示指定master的所有slave以及它們的狀態
sentinel get-master-addr-by-name <master name>
返回指定master的ip和端口,如果正在進行failover或者failover已經完成,
將會顯示被提升為master的slave的ip和端口。
sentinel reset <pattern>
重置名字匹配該正則表達式的所有的master的狀態信息,清楚其之前的狀態信息,以及slaves信息
sentinel failover <master name>
強制sentinel執行failover,並且不需要得到其他sentinel的同意。
但是failover后會將最新的配置發送給其他sentinel。
主機宕機模擬:
強行殺死主節點6379服務器后的30秒,哨兵就會進行主節點選舉
哨兵26379日志打印:
~# +sdown master mymaster 127.0.0.1 6379
~# +odown master mymaster 127.0.0.1 6379 #quorum 2/2
~# +new-epoch 1
~# +try-failover master mymaster 127.0.0.1 6379
~# +vote-for-leader ae12e9902494e32aa77172ad7900dafb83b29ea4 1
~# dbeba218078a3400c04c0fb2247861be0167e2b8 voted for ae12e9902494e32aa77172ad7900dafb83b29ea4 1
~# 335d08176477f79734a60420f0b1890303c9aec1 voted for ae12e9902494e32aa77172ad7900dafb83b29ea4 1
~# +elected-leader master mymaster 127.0.0.1 6379
~# +failover-state-select-slave master mymaster 127.0.0.1 6379
~# +selected-slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
~* +failover-state-send-slaveof-noone slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
~* +failover-state-wait-promotion slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
~# +promoted-slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
~# +failover-state-reconf-slaves master mymaster 127.0.0.1 6379
~* +slave-reconf-sent slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379
~* +slave-reconf-inprog slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379
~* +slave-reconf-done slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379
~# -odown master mymaster 127.0.0.1 6379
~# +failover-end master mymaster 127.0.0.1 6379
~# +switch-master mymaster 127.0.0.1 6379 127.0.0.1 6380
~* +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6380
~* +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380
~# +sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380
哨兵26380、26381日志打印(兩個一樣)
~# +sdown master mymaster 127.0.0.1 6379
~# +new-epoch 1
~# +vote-for-leader ae12e9902494e32aa77172ad7900dafb83b29ea4 1
~# +odown master mymaster 127.0.0.1 6379 #quorum 3/2
~# Next failover delay: I will not start a failover before Fri Jan 14 01:16:10 2022
~# +config-update-from sentinel ae12e9902494e32aa77172ad7900dafb83b29ea4 127.0.0.1 26379 @ mymaster 127.0.0.1 6379
~# +switch-master mymaster 127.0.0.1 6379 127.0.0.1 6380
~* +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6380
~* +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380
~# +sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380
通過上面的日志可以看出6379宕機了,但是通過哨兵選舉6380切換為主機,並把它從機設置連接為6380為主機
原主機宕機后上線模擬:
命令切換到home目錄:/home/redis6379/bin/redis-server /home/redis6379/conf/redis6379.conf 2>&1 &
但是啟動6379后日志拼命打印如下日志,並發現連不上哨兵選舉的主機(在Redis服務器有密碼的情況下) ~* Retrying with SYNC... ~# MASTER aborted replication with an error: NOAUTH Authentication required. ~* Reconnecting to MASTER 127.0.0.1:6381 after failure ~* MASTER <-> REPLICA sync started ~* Non blocking connect for SYNC fired the event. ~* Master replied to PING, replication can continue... ~* (Non critical) Master does not understand REPLCONF listening-port: -NOAUTH Authentication required. ~* (Non critical) Master does not understand REPLCONF capa: -NOAUTH Authentication required. ~* Partial resynchronization not possible (no cached master) ~# Unexpected reply to PSYNC from master: -NOAUTH Authentication required. 這時候就得殺死6379 Redis服務后進行簡單配置,在redis6379.conf內找到 masterauth配置主機密碼 masterauth 1234 這個配置在主從復制時就可以配置密碼
哨兵26380日志打印:
~# -sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380
~* +convert-to-slave slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380
~# +sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380
~* +reboot slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380
~# -sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380
哨兵26379、26381日志打印(兩個一樣)
~# -sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380
~# +sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380
~* +reboot slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380
~# -sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380
這時6379的Redis服務就會被當為從機來指向6380哨兵選舉的Redis主機上
8:哨兵日志輸出狀態說明
@
字符之后的內容用於指定主服務器,這些內容是可選的,它們僅在@字符之前的內容指定的
實例不是主服務器時使用
+slave
一個新的從服務器已經被Sentinel識別並關聯。
+sdown
給定的實例現在處於主觀下線狀態。
-sdown
給定的實例已經不再處於主觀下線狀態。
+odown
給定的實例現在處於客觀下線狀態。
-odown
給定的實例已經不再處於客觀下線狀態。
+new-epoch
當前的紀元(epoch)已經被更新。
+try-failover
一個新的故障遷移操作正在執行中,等待被大多數 Sentinel 選中(waiting to be
elected by the majority)
+reset-master
主服務器已被重置
+monitor
主節點已被監視器監控
+failover-state-reconf-slaves
故障轉移狀態切換到了 reconf-slaves 狀態。
+failover-detected
另一個 Sentinel 開始了一次故障轉移操作,或者一個從服務器轉換成了主服務器。
+slave-reconf-sent
領頭(leader)的 Sentinel 向實例發送了 [SLAVEOF](/commands/slaveof.html) 命令,
為實例設置新的主服務器。
+slave-reconf-inprog
實例正在將自己設置為指定主服務器的從服務器,但相應的同步過程仍未完成。
+slave-reconf-done
從服務器已經成功完成對新主服務器的同步。
-dup-sentinel
對給定主服務器進行監視的一個或多個 Sentinel 已經因為重復出現而被移除 —— 當Sentinel實
例重啟的時候,就會出現這種情況。
+sentinel
一個監視給定主服務器的新 Sentinel 已經被識別並添加。
+elected-leader
贏得指定紀元的選舉,可以進行故障遷移操作了。
+failover-state-select-slave
故障轉移操作現在處於 select-slave 狀態 —— Sentinel 正在尋找可以升級為主服務器的從服務器。
no-good-slave
Sentinel 操作未能找到適合進行升級的從服務器。Sentinel 會在一段時間之后再次嘗試尋找合適的
從服務器來進行升級,又或者直接放棄執行故障轉移操作。
selected-slave
Sentinel 順利找到適合進行升級的從服務器。
failover-state-send-slaveof-noone
Sentinel 正在將指定的從服務器升級為主服務器,等待升級功能完成。
failover-end-for-timeout
故障轉移因為超時而中止,不過最終所有從服務器都會開始復制新的主服務器
(slaves will eventually be configured to replicate with the new master anyway)
failover-end
故障轉移操作順利完成。所有從服務器都開始復制新的主服務器了。
+switch-master
配置變更,主服務器的 IP 和地址已經改變。 這是絕大多數外部用戶都關心的信息。
+tilt
進入 tilt 模式。
-tilt
退出 tilt 模式。
四:集群模式Linux下搭建(重點)
Redis 是我們目前大規模使用的緩存中間件,由於它強大高效而又便捷的功能,得到了廣泛的使用。單節點的Redis已經就達到了很高的性能,為了提高可用性我們用主從復制到哨兵再到更強大的Redis集群。
Redis集群(Redis Cluster)是Redis 3.0開始引入的一個分布式存儲系統;Redis集群是一個可以在多個Redis節點之間進行數據共享的設施(installation),不過Redis集群不支持那些需要同時處理多個鍵的Redis命令(如:mset,hmset...), 因為執行這些命令需要在多個Redis節點之間移動數據,並且在高負載的情況下,這些命令將降低Redis集群的性能,並導致不可預測的錯誤。
下面我將詳細介紹Redis集群,主從和哨兵的搭建只是便於理解集群的演變,本節適用3.0~6.0的Redis版本
1:Redis集群介紹
Redis集群通過分區(partition)來提供一定程度的可用性(availability);
即使集群中有一部分節點失效或者無法進行通訊, 集群也可以繼續處理命令請求。
Redis集群提供了以下兩個好處: 將數據自動切分(split)到多個節點的能力,這就是下面說的數據分片。 當集群中的一部分節點失效或者無法進行通訊時,仍然可以繼續處理命令請求的能力。
2:數據分片
Redis集群沒有使用一致性hash(consistency hashing), 而是引入了哈希槽的概念,使用哈希槽來實現數據分片(sharding);一個Redis集群包含16384個哈希槽(hash slot),數據庫中的每個鍵計算后都會在這16384個哈希槽的其中一個槽位上;集群中槽位計算使用公式CRC16(key) % 16384來計算鍵key屬於哪個槽里, 其中 CRC16(key) 語句用於計算鍵key的CRC16校驗和。
集群中的每個節點負責處理一部分哈希槽。舉個例子,一個集群中存在三個Master主節點,那么它最多可以有三個哈希槽, 其中:
節點 A 負責處理 0 號至 5460 號哈希槽。 [5461個槽點]
節點 B 負責處理 5461 號至 10922 號哈希槽。 [5462個槽點]
節點 C 負責處理 10923 號至 16383 號哈希槽。 [5461個槽點]
這種將哈希槽分布到不同節點的做法使得用戶可以很容易地向集群中添加或者刪除節點。
因為添加一個集群Master節點我只需要把前三個Master節點上的槽位里的槽點提出來部分分給新添加上來的Master節點上的槽位里;刪除也差不多,只需要提前把待刪除的主節點Master上的槽點全部提取出來分給其它Master節點上的槽位里,再刪除主節點Master
這時我要添加一個key鍵比如說:設置一個key,叫MyName的key == > set MyName antLaddie
按照Redis Cluster的哈希槽算法,CRC16('MyName') = 45121;45121 % 16384 = 12353 那么這個key就被分配到了節點C上;同樣的,當我連接(A,B,C)的任意一個節點想獲取MyName這個key,都會轉到節點C上;如果用戶將新節點 D 添加到集群中,那么集群只需要將節點 A 、B 、C 中的部分槽移動到節點 D 就可以了。增加一個D節點的結果可能如下(把ABC槽點分部分給D):
節點A覆蓋1365-5460
節點B覆蓋6827-10922
節點C覆蓋12288-16383
節點D覆蓋0-1364,5461-6826,10923-1228
與此類似, 如果用戶要從集群中移除節點 A , 那么集群只需要將節點 A 中的所有哈希槽移動到節點 B 和節點 C ,然后再移除空白(不包含任何哈希槽)的節點 A 就可以了,因為將一個哈希槽從一個節點移動到另一個節點不會造成節點阻塞, 所以無論是添加新節點還是移除已存在節點,又或者改變某個節點包含的哈希槽數量, 都不會造成集群下線。
3:集群主從復制模型
為了使集群在一部分節點下線或者無法與集群的大多數(majority)節點進行通訊的情況下, 仍然可以正常運作, Redis集群對節點使用了主從復制功能;集群中的每個節點都有 1 個至 N 個復制品(replica), 其中一個復制品為主節點(master), 而其余的 N-1 個復制品為從節點(slave)。在之前列舉的節點A 、B 、C的例子中,如果節點 B 下線了(沒有從節點), 那么集群將無法正常運行, 因為集群找不到節點來處理 5461 號至 10922號的哈希槽位。另一方面, 假如在創建集群的時候(或者至少在節點 B 下線之前), 我們為主節點 B 添加了從節點 B1 , 那么當主節點 B 下線的時候,集群就會將 B1 設置為新的主節點, 並讓它代替下線的主節點 B , 繼續處理 5461 號至 10922 號的哈希槽, 這樣集群就不會因為主節點 B 的下線而無法正常運作了。不過如果節點 B 和 B1 都下線的話, Redis 集群還是會停止運作。
總的來說,當某個負責指定插槽槽位的主節點(Master)下線了,並且負責這個槽位內的主從模型范圍內里找不到替代主節點的從機后,整個集群將會置為不可用的狀態;但是可以通過 cluster-require-full-coverage no 來關閉這限制,表示除下線的槽位不可以,其余槽位可正常寫入和讀取
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集群至少需要准備3個主Master節點和3個從Slave節點,總共6個節點才能搭建一套Redis集群,因為6台機器成本太大,所以換成偽集群在一台機器上部署;這里我將介紹 redis3.0~6.0 兩種方式搭建集群
注:若不是工作需求直接使用5.0+版本,直接使用官方自帶的redis-cli -c 來操作集群,不需要在下載Ruby腳本啥的

①:節點說明 127.0.0.1:8001[Master主節點] 127.0.0.1:8004 [Slave從節點] 127.0.0.1:8002[Master主節點] 127.0.0.1:8005 [Slave從節點] 127.0.0.1:8003[Master主節點] 127.0.0.1:8006 [Slave從節點] 127.0.0.1:8007 [后面用來測試擴容] 127.0.0.1:8008 [后面用來測試擴容] 127.0.0.1:8009 [后面用來測試擴容] 127.0.0.1:8010 [后面用來測試擴容] ②:搭建基本環境及BaseRedis(就是一個單機版Redis) cd /home yum -y install cpp binutils glibc glibc-kernheaders glibc-common glibc-devel gcc make gcc-c++ libstdc++-devel tcl # 通過 rz -y 上傳Redis壓縮包 redis-3.2.9.tar.gz 或 redis-6.2.6.tar.gz tar -zxvf redis-3.2.9.tar.gz cd redis-3.2.9/ mkdir -p /usr/local/redisCluster/redisBase/bin make && make PREFIX=/usr/local/redisCluster/redisBase install # 到這我們就有一個基本的Redis程序了,可以用這個redisBase里的命令來搭配不同配置文件批量啟動集群 # 批量集群節點文件夾創建 mkdir -p /usr/local/redisCluster/redis8001 /usr/local/redisCluster/redis8001/etc mkdir -p /usr/local/redisCluster/redis8002 /usr/local/redisCluster/redis8002/etc mkdir -p /usr/local/redisCluster/redis8003 /usr/local/redisCluster/redis8003/etc mkdir -p /usr/local/redisCluster/redis8004 /usr/local/redisCluster/redis8004/etc mkdir -p /usr/local/redisCluster/redis8005 /usr/local/redisCluster/redis8005/etc mkdir -p /usr/local/redisCluster/redis8006 /usr/local/redisCluster/redis8006/etc mkdir -p /usr/local/redisCluster/redis8007 /usr/local/redisCluster/redis8007/etc mkdir -p /usr/local/redisCluster/redis8008 /usr/local/redisCluster/redis8008/etc mkdir -p /usr/local/redisCluster/redis8009 /usr/local/redisCluster/redis8009/etc mkdir -p /usr/local/redisCluster/redis8010 /usr/local/redisCluster/redis8010/etc # 為每個節點文件夾里面放一個Redis配置文件 cp /home/redis-3.2.9/redis.conf /usr/local/redisCluster/redis8001/etc/redisNodes_8001.conf cp /home/redis-3.2.9/redis.conf /usr/local/redisCluster/redis8002/etc/redisNodes_8002.conf cp /home/redis-3.2.9/redis.conf /usr/local/redisCluster/redis8003/etc/redisNodes_8003.conf cp /home/redis-3.2.9/redis.conf /usr/local/redisCluster/redis8004/etc/redisNodes_8004.conf cp /home/redis-3.2.9/redis.conf /usr/local/redisCluster/redis8005/etc/redisNodes_8005.conf cp /home/redis-3.2.9/redis.conf /usr/local/redisCluster/redis8006/etc/redisNodes_8006.conf cp /home/redis-3.2.9/redis.conf /usr/local/redisCluster/redis8007/etc/redisNodes_8007.conf cp /home/redis-3.2.9/redis.conf /usr/local/redisCluster/redis8008/etc/redisNodes_8008.conf cp /home/redis-3.2.9/redis.conf /usr/local/redisCluster/redis8009/etc/redisNodes_8009.conf cp /home/redis-3.2.9/redis.conf /usr/local/redisCluster/redis8010/etc/redisNodes_8010.conf
基本的文件創建好,我們就要修改每個節點的配置文件了,然后和一鍵啟動腳本即可
①:修改每個節點下的配置文件,如下示例,其它文件只需要套用此配置,把8001批量替換800* 具體替換的vim命令 :%s/源字符串/目標字符串/g # 端口號 port 8001
# 設置外部任何IP都可以連接,或者設置指定IP連接 用 "-" 分割
bind 0.0.0.0 或 * 新版本設置:bind * -::* # 后台啟動 daemonize yes # 指定數據文件存放發位置,必須指定不同的目錄位置,不然會丟失運行的一些數據,比如日志,持久化文件等 dir /usr/local/redisCluster/redis8001 # 指定新的PID進程文件路徑 (windows下沒有)當 daemonize yes為守護進程時必須設置 pidfile /var/run/redisNodes_8001.pid # 日志文件名稱 logfile "/usr/local/redisCluster/redis8001/redisNodes_8001.log" # RDB持久化快照的的文件名 dbfilename dumpNodes_8001.rdb # 開啟aof 注同時開啟AOF和RDB時當Redis重啟時,會優先使用AOF文件來還原數據集,若考慮性能則可以關閉aof appendonly yes # aof文件路徑 appendfilename "appendonly_8001.aof" # 是否開啟集群(必須開啟) cluster-enabled yes #集群節點配置文件 cluster-config-file nodes-8001.conf # 集群連接超時時間 cluster-node-timeout 5000 ②:創建Redis集群啟動腳本 RedisClusterStart.sh 這里的 8007 8008 8009 8010雖然啟動,但是不使用,后面擴容使用 cat > RedisClusterStart.sh << EOF #!/bin/sh /usr/local/redisCluster/redisBase/bin/redis-server /usr/local/redisCluster/redis8001/etc/redisNodes_8001.conf /usr/local/redisCluster/redisBase/bin/redis-server /usr/local/redisCluster/redis8002/etc/redisNodes_8002.conf /usr/local/redisCluster/redisBase/bin/redis-server /usr/local/redisCluster/redis8003/etc/redisNodes_8003.conf /usr/local/redisCluster/redisBase/bin/redis-server /usr/local/redisCluster/redis8004/etc/redisNodes_8004.conf /usr/local/redisCluster/redisBase/bin/redis-server /usr/local/redisCluster/redis8005/etc/redisNodes_8005.conf /usr/local/redisCluster/redisBase/bin/redis-server /usr/local/redisCluster/redis8006/etc/redisNodes_8006.conf /usr/local/redisCluster/redisBase/bin/redis-server /usr/local/redisCluster/redis8007/etc/redisNodes_8007.conf /usr/local/redisCluster/redisBase/bin/redis-server /usr/local/redisCluster/redis8008/etc/redisNodes_8008.conf /usr/local/redisCluster/redisBase/bin/redis-server /usr/local/redisCluster/redis8009/etc/redisNodes_8009.conf /usr/local/redisCluster/redisBase/bin/redis-server /usr/local/redisCluster/redis8010/etc/redisNodes_8010.conf echo "redis is start" EOF chmod 744 RedisClusterStart.sh
這時我們就把10個節點的Redis啟動了,此時的Redis都是以集群模式啟動了,只是現在沒有讓它們之間集群關聯
6:Redis集群關聯(原生)
集群的搭建可以分為四步:
①:啟動節點:將節點以集群模式啟動,此時節點是獨立的,並沒有建立聯系;[上一小節已啟動]
②:節點握手:讓獨立的節點連成一個網絡;
③:分配槽:將16384個槽分配給主節點;
④:指定主從關系:為從節點指定主節點。
注:這里我只使用 8001 ~ 8006 其中 8001 ~ 8003為Master主節點,要分配槽的,8004 ~ 8006 為Slave從節點
1:節點握手
我們上面的10個節點啟動以后是相互獨立的,並不知道其它節點的存在;需要進行節點握手,將獨立的節點組成一個網絡。節點握手使用 cluster meet {ip} {port} 命令實現,例如在8001節點中執行 cluster meet 10.200.157.126 8002,可以完成8001節點和8002節點的握手;注意ip使用的是局域網ip而不是 localhost 或127.0.0.1,是為了其他機器上的節點或客戶端也可以訪問。可使用cluster nodes查看
以集群模式連接8001節點:(這里一定要加 -c 以集群模式啟動)
/usr/local/redisCluster/redisBase/bin/redis-cli -c -h 10.200.157.126 -p 8001
查看當前節點:(此時8001就單獨一個節點集群)
10.200.157.126:8001> cluster nodes
3a00331cad40d52e5755c22699668574e090fa7e :8001 myself,master - 0 0 0 connected
在 8001 節點下使用Cluster meet 命令把所有節點加入到集群,完成節點握手:
cluster meet 10.200.157.126 8002
cluster meet 10.200.157.126 8003
cluster meet 10.200.157.126 8004
cluster meet 10.200.157.126 8005
cluster meet 10.200.157.126 8006

2:分配槽
在Redis集群中,借助槽實現數據分區。集群有16384個槽,槽是數據管理和遷移的基本單位。當數據庫中的16384個槽都分配了節點時,集群處於上線狀態(ok);如果有任意一個槽沒有分配節點,則集群處於下線狀態(fail)。cluster info命令可以查看集群狀態,分配槽之前狀態為fail;
未分配完(或未分配)槽點:
10.200.157.126:8001> cluster info
cluster_state:fail 【集群狀態fail失敗 ok 成功】
cluster_slots_assigned:0 【當前整個集群分配的插槽點數,未到16384是無法啟動的】
通過redis_cli客戶端命令為 8001 ~ 8003 分配插槽 【每個節上的插槽隨便分配點數,這里我就平均分配】
/usr/local/redisCluster/redisBase/bin/redis-cli -p 8001 cluster addslots {0..5460} /usr/local/redisCluster/redisBase/bin/redis-cli -p 8002 cluster addslots {5461..10922} /usr/local/redisCluster/redisBase/bin/redis-cli -p 8003 cluster addslots {10923..16383}
分配完槽點顯示正常:
10.200.157.126:8001> cluster info
cluster_state:ok
cluster_slots_assigned:16384
3:指定主從關系
集群中指定主從關系就不再使用slaveof命令了,而是使用 cluster replicate 命令;參數使用節點ID
從分配插槽時就已經確定了主節點Master了,因為只有主節點才可以分配插槽,下面我將從機連接到主機上 Master 8001 --> Slave 8004 Master 8002 --> Slave 8005 Master 8003 --> Slave 8006 隨便進入一個集群節點查詢當前的全部集群ID,用來分配主從關系,這里我就進入8001節點查看
開始分配主從: cd /usr/local/redisCluster/redisBase/bin/ ./redis-cli -p 8004 cluster replicate 3a00331cad40d52e5755c22699668574e090fa7e ./redis-cli -p 8005 cluster replicate 72cfe73954d8dc94f3ba0a3910885fccf1a26aba ./redis-cli -p 8006 cluster replicate 372db80734eaf94f4edeab82ab3b8e5ba4bc40d6
測試:
10.200.157.126:8001> set name zhangsan
-> Redirected to slot [5798] located at 10.200.157.126:8002
OK
【↑↑ 此時計算出name屬於5798槽點,所以在8002,這是自動切換到8002節點保存】
10.200.157.126:8002> set age 22
-> Redirected to slot [741] located at 10.200.157.126:8001
OK
【↑↑ 此時計算出age屬於741槽點,所以在8001,這是自動切換到8001節點保存】
7:Redis集群關聯(Ruby腳本搭建 Redis-trib)
除了使用原生的方式,我們還可以使用Ruby腳本來搭建集群,不過在搭建前需要下載依賴ruby和rubygems;下載完我們就可以通過redis-trib.rb的Ruby腳本文件實現自動化的集群搭建
①:下載依賴ruby和rubygems:yum -y install ruby rubygems ②:安裝redis和ruby的接口:gem install redis
Redis5.0.0以上版本就不推薦使用此方式了,因為有更好的 redis-cli 方式

當你出現了這種情況就需要按照如下步驟解決: 》》[root@MiWiFi-IR1200G-srv redisCluster]# gem install redis 》》Fetching: redis-4.5.1.gem (100%) 》》ERROR: Error installing redis: 》》 redis requires Ruby version >= 2.4.0. 【說的是需要2.4及2.4以上的Ruby版本】 解決方案: ①:安裝curl yum install curl ②:安裝rvm curl -L get.rvm.io | bash -s stable 這時候可能會出現問題: curl: (7) Failed connect to raw.githubusercontent.com:443; 拒絕連接 我們需要修改hosts文件:sudo vim /etc/hosts 然后把 199.232.28.133 raw.githubusercontent.com 復制加到hosts文件的最后一行 然后再執行 curl -L get.rvm.io | bash -s stable ③:刷新rvm文件 source /usr/local/rvm/scripts/rvm ⑤:查看rvm庫中已知的ruby版本 rvm list known ⑥:安裝一個ruby版本 rvm install 2.6.3 ⑦:使用一個ruby版本 並設置為默認版本 rvm use 2.6.3 ruby --version ⑧:卸載一個已知版本 rvm remove 2.0.0 ⑨:安裝最初出問題的命令 [root@MiWiFi-IR1200G-srv redisCluster]# gem install redis Fetching redis-4.5.1.gem Successfully installed redis-4.5.1 Parsing documentation for redis-4.5.1 Installing ri documentation for redis-4.5.1 Done installing documentation for redis after 0 seconds 1 gem installed
此時此刻我們就可以使用 redis-trib.rb 來搭建集群了
把我們之前解壓編譯的redis里的 redis-trib.rb 文件拷貝到我們的redisBase基本命令文件夾里
cp /home/redis-3.2.9/src/redis-trib.rb /usr/local/redisCluster/redisBase/bin/
## 注不要出現空格
/usr/local/redisCluster/redisBase/bin/redis-trib.rb create --replicas 1 10.200.157.126:8001 10.200.157.126:8002 10.200.157.126:8003 10.200.157.126:8004 10.200.157.126:8005 10.200.157.126:8006
說明:
create:這表示我們希望創建一個新的集群
--replicas 1:代表比例,就是主節點數/從節點數比例
1:代表 1/1=1 說明1Master 1Slave 假設20個Redis節點就代表集群里存在10個主從,每個Master下面存在1個Slave
0.5:代表 1/2 說明1Master 2Slave 假設15個Redis節點就代表集群里存在5個主從,每個Master下面存在2個Slave
集群的創建是按照順序來的,比如 1 那么上面的例子就是前3為Master,后3為Slave,和前面一一對應
搭建成功記得測試喲!

8:Redis集群關聯(redis-cli官方工具搭建)
若Redis是5.0以上版本,那么搭建Redis集群就簡單多了,我們可以直接使用redis-cli就可以快速進行集群搭建;
注:Redis5.0以下使用上面介紹的方法redis-trib.rb
[root@MiWiFi-IR1200G-srv redisCluster]# cd /usr/local/redisCluster/redisBase/bin/ [root@MiWiFi-IR1200G-srv bin]# ./redis-cli --cluster create --cluster-replicas 1 192.168.31.51:8001 192.168.31.51:8002 192.168.31.51:8003 192.168.31.51:8004 192.168.31.51:8005 192.168.31.51:8006 基本參數介紹:
--cluster
指定是用於創建集群環境
--cluster-replicas
用於指定主節點上從節點數,1代表1主1從,2代表1主2從;
注:主機必須大於等於三台,那設置2從機就代表至少准備9台節點,三個1主2從
-a
若存在密碼則通過這個設置(前提得一樣)
{IP}:{端口}...
代表哪些集群組成集群

我們也可以使用:./redis-cli --cluster check 127.0.0.1:8001 查看集群狀態
9:Redis集群的基本連接及節點下線
這里我們就使用官方自帶的 redis-cli 來連接集群,但是注意的是必須加上 -c 參數,代表我們是以集群方式連接,這里我就以8001來進行測試
# 連接 8001 主節點端口(因為連接從節點Slave無法寫操作,所以不連那個測試)
[root@MiWiFi-IR1200G-srv bin]# ./redis-cli -c -h 127.0.0.1 -p 8001
127.0.0.1:8001> set name zhangsan
-> Redirected to slot [5798] located at 192.168.31.51:8002
OK
【↑↑ 此時計算出name屬於5798槽點,所以在8002,這是自動切換到8002節點保存】
192.168.31.51:8002> set age 22
-> Redirected to slot [741] located at 192.168.31.51:8001
OK
【↑↑ 此時計算出age屬於741槽點,所以在8001,這是自動切換到8001節點保存】
192.168.31.51:8001> keys *
1) "age"
【↑↑ 此時在8001插槽里,所以在只能查詢到8001槽點下的全部數據】
192.168.31.51:8001> set height 180
-> Redirected to slot [8223] located at 192.168.31.51:8002
OK
【↑↑ 此時計算出height屬於8223槽點,所以在8002,這是自動切換到8002節點保存】
192.168.31.51:8002> keys *
1) "height"
2) "name"
【↑↑ 此時在8001插槽里,所以在只能查詢到8001槽點下的全部數據】
192.168.31.51:8002> get age
-> Redirected to slot [741] located at 192.168.31.51:8001
"22"
【↑↑ 計算age鍵在8001下,所以跳轉過去取值】
192.168.31.51:8001> get name
-> Redirected to slot [5798] located at 192.168.31.51:8002
"zhangsan"
【↑↑ 計算age鍵在8002下,所以跳轉過去取值】
192.168.31.51:8002>
【↑↑ 最終在8002節點下】
測試8001的這個Master主節點宕機
案例中我們集群是三個主節點Master[8001~8003]和三個從節點[8004~8006];這時候我把8001宕機,那么8004從機會頂上來的當主機
①:使用kill強行殺死一個8001節點的RedisCluster ②:使用redis-trib.rb的檢查命令來查看當前集群的狀態(注:必須連接一個在線的主或從節點)
[root@MiWiFi-IR1200G-srv bin]# /usr/local/redisCluster/redisBase/bin/redis-trib.rb check 127.0.0.1:8006
>>> Performing Cluster Check (using node 127.0.0.1:8006)
S: 9b868e59ccf602258d079339aa51d7335d637e8d 127.0.0.1:8006
slots: (0 slots) slave
replicates 0a8967caa61cc159a99d409ebe61a73c7ade16cf
S: 2293234155950a91541f1a3a64884a89fce6c469 192.168.31.51:8005
slots: (0 slots) slave
replicates 51ede3997f64d139fb66810df132c67fc1fffe2f
M: 51ede3997f64d139fb66810df132c67fc1fffe2f 192.168.31.51:8002
slots:5461-10922 (5462 slots) master
1 additional replica(s)
M: 0a8967caa61cc159a99d409ebe61a73c7ade16cf 192.168.31.51:8003
slots:10923-16383 (5461 slots) master
1 additional replica(s)
M: e7f4ae2d2a7f7c48b37b4273de572405caec9f91 192.168.31.51:8004 slots:0-5460 (5461 slots) master 0 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
開頭的S代表Slave M代表Master 8001下線后發現8004主動擔起主節點的重任
注:若沒有 redis-trib.rb 的可以使用 redis-cli 程序來連接查看狀態
/usr/local/redisCluster/redisBase/bin/redis-cli -c -h 127.0.0.1 -p 8006
127.0.0.1:8006>cluster nodes
測試8001的這個主節點上線
①:使用8001的配置文件來啟動8001節點
[root@MiWiFi-IR1200G-srv bin]# cd /usr/local/redisCluster/redisBase/bin/
[root@MiWiFi-IR1200G-srv bin]# ./redis-server /usr/local/redisCluster/redis8001/etc/redisNodes_8001.conf ②:檢查集群狀況
[root@MiWiFi-IR1200G-srv bin]# /usr/local/redisCluster/redisBase/bin/redis-trib.rb check 127.0.0.1:8006
>>> Performing Cluster Check (using node 127.0.0.1:8006)
S: 9b868e59ccf602258d079339aa51d7335d637e8d 127.0.0.1:8006
slots: (0 slots) slave
replicates 0a8967caa61cc159a99d409ebe61a73c7ade16cf
S: 2293234155950a91541f1a3a64884a89fce6c469 192.168.31.51:8005
slots: (0 slots) slave
replicates 51ede3997f64d139fb66810df132c67fc1fffe2f
M: 51ede3997f64d139fb66810df132c67fc1fffe2f 192.168.31.51:8002
slots:5461-10922 (5462 slots) master
1 additional replica(s)
M: 0a8967caa61cc159a99d409ebe61a73c7ade16cf 192.168.31.51:8003
slots:10923-16383 (5461 slots) master
1 additional replica(s)
S: 3b5a75e7f60745a59864aa4600e454be49b5d240 192.168.31.51:8001 slots: (0 slots) slave replicates e7f4ae2d2a7f7c48b37b4273de572405caec9f91
M: e7f4ae2d2a7f7c48b37b4273de572405caec9f91 192.168.31.51:8004
slots:0-5460 (5461 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.
此時8001節點上線時只能當個從機了,因為8004節點之前謀權篡位了,只有等8004下線后8001才會成為主節點
測試8004主節點和8001從節點這一個小的主從全部宕機
通過ps -ef | grep redis 查看進程並使用 kill 關閉了8001和8004兩個節點,此時按照默認配置,此集群是無法正常使用的了,這時只能讓人為參與,啟動宕機的機器;或者把宕機的那一部分插槽轉移到其它好的主節點上,這樣集群就會存在兩個主節點了;
這是我們就需要把8001、8004給重啟一下,這里我為了方便,直接把全部Redis進程殺死並重新執行腳本
# 殺死Redis全部進程
kill -9 `ps -ef | grep redis | grep -v grep | awk '{print $2}'`
# 啟動腳本啟動全部Redis(包括)
/usr/local/redisCluster/RedisClusterStart.sh
從下面開始我將介紹redis-trib方式(3.0 >= redis <5.0)和redis-cli(redis >= 5.0)兩種方式來操作集群;推薦使用redis-cli
老版本使用redis-trib方式,新版本使用redis-cli(推薦)
10:集群增加主節點(redis-trib方式)
我們可以看出之前我一直啟動着8007~8010這四台機器,就是用來后面的擴容做准備,這時我將8007加入到集群中並設置主節點Master;我們可以通過redis-trib的add node指令加入節點
# 使用redis-trib.rb的add-node指令 # redis-trib.rb add-node {待加入集群的IP:端口} {已存在集群中的任意節點IP:端口} [root@localhost redisCluster]# cd /usr/local/redisCluster/redisBase/bin/ [root@localhost bin]# ./redis-trib.rb add-node 10.200.157.141:8007 10.200.157.141:8001
此時此刻我們已經把主節點加入到集群了,這時加入的8007Master是一個(slots: (0 slots) master);所以要想使用就必先分配插槽,
從8001~8003里面隨便分一點給8007;分配使用redis-trib.rb的reshard指令重新分片; 注:這個IP和端口連接任意的都可以,只要能進入集群 [root@localhost bin]# ./redis-trib.rb reshard 10.200.157.141:8005
How many slots do you want to move (from 1 to 16384)? 4096 【回車】
(提示我們要移動多少個插槽(從1到16384);我們可以均勻分配 16384/4=4096所以我們就填寫4096,若均勻下來存在小數我們就取個整就行)
(建議分配盡量均勻,相差太大可能會有問題(相差幾十都還行),這是我的小建議,出了那問題老麻煩了)
What is the receiving node ID? d9859d6acf261106cd1c8d5d7ce47c0425250dff 【回車】
(提示我們把這4096個插槽點分給那個MasterID )
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.
Source node #1: all 【回車】
(提示我們redis-trib.rb會向你詢問重新分片的源節點(source node), 也即是說要從哪個節點中取出 4096 個哈希槽,並將這些槽移動 到8007節點上面。如果我們不打算從特定的節點上取出指定數量的哈希槽, 那么可以向 redis-trib輸入all,這樣的話, 集群中的所有主節點 都會成為源節點, redis-trib.rb將從各個源節點中各取出一部分哈希槽,湊夠4096個, 然后移動到7006節點上)
Do you want to proceed with the proposed reshard plan (yes/no)? yes 【回車】
(是否要繼續提議的重新分片計划)

11:集群增加主節點(redis-cli方式)
這里我需要添加一個8007節點,默認添加就為主節點Master
[root@MiWiFi-IR1200G-srv bin]# ./redis-cli --cluster add-node 192.168.31.51:8007 192.168.31.51:8002
add-node {待添加IP}:{待添加端口} {已存在IP}:{已存在端口}

分配插槽給8007【平均分配】
[root@MiWiFi-IR1200G-srv bin]# ./redis-cli --cluster rebalance --cluster-threshold 1 --cluster-use-empty-masters 192.168.31.51:8007
分配【手動分配】
./redis-cli --cluster reshard --cluster-from all --cluster-to {需要分配槽點的ID} --cluster-slots {分配的槽點} --cluster-yes 127.0.0.1:8001
12:集群增加從節點(redis-trib方式)
增加一個8008節點來作為8007主節點的從機
和添加主節點一樣,但是加上 --slave 就代表添加的是從節點;
注:但是這里未指定添加到哪台主節點下,只是配置了個10.200.157.141:8001讓其加入到某個集群 這時redis-trib.rb就會將8008從節點添加到從節點較少的主節點Master上(這里顯然就添加到8007Master上)
[root@localhost bin]# cd /usr/local/redisCluster/redisBase/bin/
[root@localhost bin]# ./redis-trib.rb add-node --slave 10.200.157.141:8008 10.200.157.141:8001

但是話說回來,我不想讓redis-trib來分配從節點到任意一個主節點下,我要自己手動指定到主節點Master下, 這里我准備將8009未分配到集群的節點分配給8003主節點下 這里的 --master-id 代表指定的主節點node id [root@localhost bin]# cd /usr/local/redisCluster/redisBase/bin/ [root@localhost bin]# ./redis-trib.rb add-node --slave --master-id aec1bb289da5fed2159ccb3217d2aec03ba47709 10.200.157.141:8009 10.200.157.141:8002 
13:集群增加從節點(redis-cli方式)
這里我就把8008添加到8007節點下(8007就是剛剛我們添加的主節點)
[root@MiWiFi-IR1200G-srv bin]# ./redis-cli --cluster add-node --cluster-slave --cluster-master-id a669b1cb86c103eb08e527fc6ff6a489f7fb2904 192.168.31.51:8009 192.168.31.51:8003 --cluster-slave:加入的是從節點 --cluster-master-id:后面設置要連接誰當主節點;這里設置ID
14:集群移除一個主節點(redis-trib方式)
我現在的需求時移除8007主節點,但移除主節點前,我們必須先把當前待移除的8007主節點里的全部插槽移除出去,也就是要重新分片
這里我就把8007里的全部插槽移出去,移動到8003主節點上
這里的 del-node 指令代表移除節點;d9859d6acf261106cd1c8d5d7ce47c0425250dff代表移除的8007節點ID
[root@localhost bin]# cd /usr/local/redisCluster/redisBase/bin/ [root@localhost bin]# ./redis-trib.rb del-node 10.200.157.141:8002 d9859d6acf261106cd1c8d5d7ce47c0425250dff >>> Removing node d9859d6acf261106cd1c8d5d7ce47c0425250dff from cluster 10.200.157.141:8002 [ERR] Node 10.200.157.141:8007 is not empty! Reshard data away and try again. 【報錯 >>> 從集群 10.200.157.141:8002 中刪除節點 d9859d6acf261106cd1c8d5d7ce47c0425250dff】 【報錯[ERR] 節點 10.200.157.141:8007 不為空(就是8007節點里存在插槽)! 重新分片數據,然后重試。】
# 重新分片 注:這個IP和端口連接任意的都可以,只要能進入集群
[root@localhost bin]# ./redis-trib.rb reshard 10.200.157.141:8002
How many slots do you want to move (from 1 to 16384)? 4096
(這里我就移動4096個插槽點)
What is the receiving node ID? aec1bb289da5fed2159ccb3217d2aec03ba47709
(把這4096個插槽點移動到誰的主節點上,這里我移動到8003主節點上)
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.
Source node #1:d9859d6acf261106cd1c8d5d7ce47c0425250dff
Source node #2:done
(說的是我要從哪個主節點ID里分配這4096個插槽點,若設置all的話就會平均每個都抽出來一點插槽) (但這我明確指出從8007節點里移動插槽到8003;;done結束設置)
Do you want to proceed with the proposed reshard plan (yes/no)? yes 【回車】

15:集群移除一個主/從節點(redis-cli方式)
刪除節點和上面一節邏輯一樣
①:對當前集群進行重新分片,把待刪除的主機上的全部插槽移動到其它主節點下
./redis-cli --cluster reshard {集群內任意IP}:{集群內任意端口}
==>具體的參考上面和 ./redis-trib.rb reshard 10.200.157.141:8002 一樣
②:刪除節點(這里刪除主節點和從節點命令一樣)
./redis-cli --cluster del-node {集群內任意IP}:{集群內任意端口} {待刪除的ID}
16:集群移除一個從節點(redis-trib方式)
我現在要移除8009從節點,因為它是從節點也沒有插槽,所以直接移除
[root@localhost bin]# ./redis-trib.rb del-node 10.200.157.141:8002 7aab013e8257fce39bdcd36cad9320cd4265ef21
>>> Removing node 7aab013e8257fce39bdcd36cad9320cd4265ef21 from cluster 10.200.157.141:8002
>>> Sending CLUSTER FORGET messages to the cluster...
>>> SHUTDOWN the node.
.