什麼是 Redis Sentinel#
- redis sentinel 讓 redis 擁有高可用性 (high availability)。
- sentinel 會監控 redis 服務,在主節點 (master) 異常時啟動容錯移轉 (failover),將複製節點 (replica) 提升成主節點,並告知跟 sentinel 建立連線的客戶端。
要實測一個最簡單的 redis sentinel 服務,我們需要 3 個 redis + 3 個 sentinel 的架構。使用 docker compose 可以直接在一台電腦上建出這樣的環境。
設定 Sentinel 配置檔#
啟動 sentinel 需要準備配置檔 sentinel.conf
範例如下:
1
2
3
4
5
| sentinel monitor mymaster redis-master 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 180000
sentinel parallel-syncs mymaster 1
sentinel resolve-hostnames yes
|
以下依序說明每行配置的作用:
1
| sentinel monitor <master-name> <ip> <port> <quorum>
|
設定 sentinel 監控對象
- master-name: 對監控的 master node 設計一個名稱
- ip: master node ip
- port: master node port
- quorum: 判定 master 異常的 sentinel 數量
1
| sentinel down-after-milliseconds mymaster 5000
|
sentinel 判定連不到 master 的時間,這邊我們設定 5 秒
1
| sentinel failover-timeout mymaster 180000
|
容錯移轉 (failover) 逾時的時間
1
| sentinel parallel-syncs mymaster 1
|
容錯移轉 (failover) 後同時可以重新配置使用新的 master 的數量
1
| sentinel resolve-hostnames yes
|
讓 sentinel 支援 DNS/hostnames
程式連 Redis Sentinel#
同時我也用 go 寫一個簡單程式,使用 go-redis 的 NewFailoverClient() 連 redis。FailoverClient 使用 sentinel 來連 redis 主服務,達到 failover 的效果。
程式會用 ping 跟 client info 來印出目前程式的連線狀況。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| package main
import (
"context"
"fmt"
"time"
"github.com/redis/go-redis/v9"
)
func main() {
ctx := context.Background()
cli := redis.NewFailoverClient(&redis.FailoverOptions{
MasterName: "mymaster",
SentinelAddrs: []string{
"sentinel-1:26379",
"sentinel-2:26379",
"sentinel-3:26379",
},
})
for {
result, err := cli.Ping(ctx).Result()
fmt.Println("redis ping", result, err)
info := cli.ClientInfo(ctx).Val()
if info != nil {
fmt.Println("client info addr", info.Addr)
fmt.Println("client info laddr", info.LAddr)
}
time.Sleep(2 * time.Second)
}
}
|
Docker Compose#
完整的 docker-compose.yml
如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
| version: '3.8'
services:
redis-master:
image: redis:7.0.15
redis-slave1:
image: redis:7.0.15
command: redis-server --slaveof redis-master 6379
depends_on:
- redis-master
redis-slave2:
image: redis:7.0.15
command: redis-server --slaveof redis-master 6379
depends_on:
- redis-master
- redis-slave1
sentinel-1:
image: redis:7.0.15
command: redis-sentinel /usr/local/etc/redis/sentinel.conf
volumes:
- ./sentinel/sentinel1.conf:/usr/local/etc/redis/sentinel.conf
depends_on:
- redis-master
sentinel-2:
image: redis:7.0.15
command: redis-sentinel /usr/local/etc/redis/sentinel.conf
volumes:
- ./sentinel/sentinel1.conf:/usr/local/etc/redis/sentinel.conf
depends_on:
- redis-master
sentinel-3:
image: redis:7.0.15
command: redis-sentinel /usr/local/etc/redis/sentinel.conf
volumes:
- ./sentinel/sentinel1.conf:/usr/local/etc/redis/sentinel.conf
depends_on:
- redis-master
app:
image: golang:1.21.3
working_dir: /app
command: go run main.go
volumes:
- ./:/app
depends_on:
- redis-master
|
啟動 Redis Sentinel#
輸入 docker compose up -d
啟動,等服務都是 running 後,我們來看一下 redis 跟 sentinel 的狀態。
查看 redis-master replication 資訊:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| docker compose exec redis-master redis-cli info replication
# Replication
role:master
connected_slaves:2
slave0:ip=172.26.0.7,port=6379,state=online,offset=332361,lag=0
slave1:ip=172.26.0.8,port=6379,state=online,offset=332361,lag=0
master_failover_state:no-failover
master_replid:5fddecc88cfc92eafb11d449e343d8228443c45b
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:332496
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:332496
|
查看 sentinel-1 資訊:
1
2
3
4
5
6
7
8
9
| docker compose exec sentinel-1 redis-cli -p 26379 info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_tilt_since_seconds:-1
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=172.26.0.2:6379,slaves=2,sentinels=3
|
- mymaster 目前是 172.26.0.2:6379 (redis-master)
查看 sentinel-1 log:
1
2
3
4
5
6
| redis-sentinel-lab-sentinel-1-1 | 1:X 05 Apr 2024 15:56:41.813 # Sentinel ID is 8d6bf48cae2f8253311d505494ce82b90baef62e
redis-sentinel-lab-sentinel-1-1 | 1:X 05 Apr 2024 15:56:41.813 # +monitor master mymaster 172.26.0.2 6379 quorum 2
redis-sentinel-lab-sentinel-1-1 | 1:X 05 Apr 2024 15:56:43.808 * +sentinel sentinel c1e780b5117fb4a224733ddad07a2e9af7ec3eef 172.26.0.4 26379 @ mymaster 172.26.0.2 6379
redis-sentinel-lab-sentinel-1-1 | 1:X 05 Apr 2024 15:56:43.833 * +sentinel sentinel f649283af8d6254a29f80072b19a3f20d52ea221 172.26.0.3 26379 @ mymaster 172.26.0.2 6379
redis-sentinel-lab-sentinel-1-1 | 1:X 05 Apr 2024 15:56:51.994 * +slave slave 172.26.0.7:6379 172.26.0.7 6379 @ mymaster 172.26.0.2 6379
redis-sentinel-lab-sentinel-1-1 | 1:X 05 Apr 2024 15:56:52.134 * +slave slave 172.26.0.8:6379 172.26.0.8 6379 @ mymaster 172.26.0.2 6379
|
- sentinel 連到 redis-master
- 接著收到另外兩台 sentinel 的資料以及 slave 的資料
查看程式 log:
1
2
3
4
5
6
7
| docker compose logs -f app
redis-sentinel-lab-app-1 | redis: 2024/04/05 16:32:26 sentinel.go:736: sentinel: discovered new sentinel="172.26.0.4:26379" for master="mymaster"
redis-sentinel-lab-app-1 | redis: 2024/04/05 16:32:26 sentinel.go:736: sentinel: discovered new sentinel="172.26.0.3:26379" for master="mymaster"
redis-sentinel-lab-app-1 | redis: 2024/04/05 16:32:26 sentinel.go:700: sentinel: new master="mymaster" addr="172.26.0.2:6379"
redis-sentinel-lab-app-1 | redis ping PONG <nil>
redis-sentinel-lab-app-1 | client info addr 172.26.0.5:52730
redis-sentinel-lab-app-1 | client info laddr 172.26.0.2:6379
|
- sentinel 提供了目前的 master node ip: 172.26.0.2:6379 (redis-master)
- 程式依照 sentinel 提供的 ip 順利的連到 redis
容錯移轉 (Failover) 測試#
直接下指令故意關掉 redis master
1
| docker compose stop redis-master
|
等服務中斷後,我們再來看一下 redis 跟 sentinel 的狀態。
查看 redis-slave1 的 replication 資訊:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| docker compose exec redis-slave1 redis-cli info replication
# Replication
role:slave
master_host:172.26.0.8
master_port:6379
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_read_repl_offset:872011
slave_repl_offset:872011
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
...
|
- role 還是 slave
- master host 指到另一台 slave
查看 redis-slave2 的 replication 資訊:
1
2
3
4
5
6
7
8
9
10
11
| docker compose exec redis-slave2 redis-cli info replication
# Replication
role:master
connected_slaves:1
slave0:ip=172.26.0.7,port=6379,state=online,offset=877304,lag=1
master_failover_state:no-failover
master_replid:de8d7834c30c4ba42f26587d4b617ec65126dc6c
master_replid2:5fddecc88cfc92eafb11d449e343d8228443c45b
master_repl_offset:877304
second_repl_offset:835557
...
|
查看 sentinel-1 資訊:
1
2
3
4
5
6
7
8
9
| docker compose exec sentinel-1 redis-cli -p 26379 info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_tilt_since_seconds:-1
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=172.26.0.8:6379,slaves=2,sentinels=3
|
- master 變成 172.26.0.8:6379 (redis-slave2) 了
查看 sentinel-1 log:
1
2
3
4
5
6
7
8
9
10
11
12
13
| redis-sentinel-lab-sentinel-1-1 | 1:X 05 Apr 2024 17:06:38.170 # Failed to resolve hostname 'redis-master'
redis-sentinel-lab-sentinel-1-1 | 1:X 05 Apr 2024 17:06:42.136 # +sdown master mymaster 172.26.0.2 6379
redis-sentinel-lab-sentinel-1-1 | 1:X 05 Apr 2024 17:06:42.202 # +odown master mymaster 172.26.0.2 6379 #quorum 2/2
redis-sentinel-lab-sentinel-1-1 | 1:X 05 Apr 2024 17:06:42.203 # +new-epoch 1
redis-sentinel-lab-sentinel-1-1 | 1:X 05 Apr 2024 17:06:42.203 # +try-failover master mymaster 172.26.0.2 6379
redis-sentinel-lab-sentinel-1-1 | 1:X 05 Apr 2024 17:06:42.278 # +vote-for-leader 8d6bf48cae2f8253311d505494ce82b90baef62e 1
redis-sentinel-lab-sentinel-1-1 | 1:X 05 Apr 2024 17:06:42.281 # c1e780b5117fb4a224733ddad07a2e9af7ec3eef voted for c1e780b5117fb4a224733ddad07a2e9af7ec3eef 1
redis-sentinel-lab-sentinel-1-1 | 1:X 05 Apr 2024 17:06:42.317 # f649283af8d6254a29f80072b19a3f20d52ea221 voted for c1e780b5117fb4a224733ddad07a2e9af7ec3eef 1
redis-sentinel-lab-sentinel-1-1 | 1:X 05 Apr 2024 17:06:43.402 # +config-update-from sentinel c1e780b5117fb4a224733ddad07a2e9af7ec3eef 172.26.0.4 26379 @ mymaster 172.26.0.2 6379
redis-sentinel-lab-sentinel-1-1 | 1:X 05 Apr 2024 17:06:43.403 # +switch-master mymaster 172.26.0.2 6379 172.26.0.8 6379
redis-sentinel-lab-sentinel-1-1 | 1:X 05 Apr 2024 17:06:43.405 * +slave slave 172.26.0.7:6379 172.26.0.7 6379 @ mymaster 172.26.0.8 6379
redis-sentinel-lab-sentinel-1-1 | 1:X 05 Apr 2024 17:06:43.413 # Failed to resolve hostname 'redis-master'
redis-sentinel-lab-sentinel-1-1 | 1:X 05 Apr 2024 17:06:43.413 * +slave slave :6379 6379 @ mymaster 172.26.0.8 6379
|
- 無法解析 redis-master 這個 hostname,sentinel 開始判定 master 服務中斷。
- 達到兩台 sentinel 判定 master 服務中斷後,開始容錯移轉的程序。
- 先投票選出主要負責容錯移轉的 sentinel 服務,再由主責的 sentinel 切換 master ip,其他的 sentinel 則是跟主責的 sentinel 同步 config 即可。
查看 sentinel-2 的 log:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| redis-sentinel-lab-sentinel-2-1 | 1:X 05 Apr 2024 17:06:42.278 # +vote-for-leader c1e780b5117fb4a224733ddad07a2e9af7ec3eef 1
redis-sentinel-lab-sentinel-2-1 | 1:X 05 Apr 2024 17:06:42.281 # 8d6bf48cae2f8253311d505494ce82b90baef62e voted for 8d6bf48cae2f8253311d505494ce82b90baef62e 1
redis-sentinel-lab-sentinel-2-1 | 1:X 05 Apr 2024 17:06:42.314 # f649283af8d6254a29f80072b19a3f20d52ea221 voted for c1e780b5117fb4a224733ddad07a2e9af7ec3eef 1
redis-sentinel-lab-sentinel-2-1 | 1:X 05 Apr 2024 17:06:42.357 # +elected-leader master mymaster 172.26.0.2 6379
redis-sentinel-lab-sentinel-2-1 | 1:X 05 Apr 2024 17:06:42.357 # +failover-state-select-slave master mymaster 172.26.0.2 6379
redis-sentinel-lab-sentinel-2-1 | 1:X 05 Apr 2024 17:06:42.430 # +selected-slave slave 172.26.0.8:6379 172.26.0.8 6379 @ mymaster 172.26.0.2 6379
redis-sentinel-lab-sentinel-2-1 | 1:X 05 Apr 2024 17:06:42.431 * +failover-state-send-slaveof-noone slave 172.26.0.8:6379 172.26.0.8 6379 @ mymaster 172.26.0.2 6379
redis-sentinel-lab-sentinel-2-1 | 1:X 05 Apr 2024 17:06:42.488 * +failover-state-wait-promotion slave 172.26.0.8:6379 172.26.0.8 6379 @ mymaster 172.26.0.2 6379
redis-sentinel-lab-sentinel-2-1 | 1:X 05 Apr 2024 17:06:43.364 # +promoted-slave slave 172.26.0.8:6379 172.26.0.8 6379 @ mymaster 172.26.0.2 6379
redis-sentinel-lab-sentinel-2-1 | 1:X 05 Apr 2024 17:06:43.364 # +failover-state-reconf-slaves master mymaster 172.26.0.2 6379
redis-sentinel-lab-sentinel-2-1 | 1:X 05 Apr 2024 17:06:43.400 * +slave-reconf-sent slave 172.26.0.7:6379 172.26.0.7 6379 @ mymaster 172.26.0.2 6379
redis-sentinel-lab-sentinel-2-1 | 1:X 05 Apr 2024 17:06:44.451 # -odown master mymaster 172.26.0.2 6379
redis-sentinel-lab-sentinel-2-1 | 1:X 05 Apr 2024 17:06:44.457 * +slave-reconf-inprog slave 172.26.0.7:6379 172.26.0.7 6379 @ mymaster 172.26.0.2 6379
redis-sentinel-lab-sentinel-2-1 | 1:X 05 Apr 2024 17:06:44.457 * +slave-reconf-done slave 172.26.0.7:6379 172.26.0.7 6379 @ mymaster 172.26.0.2 6379
redis-sentinel-lab-sentinel-2-1 | 1:X 05 Apr 2024 17:06:44.525 # +failover-end master mymaster 172.26.0.2 6379
redis-sentinel-lab-sentinel-2-1 | 1:X 05 Apr 2024 17:06:44.525 # +switch-master mymaster 172.26.0.2 6379 172.26.0.8 6379
redis-sentinel-lab-sentinel-2-1 | 1:X 05 Apr 2024 17:06:44.528 * +slave slave 172.26.0.7:6379 172.26.0.7 6379 @ mymaster 172.26.0.8 6379
redis-sentinel-lab-sentinel-2-1 | 1:X 05 Apr 2024 17:06:44.535 # Failed to resolve hostname 'redis-master'
redis-sentinel-lab-sentinel-2-1 | 1:X 05 Apr 2024 17:06:44.535 * +slave slave :6379 6379 @ mymaster 172.26.0.8 6379
|
這台就是被選為主責切換 master 的 sentinel,可以看到整個過程
- 挑一台 slave 提升為 master
- 重新設定 slave
- 將 mymaster ip 設成新的 master ip
查看程式 log:
1
2
3
4
5
6
7
| redis-sentinel-lab-app-1 | redis ping PONG <nil>
redis-sentinel-lab-app-1 | client info addr 172.26.0.5:52730
redis-sentinel-lab-app-1 | client info laddr 172.26.0.2:6379
redis-sentinel-lab-app-1 | redis: 2024/04/05 17:06:43 sentinel.go:700: sentinel: new master="mymaster" addr="172.26.0.8:6379"
redis-sentinel-lab-app-1 | redis ping PONG <nil>
redis-sentinel-lab-app-1 | client info addr 172.26.0.5:32854
redis-sentinel-lab-app-1 | client info laddr 172.26.0.8:6379
|
- 程式從 sentinel 拿到新的 master ip,下一個指令就連到新的 ip 了
寫在最後#
以上是對 redis sentinel 的小型測試。測試過程讓我們了解 redis sentinel 是如何實現容錯移轉 (failover) 機制以滿足高可用性。
測試檔案都放到我的 github repository 裡: nyogjtrc/redis-sentinel-lab
Reference#