Redis Master-Slave

前言

Master-Slave 是 Redis 提供的主從複製機制,由 Master 負責寫入,並同步數據到所有 Slave
讓 Slave 分擔讀取功能,可減少 Master 負擔

環境

Linux VM = ubuntu-2004-lts
Redis Docker映像檔 = redis:6.0.0

本篇透過 GCP VM 來測試
準備 3 台 Linux VM
1 台 Redis Master
2 台 Redis Slave

機器 IP
redis-master 10.140.0.20
redis-slave-1 10.140.0.21
redis-slave-2 10.140.0.22

設定 VPC & Firewall

# 建立 VPC
gcloud compute networks create redis-vpc --subnet-mode custom

# 建立 VPC 子網路
gcloud compute networks subnets create redis-vpc-subnet \
  --network redis-vpc \
  --range 10.240.0.0/24 \
  --region asia-east1

# 設定機器對內防火牆
gcloud compute firewall-rules create redis-vpc-allow-internal \
  --allow tcp,udp,icmp,ipip \
  --network redis-vpc \
  --source-ranges 10.240.0.0/24

# 設定機器對外防火牆 (IP 請指定要訪問 Redis 的 連線IP)
gcloud compute firewall-rules create redis-vpc-allow-external \
  --allow tcp:6379 \
  --network redis-vpc \
  --source-ranges x.x.x.x

# 設定機器對外防火牆 SSH 連線
gcloud compute firewall-rules create redis-vpc-allow-ssh \
  --allow tcp:22 \
  --network redis-vpc \
  --source-ranges 0.0.0.0/0

設定 VM

建立 Master 機器

gcloud compute instances create redis-master \
    --async \
    --boot-disk-size 100GB \
    --can-ip-forward \
    --image-family ubuntu-2004-lts \
    --image-project ubuntu-os-cloud \
    --machine-type e2-standard-2 \
    --private-network-ip 10.240.0.20 \
    --scopes compute-rw,storage-ro,service-management,service-control,logging-write,monitoring \
    --subnet redis-vpc-subnet \
    --zone asia-east1-a \
    --tags redis-vpc

建立 2 台 Slave 機器

for i in 1 2; do
  gcloud compute instances create redis-slave-${i} \
    --async \
    --boot-disk-size 100GB \
    --can-ip-forward \
    --image-family ubuntu-2004-lts \
    --image-project ubuntu-os-cloud \
    --machine-type e2-standard-2 \
    --private-network-ip 10.240.0.2${i} \
    --scopes compute-rw,storage-ro,service-management,service-control,logging-write,monitoring \
    --subnet redis-vpc-subnet \
    --zone asia-east1-a \
    --tags redis-vpc
done

安裝 Docker

參考 w4560000 - Linux 安裝 Docker、Docker-Compose

3 台 VM 都先設定好 volumn 資料夾

mkdir redis && mkdir redisdata

Redis Master-Slave 建置

Redis Slave 服務啟動後,初始連線到 Master 時,Master 會執行 Bgsave 建立 RDB 檔並回傳給 Slave 來載入資料

redis.conf

  • repl-ping-replica-period

    master 每隔幾秒會 ping slave,確認是否活著
    ex: repl-ping-replica-period 10 (預設)

  • repl-timeout

    當 redis 檢測到 repl-timeout 超時,將會關閉主從連線,並由 slave 重新發起主從連線請求
    該值需大於 repl-ping-replica-period,避免一直觸發 timeout 重連
    以下三種狀況是超時狀況

    1. slave 角度,master 同步 RDB 數據超時
    2. slave 角度,在 repl-timeout 時間內沒有收到 master 的發送的數據或 ping
    3. master 角度,在 repl-timeout 時間內沒有收到 slave 發送的 REPLCONF ACK
      ex: repl-timeout 60 (預設)

Master、Slave 都先新增 redis.conf
路徑 ~/redis/redis.conf

bind 0.0.0.0
protected-mode no
dir ./

# AOF
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec

# AOF rewrite
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 0
auto-aof-rewrite-min-size 1mb
aof-load-truncated no
aof-use-rdb-preamble yes

# REPLICATION
repl-ping-replica-period 10
repl-timeout 60

Master 建立 Redis 服務

docker run --name redis-master \
-p 6379:6379 \
-v /home/leozheng0411/redis:/usr/local/etc/redis \
-v /home/leozheng0411/redisdata:/data \
-d redis:6.0.0 \
redis-server /usr/local/etc/redis/redis.conf

Slave 建立 Redis 服務

docker run --name redis-slave \
-p 6379:6379 \
-v /home/leozheng0411/redis:/usr/local/etc/redis \
-v /home/leozheng0411/redisdata:/data \
-d redis:6.0.0 \
redis-server /usr/local/etc/redis/redis.conf --replicaof 10.240.0.20 6379

備註: 雖然 Slave 在這邊主要是讀取功能,不負責寫入,並且是接收 Master 同步過來的資料
理論上不需要在多做 AOF 來備份,但若 Master 發生異常,Slave 則會升為 Master,則此時若沒有備份機制,那就很危險了
所以 Slave 建置時,一樣先建好備份機制,以防萬一

確認是否有主從同步

Master

# 查看 Replication 資訊
docker exec -it redis-master redis-cli info replication

# 輸出
role:master
connected_slaves:2
slave0:ip=10.240.0.21,port=6379,state=online,offset=1469,lag=0
slave1:ip=10.240.0.22,port=6379,state=online,offset=1469,lag=0
master_replid:5ab3de3667aafae90f3d12900834098fa01c65c1
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:1469
master_repl_meaningful_offset:853
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:1469

# 設定資料測試
docker exec -it redis-master redis-cli SET Key1 "1"

# 輸出
OK

Slave1

docker exec -it redis-slave redis-cli GET Key1

# 輸出
"1"

Slave2

docker exec -it redis-slave redis-cli GET Key1

# 輸出
"1"

Slave 是否可寫入資料

Slave1

docker exec -it redis-slave redis-cli SET Key1 "10"

# 輸出
(error) READONLY You can't write against a read only replica.

因主要是由 Master 寫入資料,同步到 Slave,其他應用程式可讀取 Slave,來達成讀寫分離
所以 Redis 預設 Slave 是不能寫入資料

但仍可以設定讓 Slave 可以寫入

docker exec -it redis-slave redis-cli CONFIG SET slave-read-only no

# 輸出
OK

docker exec -it redis-slave redis-cli SET Key1 "10"

# 輸出
OK

但這個操作只有 Slave1 有影響,並不會同步到 Master、Slave2
會造成主從資料不一致,若無特殊情境的話,則讓 Slave 保持僅有讀的權限就好,避免資料異常

參考文件

HackMD tienyulin - Redis (六) - 主從複製、哨兵與叢集模式#主從複製模式


轉載請註明來源,若有任何錯誤或表達不清楚的地方,歡迎在下方評論區留言,也可以來信至 leozheng0621@gmail.com
如果文章對您有幫助,歡迎斗內(donate),請我喝杯咖啡

斗內💰

×

歡迎斗內

github