Docker Image Version(自制)
redis-sentinel:7.0.11-alpine
Dockerfile 文件
FROM redis:7.0.11-alpine
RUN touch /data/redis-sentinel.conf
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
编译镜像
docker build -t redis-sentinel:7.0.11-alpine -f ./Dockerfile .
编译原因
因为 Redis Sentinel 哨兵模式必须采用配置文件启动,所以在镜像里面加入了/data/redis-sentinel.conf
空配置文件。
方案意义
在Redis Replication 主从模式下,Redis 不能在主节点故障的情况下,重新选举新的主节点。而 Redis 哨兵模式就是用来实现这一目的的,从而实现高可用的目标。
Docker Compose 启动
docker-compose -f sentinel.yml up -d
yaml 配置文件
version: '3.8'
services:
redis-master:
container_name: redis-master
image: redis:7.0.11-alpine
hostname: redis-master
restart: unless-stopped
ports:
- "6379:6379"
networks:
redis-sentinel:
logging:
driver: json-file
options:
max-size: 100m
max-file: '3'
volumes:
- redis-master:/data
command:
- redis-server
- --bind
- "0.0.0.0"
- --port
- "6379"
- --requirepass
- "ChangeMe"
- --appendonly
- "yes"
- --masterauth
- "ChangeMe"
redis-slave1:
container_name: redis-slave1
image: redis:7.0.11-alpine
hostname: redis-slave1
restart: unless-stopped
ports:
- "6380:6379"
networks:
redis-sentinel:
logging:
driver: json-file
options:
max-size: 100m
max-file: '3'
depends_on:
- redis-master
volumes:
- redis-slave1:/data
command:
- redis-server
- --bind
- "0.0.0.0"
- --port
- "6379"
- --requirepass
- "ChangeMe"
- --appendonly
- "yes"
- --masterauth
- "ChangeMe"
- --replicaof
- "redis-master 6379"
redis-slave2:
container_name: redis-slave2
image: redis:7.0.11-alpine
hostname: redis-slave2
restart: unless-stopped
ports:
- "6381:6379"
networks:
redis-sentinel:
logging:
driver: json-file
options:
max-size: 100m
max-file: '3'
depends_on:
- redis-master
volumes:
- redis-slave2:/data
command:
- redis-server
- --bind
- "0.0.0.0"
- --port
- "6379"
- --requirepass
- "ChangeMe"
- --appendonly
- "yes"
- --masterauth
- "ChangeMe"
- --replicaof
- "redis-master 6379"
redis-sentinel1:
container_name: redis-sentinel1
image: redis-sentinel:7.0.11-alpine
hostname: redis-sentinel1
restart: unless-stopped
ports:
- "16379:16379"
networks:
redis-sentinel:
logging:
driver: json-file
options:
max-size: 100m
max-file: '3'
command:
- redis-sentinel
- "/data/redis-sentinel.conf"
- --bind
- "0.0.0.0"
- --port
- "16379"
- --sentinel resolve-hostnames yes
- --sentinel monitor mymaster redis-master 6379 2
- --sentinel auth-pass mymaster ChangeMe
redis-sentinel2:
container_name: redis-sentinel2
image: redis-sentinel:7.0.11-alpine
hostname: redis-sentinel2
restart: unless-stopped
ports:
- "16380:16379"
networks:
redis-sentinel:
logging:
driver: json-file
options:
max-size: 100m
max-file: '3'
command:
- redis-sentinel
- "/data/redis-sentinel.conf"
- --bind
- "0.0.0.0"
- --port
- "16379"
- --sentinel resolve-hostnames yes
- --sentinel monitor mymaster redis-master 6379 2
- --sentinel auth-pass mymaster ChangeMe
redis-sentinel3:
container_name: redis-sentinel3
image: redis-sentinel:7.0.11-alpine
hostname: redis-sentinel3
restart: unless-stopped
ports:
- "16381:16379"
networks:
redis-sentinel:
logging:
driver: json-file
options:
max-size: 100m
max-file: '3'
command:
- redis-sentinel
- "/data/redis-sentinel.conf"
- --bind
- "0.0.0.0"
- --port
- "16379"
- --sentinel resolve-hostnames yes
- --sentinel monitor mymaster redis-master 6379 2
- --sentinel auth-pass mymaster ChangeMe
volumes:
redis-master:
redis-slave1:
redis-slave2:
networks:
redis-sentinel:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/16
配置解释
这里自建了一个名字叫redis-sentinel
的局域网,同时 Redis 已经提供了 NAT 模式的解决方案,但是在故障迁移的过程中,其会使用annuouce
相关参数,可能会造成部分网络访问不可达,从而无法进行故障迁移。如遇到多台机器部署,请自行修改配置,将 Docker 改变成host
访问模式。
monitor mymaster redis-master 6379 2
auth-pass mymaster ChangeMe
上面mymaster
指的的三台哨兵监控的主从集群名字命名为mymaster
,后面两个参数为主节点的 IP 和端口,这里 IP 最好不要指定死,写成host
主机名称格式,因为在实验过程中,它会出现指定固定 IP 失效的问题。2
则是代表客观投票数量quorum
,当投票数量为 2 的时候,该节点会被认为是主节点。第二行则是设置哨兵的通信密码。
故障迁移原理
当主节点下线的时候,哨兵会用 RAFT 算法选出一名leader
出来去执行故障迁移,而新的主节点则是根据副本的偏移指针offset
和优先级选出的。
信息查询
redis-cli -p 16379
> sentinel master mymaster
1) "name"
2) "mymaster"
3) "ip"
4) "172.20.0.2"
5) "port"
6) "6379"
7) "runid"
8) ""
9) "flags"
10) "s_down,master,disconnected"
11) "link-pending-commands"
12) "3"
13) "link-refcount"
14) "1"
15) "last-ping-sent"
16) "332471"
17) "last-ok-ping-reply"
18) "332471"
19) "last-ping-reply"
20) "332471"
21) "s-down-time"
22) "302434"
23) "down-after-milliseconds"
24) "30000"
25) "info-refresh"
26) "0"
27) "role-reported"
28) "master"
29) "role-reported-time"
30) "332471"
31) "config-epoch"
32) "0"
33) "num-slaves"
34) "0"
35) "num-other-sentinels"
36) "0"
37) "quorum"
38) "2"
39) "failover-timeout"
40) "180000"
41) "parallel-syncs"
42) "1"
redis-cli -p 16379
> sentinel replicas mymaster
1) 1) "name"
2) "172.20.0.7:6379"
3) "ip"
4) "172.20.0.7"
5) "port"
6) "6379"
7) "runid"
8) "d50fe92eae88a249cac74eac7a4860bf27cfb7ea"
9) "flags"
10) "slave"
11) "link-pending-commands"
12) "0"
13) "link-refcount"
14) "1"
15) "last-ping-sent"
16) "0"
17) "last-ok-ping-reply"
18) "147"
19) "last-ping-reply"
20) "147"
21) "down-after-milliseconds"
22) "30000"
23) "info-refresh"
24) "2063"
25) "role-reported"
26) "slave"
27) "role-reported-time"
28) "83556"
29) "master-link-down-time"
30) "0"
31) "master-link-status"
32) "ok"
33) "master-host"
34) "172.20.0.2"
35) "master-port"
36) "6379"
37) "slave-priority"
38) "100"
39) "slave-repl-offset"
40) "17317"
41) "replica-announced"
42) "1"
2) 1) "name"
2) "172.20.0.6:6379"
3) "ip"
4) "172.20.0.6"
5) "port"
6) "6379"
7) "runid"
8) "c2c96920f2d609b480aaffebaa2ab377192061de"
9) "flags"
10) "slave"
11) "link-pending-commands"
12) "0"
13) "link-refcount"
14) "1"
15) "last-ping-sent"
16) "0"
17) "last-ok-ping-reply"
18) "146"
19) "last-ping-reply"
20) "146"
21) "down-after-milliseconds"
22) "30000"
23) "info-refresh"
24) "2063"
25) "role-reported"
26) "slave"
27) "role-reported-time"
28) "83567"
29) "master-link-down-time"
30) "0"
31) "master-link-status"
32) "ok"
33) "master-host"
34) "172.20.0.2"
35) "master-port"
36) "6379"
37) "slave-priority"
38) "100"
39) "slave-repl-offset"
40) "17317"
41) "replica-announced"
42) "1"
redis-cli -p 16379
> sentinel sentinels mymaster
1) 1) "name"
2) "4f403bfbc3e217abfd5ee1d41d57ab47c57f2460"
3) "ip"
4) "172.20.0.4"
5) "port"
6) "16379"
7) "runid"
8) "4f403bfbc3e217abfd5ee1d41d57ab47c57f2460"
9) "flags"
10) "sentinel"
11) "link-pending-commands"
12) "0"
13) "link-refcount"
14) "1"
15) "last-ping-sent"
16) "0"
17) "last-ok-ping-reply"
18) "51"
19) "last-ping-reply"
20) "51"
21) "down-after-milliseconds"
22) "30000"
23) "last-hello-message"
24) "101"
25) "voted-leader"
26) "?"
27) "voted-leader-epoch"
28) "0"
2) 1) "name"
2) "22ba98e404eca360be059f0abd8ef745e97a9760"
3) "ip"
4) "172.20.0.5"
5) "port"
6) "16379"
7) "runid"
8) "22ba98e404eca360be059f0abd8ef745e97a9760"
9) "flags"
10) "sentinel"
11) "link-pending-commands"
12) "0"
13) "link-refcount"
14) "1"
15) "last-ping-sent"
16) "0"
17) "last-ok-ping-reply"
18) "51"
19) "last-ping-reply"
20) "51"
21) "down-after-milliseconds"
22) "30000"
23) "last-hello-message"
24) "694"
25) "voted-leader"
26) "?"
27) "voted-leader-epoch"
28) "0"