1.Redis持久化機制
Redis設計了兩種持久化落盤機制:RDB和AOF
1.1 RDB持久化
RDB持久化是Redis的數據快照,簡單來說就是把內存中的所有數據都記錄到磁盤中,當Redis實例故障重啟后,從磁盤中讀取快照文件來恢復數據。快照文件稱為RDB文件,默認保存在當前運行目錄。
觸發時機:
RDB持久化在四種情況下會執行:
執行save命令:
執行下面的命令,可以立即執行一次RDB:
save命令會導致主進程執行RDB,這個過程中其它所有命令都會被阻塞。只有在數據遷移時可能用到。
執行bgsave命令:
下面的命令可以異步執行RDB:
這個命令執行后會開啟獨立進程完成RDB,主進程可以持續處理用戶請求,不受影響。
Redis停機時:
Redis停機時會執行一次save命令,實現RDB持久化。
觸發RDB條件時:
Redis內部有觸發RDB的機制,可以在redis.conf文件中找到,格式如下:
# 900秒內,如果至少有1個key被修改,則執行bgsave , 如果是save "" 則表示禁用RDB
save 900 1 ?
save 300 10 ?
save 60 10000
RDB的其它配置也可以在redis.conf文件中設置:
# 是否壓縮 ,建議不開啟,壓縮也會消耗cpu,磁盤的話不值錢
rdbcompression yes
?
# RDB文件名稱
dbfilename dump.rdb ?
?
# 文件保存的路徑目錄
dir ./
RDB原理
bgsave開始會fork主進程得到子進程,子進程共享主進程的內存數據,完成fork后讀取內存數據并寫入RDB文件中。
注:我們的進程是無法直接訪問到物理內存中,物理內存會有對應的虛擬內存頁表,進程通過訪問操作頁表的內存來間接實際操作物理內存,而子進程fork的就是主進程操作的頁表。
fork采用的是copy-on-write技術:
- 當主進程執行讀操作時,訪問共享內存;
- 當主進程執行寫操作時,則會拷貝一份數據,執行寫操作。
小結
RDB方式bgsave的基本流程?
- fork主進程得到一個子進程,共享內存空間
- 子進程讀取內存數據并寫入新的RDB文件
- 用新RDB文件替換舊的RDB文件
RDB會在什么時候執行?save 60 1000代表什么含義?
- 默認是服務停止時
- 代表60秒內至少執行1000次修改則觸發RDB
RDB的缺點?
- RDB執行間隔時間長,兩次RDB之間寫入數據有丟失的風險
- fork子進程、壓縮、寫出RDB文件都比較耗時
1.2?AOF持久化
Redis處理的每一個命令都會記錄在AOF文件中,可以看作是命令日志文件。
AOF默認是關閉的,需要修改redis.conf配置文件來開啟AOF:
# 是否開啟AOF功能,默認是no
appendonly yes
# AOF文件的名稱
appendfilename "appendonly.aof"
AOF的命令記錄的頻率也可以通過redis.conf文件來配:
# 表示每執行一次寫命令,立即記錄到AOF文件
appendfsync always
# 寫命令執行完先放入AOF緩沖區,然后表示每隔1秒將緩沖區數據寫到AOF文件,是默認方案
appendfsync everysec
# 寫命令執行完先放入AOF緩沖區,由操作系統決定何時將緩沖區內容寫回磁盤
appendfsync no
三種策略對比:
因為是記錄命令,AOF文件會比RDB文件大的多。而且AOF會記錄對同一個key的多次寫操作,但只有最后一次寫操作才有意義。通過執行bgrewriteaof命令,可以讓AOF文件執行重寫功能,用最少的命令達到相同效果。
Redis也會在觸發閾值時自動去重寫AOF文件。閾值也可以在redis.conf中配置:
RDB和AOF各有自己的優缺點,如果對數據安全性要求較高,在實際開發中往往會結合兩者來使用。
2.Redis主從集群
單節點Redis的并發能力是有上限的,要進一步提高Redis的并發能力,就需要搭建主從集群,實現讀寫分離。
2.1 主從集群搭建
我們搭建的主從集群結構共包含三個節點:一個主節點,兩個從節點
我們開啟3個Redis實例,模擬主從集群:
IP | PORT | 角色 |
---|---|---|
192.168.150.101 | 7001 | master |
192.168.150.101 | 7002 | slave |
192.168.150.101 | 7003 | slave |
我們在同一臺機器上開啟三個Redis實例,備份三份不同的配置文件和目錄,配置文件所在目錄也就是工作目錄。
1)創建目錄
我們創建三個文件夾,名字分別叫7001、7002、7003:
# 進入/tmp目錄
cd /tmp
# 創建目錄
mkdir 7001 7002 7003
如圖:
2)恢復原始配置
修改redis-6.2.4/redis.conf文件,將其中的持久化模式改為默認的RDB模式,AOF保持關閉狀態。
# 開啟RDB
# save ""
save 3600 1
save 300 100
save 60 10000
?
# 關閉AOF
appendonly no
3)拷貝配置文件到每個實例目錄
然后將redis-6.2.4/redis.conf文件拷貝到三個目錄中(在/tmp目錄執行下列命令):
# 方式一:逐個拷貝
cp redis-6.2.4/redis.conf 7001
cp redis-6.2.4/redis.conf 7002
cp redis-6.2.4/redis.conf 7003
?
# 方式二:管道組合命令,一鍵拷貝
echo 7001 7002 7003 | xargs -t -n 1 cp redis-6.2.4/redis.conf
4)修改每個實例的端口、工作目錄
修改每個文件夾內的配置文件,將端口分別修改為7001、7002、7003,將rdb文件保存位置都修改為自己所在目錄(在/tmp目錄執行下列命令):
sed -i -e 's/6379/7001/g' -e 's/dir .\//dir \/tmp\/7001\//g' 7001/redis.conf
sed -i -e 's/6379/7002/g' -e 's/dir .\//dir \/tmp\/7002\//g' 7002/redis.conf
sed -i -e 's/6379/7003/g' -e 's/dir .\//dir \/tmp\/7003\//g' 7003/redis.conf
5)修改每個實例的聲明IP
虛擬機本身有多個IP,為了避免將來混亂,我們需要在redis.conf文件中指定每一個實例的綁定ip信息,格式如下:
# redis實例的聲明 IP
replica-announce-ip 192.168.150.101
每個目錄都要改,我們一鍵完成修改(在/tmp目錄執行下列命令):
# 逐一執行
sed -i '1a replica-announce-ip 192.168.150.101' 7001/redis.conf
sed -i '1a replica-announce-ip 192.168.150.101' 7002/redis.conf
sed -i '1a replica-announce-ip 192.168.150.101' 7003/redis.conf
?
# 或者一鍵修改
printf '%s\n' 7001 7002 7003 | xargs -I{} -t sed -i '1a replica-announce-ip 192.168.150.101' {}/redis.conf
啟動實例:
為了方便查看日志,我們打開3個ssh窗口,分別啟動3個redis實例,啟動命令:
# 第1個
redis-server 7001/redis.conf
# 第2個
redis-server 7002/redis.conf
# 第3個
redis-server 7003/redis.conf
如果要一鍵停止,可以運行下面命令:
printf '%s\n' 7001 7002 7003 | xargs -I{} -t redis-cli -p {} shutdown
開始主從關系:
現在三個實例還沒有任何關系,要配置主從可以使用replicaof 或者slaveof(5.0以前)命令。
有臨時和永久兩種模式:
修改配置文件(永久生效)
在redis.conf中添加一行配置:
slaveof <masterip> <masterport>
使用redis-cli客戶端連接到redis服務,執行slaveof命令(重啟后失效):
slaveof <masterip> <masterport>
注意:在5.0以后新增命令replicaof,與salveof效果一致。
這里我們為了演示方便,使用方式二。
通過redis-cli命令連接7002,執行下面命令:
# 連接 7002
redis-cli -p 7002
# 執行slaveof
slaveof 192.168.150.101 7001
通過redis-cli命令連接7003,執行下面命令:
# 連接 7003
redis-cli -p 7003
# 執行slaveof
slaveof 192.168.150.101 7001
然后連接 7001節點,查看集群狀態:
# 連接 7001
redis-cli -p 7001
# 查看狀態
info replication
結果:
測試:
執行下列操作以測試:
- 利用redis-cli連接7001,執行set num 123
- 利用redis-cli連接7002,執行get num,再執行set num 666
- 利用redis-cli連接7003,執行get num,再執行set num 888
可以發現,只有在7001這個master節點上可以執行寫操作,7002和7003這兩個slave節點只能執行讀操作。
2.2主從數據全量同步
主從第一次建立連接時,會執行全量同步,將主節點所有數據都拷貝到從節點,流程:
master如何得知salve是第一次來連接呢??
有幾個概念,可以作為判斷依據:
Replication Id:簡稱replid,是數據集的標記,id一致則說明是同一數據集。每一個master都有唯一的replid,slave則會繼承master節點的replid
offset:偏移量,隨著記錄在repl_baklog中的數據增多而逐漸增大。slave完成同步時也會記錄當前同步的offset。如果slave的offset小于master的offset,說明slave數據落后于master,需要更新。
因此slave做數據同步,必須向master聲明自己的replication id 和offset,master才可以判斷到底需要同步哪些數據。
因為slave原本也是一個master,有自己的replid和offset,當第一次變成slave,與master建立連接時,發送的replid和offset是自己的replid和offset。
master判斷發現slave發送來的replid與自己的不一致,說明這是一個全新的slave,就知道要做全量同步了。
master會將自己的replid和offset都發送給這個slave,slave保存這些信息。以后slave的replid就與master一致了。
因此,master判斷一個節點是否是第一次同步的依據,就是看replid是否一致。
如圖:
完整流程描述:
- slave節點請求增量同步
- master節點判斷replid,發現不一致,拒絕增量同步
- master將完整內存數據生成RDB,發送RDB到slave
- slave清空本地數據,加載master的RDB
- master將RDB期間的命令記錄在repl_baklog,并持續將log中的命令發送給slave
- slave執行接收到的命令,保持與master之間的同步
2.3主從數據增量同步
全量同步需要先做RDB,然后將RDB文件通過網絡傳輸個slave,成本太高了。因此除了第一次做全量同步,其它大多數時候slave與master都是做增量同步。
什么是增量同步?就是只更新slave與master存在差異的部分數據。如圖:
那么master怎么知道slave與自己的數據差異在哪里呢?
repl_backlog原理
master怎么知道slave與自己的數據差異在哪里呢?
這就要說到全量同步時的repl_baklog文件了。
這個文件是一個固定大小的數組,只不過數組是環形,也就是說**角標到達數組末尾后,會再次從0開始讀寫**,這樣數組頭部的數據就會被覆蓋。
repl_baklog中會記錄Redis處理過的命令日志及offset,包括master當前的offset,和slave已經拷貝到的offset:
slave與master的offset之間的差異,就是salve需要增量拷貝的數據了。
隨著不斷有數據寫入,master的offset逐漸變大,slave也不斷的拷貝,追趕master的offset:
直到數組被填滿:
此時,如果有新的數據寫入,就會覆蓋數組中的舊數據。不過,舊的數據只要是綠色的,說明是已經被同步到slave的數據,即便被覆蓋了也沒什么影響。因為未同步的僅僅是紅色部分。
但是,如果slave出現網絡阻塞,導致master的offset遠遠超過了slave的offset:
如果master繼續寫入新數據,其offset就會覆蓋舊的數據,直到將slave現在的offset也覆蓋:
棕色框中的紅色部分,就是尚未同步,但是卻已經被覆蓋的數據。此時如果slave恢復,需要同步,卻發現自己的offset都沒有了,無法完成增量同步了。只能做全量同步。
主從同步優化
主從同步可以保證主從數據的一致性,非常重要。
可以從以下幾個方面來優化Redis主從就集群:
在master中配置repl-diskless-sync yes啟用無磁盤復制,避免全量同步時的磁盤IO。
Redis單節點上的內存占用不要太大,減少RDB導致的過多磁盤IO
適當提高repl_baklog的大小,發現slave宕機時盡快實現故障恢復,盡可能避免全量同步
限制一個master上的slave節點數量,如果實在是太多slave,則可以采用主-從-從鏈式結構,減少master讀的壓力,讓二級從節點東一級從節點同步數據
主從從架構圖:
總結:
簡述全量同步和增量同步區別?
全量同步:master將完整內存數據生成RDB,發送RDB到slave。后續命令則記錄在repl_baklog,逐個發送給slave。
增量同步:slave提交自己的offset到master,master獲取repl_baklog中從offset之后的命令給slave
什么時候執行全量同步?
slave節點第一次連接master節點時
slave節點斷開時間太久,repl_baklog中的offset已經被覆蓋時
什么時候執行增量同步?
slave節點斷開又恢復,并且在repl_baklog中能找到offset時
3.Redis哨兵機制
Redis提供了哨兵機制來實現主從集群的自動故障恢復。
3.1 哨兵的作用和原理
哨兵的結構如圖:
哨兵的作用如下:
監控:Sentinel 會不斷檢查您的master和slave是否按預期工作
自動故障恢復:如果master故障,Sentinel會將一個slave提升為master。當故障實例恢復后也以新的master為主
通知:Sentinel充當Redis客戶端的服務發現來源,當集群發生故障轉移時,會將最新信息推送給Redis的客戶端
Sentinel服務監控:
Sentinel基于心跳機制監測服務狀態,每隔1秒向集群的每個實例發送ping命令:
?主觀下線:如果某sentinel節點發現某實例未在規定時間響應,則認為該實例主觀下線。
?客觀下線:若超過指定數量(quorum)的sentinel都認為該實例主觀下線,則該實例客觀下線。quorum值最好超過Sentinel實例數量的一半。
集群故障恢復原理:
一旦發現master故障,sentinel需要在salve中選擇一個作為新的master,選擇依據是這樣的:
- 首先會判斷slave節點與master節點斷開時間長短,如果超過指定值(down-after-milliseconds * 10)則會排除該slave節點
- 然后判斷slave節點的slave-priority值,越小優先級越高,如果是0則永不參與選舉
- 如果slave-prority一樣,則判斷slave節點的offset值,越大說明數據越新,優先級越高
- 最后是判斷slave節點的運行id大小,越小優先級越高。
當選出一個新的master后,該如何實現切換呢?
流程如下:
- sentinel給備選的slave1節點發送slaveof no one命令,讓該節點成為master
- sentinel給所有其它slave發送slaveof 192.168.150.101 7002 命令,讓這些slave成為新master的從節點,開始從新的master上同步數據。
- 最后,sentinel將故障節點標記為slave,當故障節點恢復后會自動成為新的master的slave節點
小結:
Sentinel的三個作用是什么?
監控
故障轉移
通知
Sentinel如何判斷一個redis實例是否健康?
每隔1秒發送一次ping命令,如果超過一定時間沒有相向則認為是主觀下線
如果大多數sentinel都認為實例主觀下線,則判定服務下線
故障轉移步驟有哪些?
首先選定一個slave作為新的master,執行slaveof no one
然后讓所有節點都執行slaveof 新master
修改故障節點配置,添加slaveof 新master
3.2 哨兵集群搭建
這里我們搭建一個三節點形成的Sentinel集群,來監管之前的Redis主從集群。
三個sentinel實例信息如下:
節點 | IP | PORT |
---|---|---|
s1 | 192.168.150.101 | 27001 |
s2 | 192.168.150.101 | 27002 |
s3 | 192.168.150.101 | 27003 |
準備實例和配置:
要在同一臺虛擬機開啟3個實例,必須準備三份不同的配置文件和目錄,配置文件所在目錄也就是工作目錄。
我們創建三個文件夾,名字分別叫s1、s2、s3:
# 進入/tmp目錄
cd /tmp
# 創建目錄
mkdir s1 s2 s3
如圖:
然后我們在s1目錄創建一個sentinel.conf文件,添加下面的內容:
port 27001
sentinel announce-ip 192.168.150.101
sentinel monitor mymaster 192.168.150.101 7001 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
dir "/tmp/s1"
解讀:
port 27001
:是當前sentinel實例的端口sentinel monitor mymaster 192.168.150.101 7001 2
:指定主節點信息mymaster
:主節點名稱,自定義,任意寫192.168.150.101 7001
:主節點的ip和端口2
:選舉master時的quorum值
然后將s1/sentinel.conf文件拷貝到s2、s3兩個目錄中(在/tmp目錄執行下列命令):
# 方式一:逐個拷貝
cp s1/sentinel.conf s2
cp s1/sentinel.conf s3
# 方式二:管道組合命令,一鍵拷貝
echo s2 s3 | xargs -t -n 1 cp s1/sentinel.conf
修改s2、s3兩個文件夾內的配置文件,將端口分別修改為27002、27003:
sed -i -e 's/27001/27002/g' -e 's/s1/s2/g' s2/sentinel.conf
sed -i -e 's/27001/27003/g' -e 's/s1/s3/g' s3/sentinel.conf
為了方便查看日志,我們打開3個ssh窗口,分別啟動3個redis實例,啟動命令:
# 第1個
redis-sentinel s1/sentinel.conf
# 第2個
redis-sentinel s2/sentinel.conf
# 第3個
redis-sentinel s3/sentinel.conf
3.3 RedisTemplate集成哨兵機制
在Sentinel集群監管下的Redis主從集群,其節點會因為自動故障轉移而發生變化,Redis的客戶端必須感知這種變化,及時更新連接信息。Spring的RedisTemplate底層利用lettuce實現了節點的感知和自動切換。
下面搭建一個Demo示例來展示集成過程:
1.在項目的pom文件中引入依賴:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2.配置Redis地址:
然后在配置文件application.yml中指定redis的sentinel相關信息:
spring:redis:sentinel:master: mymasternodes:- 192.168.150.101:27001- 192.168.150.101:27002- 192.168.150.101:27003
3.配置讀寫分離
在項目的啟動類中,添加一個新的bean:
@Bean
public LettuceClientConfigurationBuilderCustomizer clientConfigurationBuilderCustomizer(){return clientConfigurationBuilder -> clientConfigurationBuilder.readFrom(ReadFrom.REPLICA_PREFERRED);
}
這個bean中配置的就是讀寫策略,包括四種:
MASTER:從主節點讀取
MASTER_PREFERRED:優先從master節點讀取,master不可用才讀取replica
REPLICA:從slave(replica)節點讀取
REPLICA _PREFERRED:優先從slave(replica)節點讀取,所有的slave都不可用才讀取master
3.Redis分片集群
主從和哨兵可以解決高可用、高并發讀的問題。但是依然有兩個問題沒有解決:
海量數據存儲問題
高并發寫的問題
使用分片集群可以解決上述問題,如圖:
分片集群特征:
- 集群中有多個master,每個master保存不同數據
- 每個master都可以有多個slave節點
- master之間通過ping監測彼此健康狀態
- 客戶端請求可以訪問集群任意節點,最終都會被轉發到正確節點
3.1 分片集群搭建
分片集群需要的節點數量較多,這里我們搭建一個最小的分片集群,包含3個master節點,每個master包含一個slave節點,這里我們會開啟6個redis實例,模擬分片集群,信息如下:
IP | PORT | 角色 |
---|---|---|
192.168.150.101 | 7001 | master |
192.168.150.101 | 7002 | master |
192.168.150.101 | 7003 | master |
192.168.150.101 | 8001 | slave |
192.168.150.101 | 8002 | slave |
192.168.150.101 | 8003 | slave |
創建出7001、7002、7003、8001、8002、8003目錄:
# 進入/tmp目錄
cd /tmp
# 刪除舊的,避免配置干擾
rm -rf 7001 7002 7003
# 創建目錄
mkdir 7001 7002 7003 8001 8002 8003
在/tmp下準備一個新的redis.conf文件,內容如下:
port 6379
# 開啟集群功能
cluster-enabled yes
# 集群的配置文件名稱,不需要我們創建,由redis自己維護
cluster-config-file /tmp/6379/nodes.conf
# 節點心跳失敗的超時時間
cluster-node-timeout 5000
# 持久化文件存放目錄
dir /tmp/6379
# 綁定地址
bind 0.0.0.0
# 讓redis后臺運行
daemonize yes
# 注冊的實例ip
replica-announce-ip 192.168.150.101
# 保護模式
protected-mode no
# 數據庫數量
databases 1
# 日志
logfile /tmp/6379/run.log
將這個文件拷貝到每個目錄下:
# 進入/tmp目錄
cd /tmp
# 執行拷貝
echo 7001 7002 7003 8001 8002 8003 | xargs -t -n 1 cp redis.conf
修改每個目錄下的redis.conf,將其中的6379修改為與所在目錄一致:
# 進入/tmp目錄
cd /tmp
# 修改配置文件
printf '%s\n' 7001 7002 7003 8001 8002 8003 | xargs -I{} -t sed -i 's/6379/{}/g' {}/redis.conf
啟動:
因為已經配置了后臺啟動模式,所以可以直接啟動服務:
# 進入/tmp目錄
cd /tmp
# 一鍵啟動所有服務
printf '%s\n' 7001 7002 7003 8001 8002 8003 | xargs -I{} -t redis-server {}/redis.conf
通過ps查看狀態:
ps -ef | grep redis
發現服務都已經正常啟動
如果要關閉所有進程,可以執行命令:
ps -ef | grep redis | awk '{print $2}' | xargs kill
或者(推薦這種方式):
printf '%s\n' 7001 7002 7003 8001 8002 8003 | xargs -I{} -t redis-cli -p {} shutdown
創建集群:
雖然服務啟動了,但是目前每個服務之間都是獨立的,沒有任何關聯。
我們需要執行命令來創建集群,在Redis5.0之前創建集群比較麻煩,5.0之后集群管理命令都集成到了redis-cli中。
1)Redis5.0之前
Redis5.0之前集群命令都是用redis安裝包下的src/redis-trib.rb來實現的。因為redis-trib.rb是有ruby語言編寫的所以需要安裝ruby環境。
# 安裝依賴
yum -y install zlib ruby rubygems
gem install redis
然后通過命令來管理集群:
# 進入redis的src目錄
cd /tmp/redis-6.2.4/src
# 創建集群
./redis-trib.rb create --replicas 1 192.168.150.101:7001 192.168.150.101:7002 192.168.150.101:7003 192.168.150.101:8001 192.168.150.101:8002 192.168.150.101:8003
2)Redis5.0以后
我們使用的是Redis6.2.4版本,集群管理以及集成到了redis-cli中,格式如下:
redis-cli --cluster create --cluster-replicas
1 192.168.150.101:7001 192.168.150.101:7002 192.168.150.101:7003 192.168.150.101:8001 192.168.150.101:8002 192.168.150.101:8003
命令說明:
redis-cli --cluster
或者./redis-trib.rb
:代表集群操作命令create
:代表是創建集群--replicas 1
或者--cluster-replicas 1
:指定集群中每個master的副本個數為1,此時節點總數 ÷ (replicas + 1)
得到的就是master的數量。因此節點列表中的前n個就是master,其它節點都是slave節點,隨機分配到不同master
通過命令可以查看集群狀態:
redis-cli -p 7001 cluster nodes
3.2 散列插槽
分片集群模式下,Redis會把每一個master節點映射到0~16383共16384個插槽(hash slot)上,查看集群信息時就能看到:
cluster slots
數據key不是與節點綁定,而是與插槽綁定。redis會根據key的有效部分計算插槽值,分兩種情況:
- key中包含"{}",且“{}”中至少包含1個字符,“{}”中的部分是有效部分
- key中不包含“{}”,整個key都是有效部分
例如:key是num,那么就根據num計算,如果是{itcast}num,則根據itcast計算。計算方式是利用CRC16算法得到一個hash值,然后對16384取余,得到的結果就是slot值。
如圖,在7001這個節點執行set a 1時,對a做hash運算,對16384取余,得到的結果是15495,因此要存儲到103節點。
到了7003后,執行`get num`時,對num做hash運算,對16384取余,得到的結果是2765,因此需要切換到7001節點
小結:
Redis如何判斷某個key應該在哪個實例?
將16384個插槽分配到不同的實例
根據key的有效部分計算哈希值,對16384取余
余數作為插槽,尋找插槽所在實例即可
如何將同一類數據固定的保存在同一個Redis實例?
這一類數據使用相同的有效部分,例如key都以{typeId}為前綴
3.3 集群伸縮
redis-cli --cluster提供了很多操作集群的命令,可以通過下面方式查看: 比如,添加節點的命令:
需求:向集群中添加一個新的master節點,并向其中存儲 num = 10
啟動一個新的redis實例,端口為7004
添加7004到之前的集群,并作為一個master節點
給7004節點分配插槽,使得num這個key可以存儲到7004實例
這里需要兩個新的功能:
添加一個節點到集群中
將部分插槽分配到新插槽
實現如下:
1.創建新的Redis實例
創建一個文件夾:
mkdir 7004
拷貝配置文件:
cp redis.conf /7004
修改配置文件:
sed /s/6379/7004/g 7004/redis.conf
啟動
redis-server 7004/redis.conf
2.添加新節點到Redis
執行命令:
redis-cli --cluster add-node ?192.168.150.101:7004 192.168.150.101:7001
通過命令查看集群狀態:
redis-cli -p 7001 cluster nodes
3.轉移插槽
我們要將num存儲到7004節點,因此需要先看看num的插槽是多少:
具體命令如下:
建立連接:
得到下面的反饋:
詢問要移動多少個插槽,我們計劃是3000個:
新的問題來了:
那個node來接收這些插槽??
顯然是7004,那么7004節點的id是多少呢?
復制這個id,然后拷貝到剛才的控制臺后:
這里詢問,你的插槽是從哪里移動過來的?
- all:代表全部,也就是三個節點各轉移一部分
- 具體的id:目標節點的id
- done:沒有了
這里我們要從7001獲取,因此填寫7001的id:填完后,點擊done,這樣插槽轉移就準備好了:
確認要轉移嗎?輸入yes:
然后,通過命令查看結果:
可以看到:?
目的達成。
3.4故障轉移
自動故障轉移
當集群中有一個master宕機會發生什么呢?
直接停止一個redis實例,例如7002:
redis-cli -p 7002 shutdown
手動故障轉移
利用cluster failover命令可以手動讓集群中的某個master宕機,切換到執行cluster failover命令的這個slave節點,實現無感知的數據遷移。其流程如下:
這種failover命令可以指定三種模式:
缺省:默認的流程,如圖1~6歩
force:省略了對offset的一致性校驗
takeover:直接執行第5歩,忽略數據一致性、忽略master狀態和其它master的意見
案例需求:在7002這個slave節點執行手動故障轉移,重新奪回master地位
步驟如下:
1)利用redis-cli連接7002這個節點
2)執行cluster failover命令
如圖:
3.5.RedisTemplate訪問分片集群
RedisTemplate底層同樣基于lettuce實現了分片集群的支持,而使用的步驟與哨兵模式基本一致:
1)引入redis的starter依賴
2)配置分片集群地址
3)配置讀寫分離
與哨兵模式相比,其中只有分片集群的配置方式略有差異,如下:
spring:redis:cluster:nodes:- 192.168.150.101:7001- 192.168.150.101:7002- 192.168.150.101:7003- 192.168.150.101:8001- 192.168.150.101:8002- 192.168.150.101:8003