手撕Redis底層3-持久化機制與集群化方案

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實例,模擬主從集群:

IPPORT角色
192.168.150.1017001master
192.168.150.1017002slave
192.168.150.1017003slave

我們在同一臺機器上開啟三個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實例信息如下:

節點IPPORT
s1192.168.150.10127001
s2192.168.150.10127002
s3192.168.150.10127003

準備實例和配置:

要在同一臺虛擬機開啟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實例,模擬分片集群,信息如下:

IPPORT角色
192.168.150.1017001master
192.168.150.1017002master
192.168.150.1017003master
192.168.150.1018001slave
192.168.150.1018002slave
192.168.150.1018003slave

創建出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

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/921573.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/921573.shtml
英文地址,請注明出處:http://en.pswp.cn/news/921573.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

mysql中null值對in子查詢的影響

1、場景 有這樣一個查詢&#xff0c;有些時候是正確的&#xff0c;有些時候沒報錯但是又查詢不到數據&#xff0c;分析數據排查后發現當user_id字段存在null值的時候查詢不到數據。select * from table1 where id in (select user_id from talbe2 where status1);2、問題 為什么…

如何在 tortoise-orm 內使用 JSON_EXTRACT

先說結論&#xff1a; # 假設 JsonField 名稱為 data&#xff0c;內容為 {"info": {"path": "我的資源創建"}} qs qs.filter(data__filter{"info.path": "我的資源創建"})我查看了 tortoise-orm 官方文檔&#xff0c;沒有這…

西門子S7-200 SMART PLC:編寫最基礎的“起保停”程序

一、什么是“起保停”電路&#xff1f;“起保停”是“啟動-保持-停止”的簡稱&#xff0c;也稱為“自鎖電路”。它是繼電器控制系統和PLC程序中最基本、最核心的控制邏輯。啟動 (Start): 由一個點動按鈕&#xff08;常開觸點&#xff09;觸發&#xff0c;使設備運行。保持 (H…

漏洞修復 Nginx SSL/TLS 弱密碼套件

掃描結果 [rootlocalhost nmap]# docker run --rm -v $(pwd)/results:/results securecodebox/nmap nmap --script ssl-enum-ciphers -p 443 xxx.cn -oX /results/output_0904.xml Starting Nmap 7.80 ( https://nmap.org ) at 2025-09-04 05:02 UTC Nmap scan report for xxx.…

ChartGPT深度體驗:AI圖表生成工具如何高效實現數據可視化與圖表美化?

最近幫運營同事做季度數據報告時&#xff0c;我差點在圖表樣式上栽跟頭 —— 明明數據都算好了&#xff0c;用 Excel 調柱狀圖的顏色、字體、坐標軸標簽&#xff0c;來回改了快半小時&#xff0c;要么字體太大擠在一起&#xff0c;要么顏色搭配顯臟&#xff0c;運營催得急&…

深入理解 JVM 字節碼文件:從組成結構到 Arthas 工具實踐

在 Java 技術體系中&#xff0c;JVM&#xff08;Java 虛擬機&#xff09;是實現 “一次編寫&#xff0c;到處運行” 的核心。而字節碼文件作為 Java 代碼編譯后的產物&#xff0c;是 JVM 執行的 “原材料”。今天&#xff0c;我們就從字節碼文件的組成結構講起&#xff0c;再結…

SoundSource for Mac 音頻控制工具

SoundSource for Mac 是一款音頻控制工具&#xff0c;中文常被稱為 音頻源管理器。它能夠精確控制系統與應用程序的音量、輸出設備和音效處理&#xff0c;讓用戶獲得比 macOS 原生更靈活的音頻管理體驗。SoundSource 既適合音樂發燒友&#xff0c;也適合日常辦公和影音娛樂用戶…

云平臺面試內容(二)

5. VPC、子網、路由、NAT網關、安全組、網絡ACL 區別與網絡隔離設計 概念區別: VPC(虛擬私有云): VPC是在公有云上劃分出的一個用戶專屬的虛擬網絡環境,相當于用戶在云上的私有數據中心。用戶可以自定義VPC的IP地址段、路由策略等。不同VPC網絡隔離,默認互不相通,確保資…

2023 arXiv MapperGPT: Large Language Models for Linking and Mapping Entities

論文基本信息 題目&#xff1a;MapperGPT: Large Language Models for Linking and Mapping Entities作者&#xff1a;Nicolas Matentzoglu, J. Harry Caufield, Harshad B. Hegde, Justin T. Reese, Sierra Moxon, Hyeongsik Kim, Nomi L. Harris, Melissa A Haendel, Christo…

Docker入門到精通:從零基礎到生產部署

前言&#xff1a;為什么你需要學習Docker&#xff1f; 想象一下&#xff0c;你開發了一個應用程序&#xff0c;在你的電腦上運行完美&#xff0c;但當你把它交給同事或部署到服務器時&#xff0c;卻出現了各種奇怪的問題。這就是著名的"在我機器上能運行"問題。 Do…

HOT100--Day15--98. 驗證二叉搜索樹,230. 二叉搜索樹中第 K 小的元素,199. 二叉樹的右視圖

HOT100–Day15–98. 驗證二叉搜索樹&#xff0c;230. 二叉搜索樹中第 K 小的元素&#xff0c;199. 二叉樹的右視圖 每日刷題系列。今天的題目是《力扣HOT100》題單。 題目類型&#xff1a;二叉樹。 關鍵&#xff1a;要深刻理解《遞歸》 98. 驗證二叉搜索樹 思路&#xff1a; …

獨角數卡對接藍鯨支付平臺實現個人

目錄 什么是獨角數卡&#xff1f;安裝部署教程一、獨角數卡安裝二、獨角數卡支付配置三、獨角數卡BUG修復 什么是獨角數卡&#xff1f; ? ? ? ? ? ? ? 獨角數卡(Dujiaoka)?是一款基于Laravel框架開發的開源式站長自動化售貨解決方案&#xff0c;主要用于虛擬商品和數字…

人工智能常見分類

人工智能的分類方式多樣&#xff0c;以下是一些常見的分類方法及具體類型&#xff1a; 一、按功能目標分類 弱人工智能&#xff08;ANI&#xff0c;Narrow AI&#xff09;&#xff1a;專注于單一任務&#xff0c;無自主意識&#xff0c;如圖像識別&#xff08;人臉解鎖&#xf…

PO BAPI bapi_po_create1

當執行BAPI時,需要導入增強字段,其中增強字段包含數值型號字段時,需要增強BADI::ME_BAPI_PO_CUST 代碼如下: 記錄一下,下次自己繼續用 bapi處: ls_te_item-po_item = lv_item.ls_te_item-zz001 = 11.ls_te_item-zz005 = 22.ls_te_item-zz008 = 33.ls_te_item-zz009 = 44…

棧欺騙技術的作用是什么?

好的&#xff0c;我們來詳細解釋一下“棧欺騙技術”&#xff08;Stack Spoofing&#xff09;的作用。簡單來說&#xff0c;棧欺騙技術的核心作用是隱藏程序&#xff08;尤其是惡意軟件或安全工具&#xff09;的真實調用鏈&#xff0c;使其逃避基于棧回溯&#xff08;Stack Walk…

Nano-banana 模型對接教程:最懂創作者的 AI 模型,比GPT-4o還強!

Nano-banana 模型對接教程&#xff08;含 BaseURL&#xff09; Nano Banana 是谷歌推出的革命性 AI 圖像編輯模型&#xff0c;代表了從"AI繪畫工具"到"AI創意伙伴"的范式轉移。它不再是被動執行指令&#xff0c;而是能深刻理解已有圖像的上下文、光影、物…

CEEMDAN-PSO-CNN-GRU 鋰電池健康狀態預測matlab

代碼說明 這個實現包含以下主要組成部分: 數據準備:加載并預處理鋰電池容量數據,劃分訓練集和測試集 CEEMDAN分解:將原始信號分解為多個本征模態函數(IMF)和一個殘差項 PSO優化:使用粒子群算法優化CNN-GRU網絡的超參數 CNN-GRU模型:構建并訓練卷積神經網絡與門控循環…

MySQL 主從讀寫分離架構

我們首先來詳細、清晰地講解 MySQL 主從讀寫分離架構&#xff0c;然后逐一解答你提出的以及補充的高頻面試問題。第一部分&#xff1a;MySQL 主從讀寫分離架構詳解1. 什么是主從復制與讀寫分離&#xff1f;你可以把它想象成一個 “團隊作戰” 的模式。主數據庫 (Master)&#x…

HTML 中的 CSS 使用說明

CSS 使用說明 1. CSS 概述 CSS (Cascading Style Sheets) 是一種用于描述 HTML 或 XML&#xff08;包括如 SVG、MathML 等 XML 方言&#xff09;文檔呈現的樣式表語言。CSS 描述了元素應該如何在屏幕、紙張或其他媒體上顯示。 2. CSS 的基本語法 CSS 規則由兩個主要部分組成…

gitlab推送失敗,內存不足的處理

git提交時報錯&#xff1a; 2025-09-03 20:03:32.583 [info] > git push origin master:master [4866ms]2025-09-03 20:03:32.583 [info] fatal: Out of memory, malloc failed (tried to allocate 1048576000 bytes)看了下服務器內存&#xff0c;空余的只有幾百M了。 用hto…