1 哨兵工作机制

1.1 环境架构

20220531161936

  • 每个哨兵节点,每 10 秒向已知的各个主从节点发送 info 命令,获取最新的拓扑结构关系和各个节点详细信息;
  • 每个哨兵节点每 1 秒向它已知的 Master、Slave 节点以及其他哨兵节点发送一个 ping 命令,从最后一次成功响应的时间开始,超过 down-after-milliseconds 设置的时间,则监测的哨兵标记为下线;
  • 如果一个 Master 节点被哨兵标记为下线,其它所有哨兵节点再次每秒 1 个 ping,未收到 pong 则确认下线,进入主观下线状态;
  • 确认 Master 主观下线的哨兵节点数,如果达到配置参数的值,则 Master 节点进入正式客观下线;
  • 如果确认 Master 主管下线的哨兵节点数,达不到配置的值,客观下线状态移除;
  • 如果哨兵节点能重新与 Master 节点进行 ping-pong ,主观下线状态移除。

1.2 为什么要用哨兵集群

  • 防止误判:对于节点的故障判断是由多个 Sentinel 节点共同完成。
  • 高可靠:即使个别 Sentinel 节点不可用,整个 Sentinel 节点集合依然是健壮的。

1.3 Leader 选举流程

​ 每个哨兵都有机会成为 leader 负责故障转移,哨兵节点之间相互请求,选举自身为 leader,每个哨兵节点必须同意或拒绝投票,当一个哨兵节点的投票数达到 哨兵总数 / 2 + 1 时,则选为 leader 负责故障转移。

1.4 故障转移

image-20220531105316357

负责故障转移的哨兵节点会按以下步骤选择 Master 节点:

  • 将现有节点拓扑结构中下线的节点过滤掉;
  • 在剩余的从节点中,选择 replica-priority(5.0 之前的 slave-priority)参数最小的节点作为 Master,0 代表不参与选举;
  • 如果未选出,则根据复制偏移量,选择最大的节点,复制偏移量越大代表数据越完整;
  • 若仍未选出,则根据 redis 运行时生成的随机 run id,选择最小 id 节点作为 Master。

选择出 Master 之后,改变其它节点的主从关系,并重写配置,使得主从关系的持久化;并依据新的 Master 节点的数据,使其它节点进行数据同步。

2 主从部署

一般来说,主从模式至少 1 个 master+2 个 slave 节点

主节点 6379,从节点 6380/6381,哨兵节点 4001/4002/4003
(详细配置参考)

2.1 Master 节点

2.1.1 配置

cat redis_6379.conf

1
2
3
4
5
6
7
8
9
10
bind 10.1.1.1
port 6379
# 主节点密码
requirepass qweasd
# 主从切换后新master节点密码
masterauth qweasd
daemonize yes
pidfile /var/run/redis_6379.pid
dir /opt/redis/redis_6379
dbfilename 6379_dump.rdb

2.1.2 启动

1
2
cd /opt/redis
src/redis-server redis_6379.conf

2.2 Slave 节点

2.2.1 配置

cat redis_6380.conf redis_6381.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
bind 10.1.1.1
# 每个节点设置自身的端口
port 6380
# slave节点密码
masterauth qweasd
# master节点密码
masterauth qweasd
# 配置文件建立初始的主从关系
# 也可以在从节点启动后,使用rediscli方式,slaveof ip port命令建立主从关系。
replicaof 10.1.1.1 6379
# 5.0之前使用slaveof配置
# slaveof 10.1.1.1 6379

# 后台启动
daemonize yes
pidfile /var/run/redis_6380.pid
dir /opt/redis/redis_6380
dbfilename 6380_dump.rdb

2.2.2 启动

分别启动 2 个从节点,默认从节点只读

1
2
3
cd /opt/redis
src/redis-server redis_6380.conf
src/redis-server redis_6381.conf

2.3 查看日志

2.3.1 Master 主节点,同步信息

1
2
3
4
5
6
7
8
9
1487:M 31 May 2022 04:46:16.774 * Replica 10.1.1.1:6379 asks for synchronization
1487:M 31 May 2022 04:46:16.774 * Full resync requested by replica 10.1.1.1:6379
......
1487:M 31 May 2022 04:46:16.894 * Synchronization with replica 10.1.1.1:6379 succeeded
......
1487:M 31 May 2022 04:46:18.738 * Replica 10.1.1.1:6380 asks for synchronization
1487:M 31 May 2022 04:46:18.738 * Full resync requested by replica 10.1.1.1:6380
......
1487:M 31 May 2022 04:46:18.805 * Synchronization with replica 10.1.1.1:6380 succeeded

2.3.2 Slave 从节点信息

1
2
3
4
5
6
7
8
9
1491:S 31 May 2022 04:46:18.734 * Connecting to MASTER 10.1.1.1:6379
1491:S 31 May 2022 04:46:18.735 * MASTER <-> REPLICA sync started
1491:S 31 May 2022 04:46:18.737 * Master replied to PING, replication can continue
......
1491:S 31 May 2022 04:46:18.754 * Full resync from master: cd06ef23f36a4b98e0b0126d04d667b5ec6031ce:0
1491:S 31 May 2022 04:46:18.805 * MASTER <-> REPLICA sync: receiving 176 bytes from master to disk
1491:S 31 May 2022 04:46:18.807 * MASTER <-> REPLICA sync: Flushing old data
1491:S 31 May 2022 04:46:18.810 * MASTER <-> REPLICA sync: Loading DB in memory
1491:S 31 May 2022 04:46:18.825 * MASTER <-> REPLICA sync: Finished with success

2.4 查看集群状态

使用 redis-cli 连接 master 查看信息如下:

1
2
3
4
5
6
7
10.1.1.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=10.1.1.1,port=6380,state=online,offset=1484,lag=1
slave1:ip=10.1.1.1,port=6381,state=online,offset=1484,lag=0
...

3 哨兵部署

3.1 配置

哨兵配置 sentinel_4001.conf、sentinel_4002.conf、sentinel_4003.conf

只需配置 master 节点地址,自动获取整个拓扑关系。

1
2
3
4
5
6
7
8
9
10
11
12
bind 10.1.1.1
# 具体哨兵节点的端口号
port 4001
daemonize yes
# 监听master节点,从master节点获取节点拓扑关系
# 2代表至少2个哨兵确认master下线,则标记为客观下线,开始选举和故障迁移 sineMaster是这个master的名字
sentinel monitor sineMaster 10.1.1.1 6379 2
# 主节点密码
sentinel auth-pass sineMaster qweasd
# 下线超时时间,毫秒
sentinel down-after-milliseconds sineMaster 3000
dir /opt/redis/sentinel_4001 # 工作路径

3.2 启动 3 个哨兵节点

1
2
3
4
cd /opt/redis
src/redis-sentinel sentinel_4001.conf
src/redis-sentinel sentinel_4002.conf
src/redis-sentinel sentinel_4003.conf

3.3 查看日志

1
2
3
4
5
6
1496:X 31 May 2022 05:09:03.984 # Sentinel ID is d62a1beae6b637f77f6e32233a4bb42ea5e0aee0
1496:X 31 May 2022 05:09:03.984 # +monitor master sineMaster 10.1.1.1 6379 quorum 2
1496:X 31 May 2022 05:09:03.987 * +slave slave 10.1.1.1:6379 10.1.1.1 6379 @ sineMaster 10.1.1.1 6379
1496:X 31 May 2022 05:09:03.992 * +slave slave 10.1.1.1:6380 10.1.1.1 6380 @ sineMaster 10.1.1.1 6379
1496:X 31 May 2022 05:09:04.380 * +sentinel sentinel ee753589ab5dea31a568e33eeee5aaf8366ebede 10.1.1.1 4002 @ sineMaster 10.1.1.1 6379
1496:X 31 May 2022 05:09:05.393 * +sentinel sentinel cbc1e91f109f153d0a2b49d81b039af57ad27309 10.1.1.1 4001 @ sineMaster 10.1.1.1 6379

3.4 查看哨兵集群状态

src/redis-cli -h 10.1.1.1 -p 4001

1
2
3
4
5
6
7
8
10.1.1.1:4001> info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=sineMaster,status=ok,address=10.1.1.1:6379,slaves=2,sentinels=3

4 集群维护

4.1 添加 slve 节点

4.1.1 新增 6382 配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
bind 10.1.1.1
#每个节点设置自身的端口
port 6382
# slave节点密码
requirepass "qweasd"
masterauth "qweasd"
#配置文件建立初始的主从关系
#也可以在从节点启动后,使用rediscli方式,slaveof ip port命令建立主从关系。

#5.0之前使用slaveof配置
#slaveof 10.1.1.1 6379
daemonize yes
pidfile "/var/run/redis_6382.pid"
dbfilename "6382_dump.rdb"
dir "/opt/redis/redis_6382"
# Generated by CONFIG REWRITE
save 3600 1
save 300 100
save 60 10000
user default on nopass sanitize-payload ~* &* +@all
replicaof 10.1.1.1 6380

4.1.2 启动

src/redis-server redis_6382.conf

4.1.3 查看节点信息

数据会自动同步

1
2
3
4
5
6
7
8
9
10
10.1.1.1:6382> keys *
1) "str1"
2) "str3"
3) "str4"
4) "str2"
10.1.1.1:6382> info replication
# Replication
role:slave
master_host:10.1.1.1
master_port:6380

4.2 master 节点下线维护

4.2.1 数据手动落盘

src/redis-cli -h 10.1.1.1 -p 6380 -a qweasd save

4.2.2 手动切换节点

1
2
3
4
5
6
7
8
9
10.1.1.1:4001> info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=sineMaster,status=ok,address=10.1.1.1:6380,slaves=3,sentinels=3
10.1.1.1:4001> sentinel failover sineMaster

4.2.3 查看新 master 节点

1
2
3
4
5
6
7
8
10.1.1.1:4001> info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=sineMaster,status=ok,address=10.1.1.1:6379,slaves=3,sentinels=3

4.2.4 查看 Redis 集群状态

1
2
3
4
5
6
7
8
info replication
# Replication
role:master
connected_slaves:3
slave0:ip=10.1.1.1,port=6382,state=online,offset=2502699,lag=0
slave1:ip=10.1.1.1,port=6381,state=online,offset=2502563,lag=1
slave2:ip=10.1.1.1,port=6380,state=online,offset=2502563,lag=1
...

4.2.5 测试数据 (可不操作直接进行下一步)

4.2.5.1 新 master 节点写入数据
1
2
10.1.1.1:6379> set str5 str5
OK
4.2.5.2 slave 节点查看数据
1
2
3
4
5
6
10.1.1.1:6382> keys *
1) "str3"
2) "str5"
3) "str4"
4) "str1"
5) "str2"

4.2.6 停掉原来的 master 节点

src/redis-cli -h 10.1.1.1 -p 6380 -a qweasd SHUTDOWN

5 高可用测试

5.1 主从同步测试

5.1.1 master 写入数据

1
2
3
4
5
6
7
8
src/redis-cli -h 10.1.1.1 -p 6379 -a qweasd
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
10.1.1.1:6379> set str1 str1
OK
10.1.1.1:6379> set str2 str2
OK
10.1.1.1:6379> set str3 str3
OK

5.1.2 查看 slave 节点

5.1.2.1 6380
1
2
3
4
10.1.1.1:6380> keys *
1) "str2"
2) "str1"
3) "str3"
5.1.2.2 6381
1
2
3
4
10.1.1.1:6381> keys *
1) "str3"
2) "str2"
3) "str1"

5.2 主从切换测试

5.2.1 停掉 master

src/redis-cli -h 10.0.16.12 -p 6379 -a qweasd SHUTDOWN

5.2.2 查看哨兵状态

可以看到 Sentinel 配置的 master 节点会自动切换成新的 ip
(命令参考)

1
2
3
4
5
6
7
8
info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=sineMaster,status=ok,address=10.1.1.1:6380,slaves=2,sentinels=3

5.2.3 查看 Redis 状态

slave 节点会自动切换到新的 master 节点

1
2
3
4
5
6
10.1.1.1:6380> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=10.1.1.1,port=6381,state=online,offset=2135687,lag=0
...

5.2.4 新 master 节点写入数据

1
2
10.1.1.1:6380> set str4 str4
OK

5.2.5 slave 节点查看数据

数据已经同步过来

1
2
3
4
5
10.1.1.1:6381> keys *
1) "str4"
2) "str3"
3) "str1"
4) "str2"

5.2.6 启动停掉的旧 master 节点

数据已经同步过来,并且自动修改 master 节点 ip,这里要注意,密码不会自动修改,需要配置提前加入masterauth参数

1
2
3
4
5
6
7
8
9
10
11
10.1.1.1:6379> keys *
1) "str1"
2) "str4"
3) "str2"
4) "str3"
10.1.1.1:6379> info replication
# Replication
role:slave
master_host:10.1.1.1
master_port:6380
master_link_status:up

5.2.7 查看配置文件

每一次故障转移,哨兵都会使各个节点的配置文件同步改变,无需人工干预维持主从关系。

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
52
53
54
55
56
57
58
59
60
61
62
63
sentinel_4001.conf

bind 10.1.1.1
#具体哨兵节点的端口号
port 4001
daemonize yes
#监听master节点,从master节点获取节点拓扑关系
#2代表至少2个哨兵确认master下线,则标记为客观下线,开始选举和故障迁移
sentinel monitor sineMaster 10.1.1.1 6380 2
sentinel auth-pass sineMaster qweasd
#下线超时时间,毫秒
sentinel down-after-milliseconds sineMaster 3000
dir "/opt/redis/sentinel_4001"
# Generated by CONFIG REWRITE
protected-mode no
pidfile "/var/run/redis.pid"
user default on nopass sanitize-payload ~* &* +@all
sentinel myid 444785ae34de834b920cedec95eb5425f873a2f2
sentinel config-epoch sineMaster 5
sentinel leader-epoch sineMaster 5
sentinel current-epoch 5
sentinel known-replica sineMaster 10.1.1.1 6379
sentinel known-replica sineMaster 10.1.1.1 6381
sentinel known-sentinel sineMaster 10.1.1.1 4003 872820ad14a3d0a4bfaf2ad79d18e0137f07b704
sentinel known-sentinel sineMaster 10.1.1.1 4002 7a985407acebebce1163cef703475e1074981a93

redis_6379.conf
bind 10.1.1.1
port 6379
#主节点密码
requirepass "qweasd"
daemonize yes
pidfile "/var/run/redis_6379.pid"
dbfilename "6379_dump.rdb"
masterauth qweasd
# Generated by CONFIG REWRITE
save 3600 1
save 300 100
save 60 10000
user default on sanitize-payload #a1bd1312d23002be258c9bb4642bbea77580353869a8ee8844e6940b7e0278b7 ~* &* +@all
dir "/opt/redis"
replicaof 10.1.1.1 6380

cat redis_6380.conf
bind 10.1.1.1
#每个节点设置自身的端口
port 6380
# slave节点密码
masterauth "qweasd"
requirepass "qweasd"
#配置文件建立初始的主从关系
#也可以在从节点启动后,使用rediscli方式,slaveof ip port命令建立主从关系。
#5.0之前使用slaveof配置
#slaveof 10.1.1.1 6379
daemonize yes
pidfile "/var/run/redis_6380.pid"
dbfilename "6380_dump.rdb"
dir "/opt/redis/redis_6380"
# Generated by CONFIG REWRITE
save 3600 1
save 300 100
save 60 10000
user default on #a1bd1312d23002be258c9bb4642bbea77580353869a8ee8844e6940b7e0278b7 ~* &* +@all

6 备份与恢复

参考: Redis备份与恢复]