一主二从三哨兵

一、架构组成

“一主二从三哨兵” 架构由 3 类角色组成,共 6 个容器(或实例):

  • 1 个主节点(Master):处理读写请求,是核心数据节点。
  • 2 个从节点(Slave):通过主从复制同步主节点数据,仅处理读请求(默认),主节点故障时可被哨兵选举为新主节点。
  • 3 个哨兵节点(Sentinel):监控主从节点状态,判断主节点是否下线,当主节点故障时自动触发故障转移(Failover),将某个从节点升级为新主节点。

二、核心组件作用

1. 主节点(Master)

  • 功能:接收所有写请求(如 SETHSET),并通过主从复制将数据同步到从节点。
  • 特点:默认只有主节点可写,从节点只读(通过配置 slave-read-only yes 控制),确保数据一致性。
  • Docker 配置关键点
    • 绑定所有网络接口(bind 0.0.0.0),允许容器外部访问。
    • 配置持久化(RDB/AOF),避免数据丢失。
    • 设置访问密码(requirepass)和主从同步密码(masterauth,与从节点一致)。

2. 从节点(Slave)

  • 功能:通过 replicaof <master-ip> <master-port> 配置同步主节点数据,仅处理读请求(分担主节点读压力)。
  • 特点:主节点故障后,可被哨兵选举为新主节点,升级后自动切换为可写状态。
  • Docker 配置关键点
    • 与主节点使用相同的密码配置(masterauth 需匹配主节点 requirepass)。
    • 关闭保护模式(protected-mode no),允许跨容器访问。
    • 配置持久化路径(与主节点独立,避免数据冲突)。

3. 哨兵节点(Sentinel)

  • 功能
    • 监控:定期检查主从节点是否存活(通过 PING 命令)。
    • 判断下线:当主节点不可达时,先标记为 “主观下线(SDOWN)”;若超过 quorum 个哨兵达成共识,则标记为 “客观下线(ODOWN)”。
    • 故障转移:客观下线后,选举哨兵 leader 执行故障转移,将最优从节点升级为新主节点,其他从节点切换到新主节点同步数据。
  • Docker 配置关键点
    • 配置监控主节点(sentinel monitor <master-name> <master-ip> <master-port> <quorum>),quorum 为达成下线共识的最小哨兵数量(3 哨兵建议设为 2)。
    • 设置主节点认证密码(sentinel auth-pass <master-name> <password>)。
    • 配置下线检测超时(sentinel down-after-milliseconds,建议 1000-3000ms)和故障转移超时(sentinel failover-timeout)。

主从配置

docker-compose.yaml

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'
services:
redis1:
image: redis
container_name: redis1
hostname: redis1
ports:
- 6379:6379
- 16379:16379
networks:
- redis_net
volumes:
- ./redis1/conf:/etc/conf
- ./redis1/data:/data
command:
redis-server /etc/conf/redis.conf

redis2:
image: redis
container_name: redis2
hostname: redis2
ports:
- 6380:6380
- 16380:16380
networks:
- redis_net
volumes:
- ./redis2/conf:/etc/conf
- ./redis2/data:/data
command:
redis-server /etc/conf/redis.conf

redis3:
image: redis
container_name: redis3
hostname: redis3
ports:
- 6381:6381
- 16381:16381
networks:
- redis_net
volumes:
- ./redis3/conf:/etc/conf
- ./redis3/data:/data
command:
redis-server /etc/conf/redis.conf

networks:
redis_net:
name: redis_net
driver: bridge
1
2
3
4
5
# 先启动服务使其创建该有的文件(需要刷新一下目录)
cd redis_service/
docker compose up

# 会报错缺少配置文件,此时再去写对应的配置文件

/redis_service/redis1/conf/ 下新建主机配置文件 redis.conf

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
databases 10 
bind 0.0.0.0
#监听
port 6379
#访问密码
requirepass 123456
masterauth 123456
#持久化文件路径
dir /data
#持久化文件
dbfilename dump.rdb
#启用 RDB 持久化文件的压缩
rdbcompression yes
#如果后台保存出错则停止写入
stop-writes-on-bgsave-error yes
#关闭保护模式
protected-mode no
#在空数据库时进行无盘复制加载
repl-diskless-load on-empty-db
#守护进程的方式运行
#daemonize yes


#持久化策略
#表示如果在 900 秒(15 分钟)内有至少 1 次数据修改操作,则执行一次 RDB 持久化。
save 900 1
#在 300 秒(5 分钟)内有至少 10 次数据修改操作,就执行一次 RDB 持久化。
save 300 10
save 60 10000

#日志
logfile redis.log

/redis_service/redis2/conf/ 下新建从机配置文件 redis.conf
配置后也在/redis_service/redis3/conf/复制一份,并修改为对应监听端口:6381

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
#实例化数据库
databases 10
bind 0.0.0.0
#监听
port 6380
#访问密码和主机密码
requirepass 123456
masterauth 123456
#持久化文件路径
dir /data
#持久化文件
dbfilename dump.rdb
#指定本地数据存储压缩
rdbcompression yes
stop-writes-on-bgsave-error yes
protected-mode no
repl-diskless-load on-empty-db
#daemonize yes
#protected-mode

#持久化策略
save 900 1
save 300 10
save 60 10000
#日志路径
logfile redis.log
replicaof redis1 6379

验证测试

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
# 再次启动
docker compose up -d

# 查看状态
docker container ls
cd redis_service
docker compose ps
docker compose stats

# 进入主机容器验证
docker exec -it redis1 bash
redis-cli
auth 123456
info

# 打开一个新的终端窗口进入从机
docker exec -it redis2 redis-cli -p 6380
auth 123456
info

# 测试主从同步
# 主机执行以下操作
set class_name zhiyun70
# 从机执行以下命令
get class_name
# 若能成功输出"zhiyun70"说明已实现主从同步

哨兵配置

修改docker-compose.yaml配置文件(添加sentinel1、sentinel2、sentinel3)

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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
version: '3'
services:
redis1:
image: redis
container_name: redis1
hostname: redis1
ports:
- 6379:6379
- 16379:16379
networks:
- redis_net
volumes:
- ./redis1/conf:/etc/conf
- ./redis1/data:/data
command:
redis-server /etc/conf/redis.conf

redis2:
image: redis
container_name: redis2
hostname: redis2
ports:
- 6380:6380
- 16380:16380
networks:
- redis_net
volumes:
- ./redis2/conf:/etc/conf
- ./redis2/data:/data
command:
redis-server /etc/conf/redis.conf

redis3:
image: redis
container_name: redis3
hostname: redis3
ports:
- 6381:6381
- 16381:16381
networks:
- redis_net
volumes:
- ./redis3/conf:/etc/conf
- ./redis3/data:/data
command:
redis-server /etc/conf/redis.conf

sentinel1:
image: redis
container_name: sentinel1
hostname: sentinel1
ports:
- 26379:26379
networks:
- redis_net
volumes:
- ./sentinel1/conf:/etc/conf
- ./sentinel1/data:/data
command:
redis-sentinel /etc/conf/sentinel.conf

sentinel2:
image: redis
container_name: sentinel2
hostname: sentinel2
ports:
- 26380:26379
networks:
- redis_net
volumes:
- ./sentinel2/conf:/etc/conf
- ./sentinel2/data:/data
command:
redis-sentinel /etc/conf/sentinel.conf

sentinel3:
image: redis
container_name: sentinel3
hostname: sentinel3
ports:
- 26381:26379
networks:
- redis_net
volumes:
- ./sentinel3/conf:/etc/conf
- ./sentinel3/data:/data
command:
redis-sentinel /etc/conf/sentinel.conf

networks:
redis_net:
name: redis_net
driver: bridge
1
2
3
# 删除原来的服务重新启动
docker compose down
docker compose up -d

刷新目录后会生成三个文件夹(sentinel1、sentinel2、sentinel3)
/redis_service/sentinel1/conf/ 下新建哨兵配置文件 sentinel.conf
配置后分别复制一份到sentinel2、sentinel3的conf下

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
#操作端口
#绑定所有网络接口
bind 0.0.0.0
#哨兵服务监听的端口。
port 26379
#指定进程 ID 文件的路径
pidfile "/data/redis-sentinel.pid"
#工作目录
dir "/tmp"
#设置访问哨兵的密码
requirepass 123456
#docker必关 不以后台进程方式运行
daemonize no
#关闭保护模式
protected-mode no
#指定日志文件路径
logfile "/data/redis-sentinel.log"
#启用主机名解析
sentinel resolve-hostnames yes
#监控名为redisMaster的主节点,节点名为redis1,端口为 6379,需要至少 2 个哨兵
sentinel monitor redisMaster redis1 6379 2
#该主节点的认证密码
sentinel auth-pass redisMaster 123456
#在指定毫秒数后认为该主节点主观下线。
sentinel down-after-milliseconds redisMaster 100
#故障转移时同时同步的从节点数量为 1 个
sentinel parallel-syncs redisMaster 1
#故障转移超时时间
sentinel failover-timeout redisMaster 600

启动服务时需要关闭sentinel.conf的编辑窗口,因为运行时需要往上面写入日志,打开窗口会占用其写入进程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 对每个sentinel.conf赋予写权限
chmod a+w /root/redis_service/sentinel1/conf/sentinel.conf
chmod a+w /root/redis_service/sentinel2/conf/sentinel.conf
chmod a+w /root/redis_service/sentinel3/conf/sentinel.conf
# 对每个data文件夹赋予写权限
chmod a+w /root/redis_service/sentinel1/data
chmod a+w /root/redis_service/sentinel2/data
chmod a+w /root/redis_service/sentinel3/data

# 删除原来的服务重新启动
cd /root/redis_service/
docker compose down
docker compose up -d
docker container ls

# 打开主机和从机终端执行以下命令查看状态
docker exec -it redis2 redis-cli -p 6380
auth 123456
info

# 打开一个新终端窗口进入哨兵容器查看状态
docker exec -it sentinel3 redis-cli -p 26379
auth 123456
info

验证测试

1
2
3
4
5
6
7
8
9
10
11
12
13
cd /root/redis_service

# 停掉其中一个服务器redis1
docker container stop redis1

# 哨兵终端查看
info sentinel
# 一键查看
docker exec -it sentinel1 redis-cli -p 26379 -a 123456 info sentinel

# 此时若主机端口由6379变为6380,则再前往redis2查看验证
docker exec -it redis2 redis-cli -p 6380 -a 123456 info
# Replication下的role由原来的slave(从机)变为master(主机),说明成功实现主从切换