Redis ①④-哨兵
Redis 哨兵
在主从复制模式中,如果主节点挂掉了,需要手动把读写请求切换到从节点,这就需要人工干预,费时费力,甚至可能会出错.
Redis 哨兵(Sentinel)就是为了解决这一问题而产生的.
Redis 哨兵(Sentinel)相关名词解释:
名词 | 逻辑结构 | 物理结构 |
---|---|---|
主节点 | Redis 主服务 | 一个独立的 redis-server 进程 |
从节点 | Redis 从服务 | 一个独立的 redis-server 进程 |
Redis 数据节点 | 主从节点 | 主节点和从节点的进程 |
哨兵节点 | 监控 Redis 数据节点的节点 | 一个独立的 redis-sentinel 进程 |
哨兵节点合集 | 若干哨兵结点的抽象组合 | 若干 redis-sentinel 进程 |
Redis 哨兵(Sentinel) | Redis 提供的高可用方案 | 哨兵节点集合和 Redis 主从节点 |
应用方 | 泛指多个客户端 | 一个或多个连接 Redis 的进程 |
Redis Sentinel 架构图
sentinel 往往由多个节点,如果只设置一个的话,如果该节点挂掉了,整个服务就不可用了.sentinel 节点的个数一般设置为奇数,3 个节点较为推荐.(在分布式系统,要避免 “单点”,“冗余” 反而不是一件坏事)
Redis Sentinel 的主要功能:
- 监控:sentinel 会不断地检查主节点和从节点是否正常工作.
- 自动故障转移:当主节点出现故障时,会自动转移到其他从节点.
- 通知:当故障发生时,sentinel 可以通过 API 发送通知给客户端或者其他哨兵节点.
自动故障转移过程:
- 主节点故障,从节点同步连接中断,主从复制停止.
- 某个哨兵节点通过定期监控发现主节点故障,为了确保不是自己误判,该哨兵节点需要和其他哨兵节点进行确认,达成共识后,才真正认定该主节点故障.
- 认定确实是主节点故障后,哨兵节点之间通过 Raft 算法选举出一个 Leader,由 Leader 负责将失效主节点的从节点升为新主节点.
- 哨兵 Leader 开始执行故障转移,从失效主节点的从节点中选择一个,将其升级为新主节点,让其他从节点同步到新主节点,通知应用层转移到新主节点.
通过 Docker 部署 Redis 哨兵
安装 Docker 和 Docker Compose.
停止之前所有的 Redis 服务器
使用 Docker 拉取 Redis 镜像
docker pull redis:5.0.9
编排主从节点
创建 docker-compose.yml
文件
mkdir redis
cd redis
mkdir redis-data
cd redis-data
vim docker-compose.yml
version: '3.7'
services:master:image: 'redis:5.0.9'container_name: redis-masterrestart: alwayscommand: redis-server --appendonly yesports:- 6379:6379slave1:image: 'redis:5.0.9'container_name: redis-slave1restart: alwayscommand: redis-server --appendonly yes --slaveof redis-master 6379ports:- 6380:6379slave2:image: 'redis:5.0.9'container_name: redis-slave2restart: alwayscommand: redis-server --appendonly yes --slaveof redis-master 6379ports:- 6381:6379
启动所有容器
# 在 /redis/redis-data 目录下执行
docker-compose up -d# 查看启动日志
docker-compose logs# 停止所有容器
docker-compose down
验证是否成功
redis-cli -p 6379
info replicationredis-cli -p 6380
info replicationredis-cli -p 6381
编排哨兵节点
创建 docker-compose.yml
文件
cd ..
mkdir redis-sentinel
cd redis-sentinel
vim docker-compose.yml
version: '3.7'
services:sentinel1:image: 'redis:5.0.9'container_name: redis-sentinel-1restart: alwayscommand: redis-sentinel /etc/redis/sentinel.confvolumes:- ./sentinel1.conf:/etc/redis/sentinel.confports:- 26379:26379sentinel2:image: 'redis:5.0.9'container_name: redis-sentinel-2restart: alwayscommand: redis-sentinel /etc/redis/sentinel.confvolumes:- ./sentinel2.conf:/etc/redis/sentinel.confports:- 26380:26379sentinel3:image: 'redis:5.0.9'container_name: redis-sentinel-3restart: alwayscommand: redis-sentinel /etc/redis/sentinel.confvolumes:- ./sentinel3.conf:/etc/redis/sentinel.confports:- 26381:26379
networks:default:external:name: redis-data_default
创建 sentinel1.conf
、sentinel2.conf
、sentinel3.conf
文件,内容保持一致即可:
bind 0.0.0.0
port 26379
sentinel monitor redis-master redis-master 6379 2
sentinel down-after-milliseconds redis-master 1000
启动所有容器
# 在 /redis/redis-sentinel 目录下执行
docker-compose up -d# 查看启动日志
docker-compose logs
如果发现启动失败,且报如下错误:
redis-sentinel-3 | *** FATAL CONFIG FILE ERROR (Redis 8.0.0) ***
redis-sentinel-3 | Reading the configuration file,at line 3
redis-sentinel-3 | >>> 'sentinel monitor redis-master redis-master 6379 2'
redis-sentinel-3 | Can't resolve instance hostname.
这通常是主从节点和哨兵节点不在同一局域网,导致 redis-master 不能被正确解析到 IP 地址.
解决方法:
- 修改
/redis/redis-sentinel/docker-compose.yml
:
# 增加以下内容
networks:default:external:name: redis-data_default
网络的 name 可能不同,需要根据实际情况修改,通过 docker network ls
查看.
docker network ls
NETWORK ID NAME DRIVER SCOPE
04c0dbe75582 bridge bridge local
2873d9806bb3 host host local
555daeff6b48 none null local
6ec1a2f23d36 redis-data_default bridge local
重新启动所有容器
docker-compose downdocker-compose up -d
验证是否成功
docker ps -a
测试主节点故障转移
停止主节点
docker stop redis-master
等待 10 秒后,查看哨兵节点日志,可以看到有以下几条消息:
# +sdown master redis-master 172.19.0.3 6379
# +new-epoch 1
# +vote-for-leader d2b17359b64cbab6cd1af623ddf717d52eab48ba 1
# +odown master redis-master 172.19.0.3 6379 #quorum 3/2
# Next failover delay: I will not start a failover before Mon May 12 12:17:10 2025
# +config-update-from sentinel d2b17359b64cbab6cd1af623ddf717d52eab48ba 172.19.0.7 26379 @ redis-master 172.19.0.3 6379
# +switch-master redis-master 172.19.0.3 6379 172.19.0.2 6379
* +slave slave 172.19.0.4:6379 172.19.0.4 6379 @ redis-master 172.19.0.2 6379
* +slave slave 172.19.0.3:6379 172.19.0.3 6379 @ redis-master 172.19.0.2 6379
# +sdown slave 172.19.0.3:6379 172.19.0.3 6379 @ redis-master 172.19.0.2 6379
# -sdown slave 172.19.0.3:6379 172.19.0.3 6379 @ redis-master 172.19.0.2 6379
sdown
:该哨兵节点主观(subjective)检测到主节点下线.odown
:#quorum 3/2:三个哨兵都认同主节点下线(超过设置的半数以上),所以是客观(objective)认为主节点下线,一般来说就是真的主节点挂了.+new-epoch 1
:哨兵节点开始新的一轮投票,选举出新的领导者.+vote-for-leader d2###ba 1
:投票给 id 为 d2###ba 的哨兵节点,票数为 1.(一般会率先投给自己一票,但是只能投一票).通过观察另外两个哨兵节点,发现它们投给了该节点,所以该节点获得半数以上的票数,称为 Leader,由该节点负责故障转移.+config-update-from sentinel d2***ba 172.19.0.7 26379 @ redis-master 172.19.0.3 6379
:通知其他哨兵节点,自己已经成为 Leader,它来开始进行 redis-master 的故障转移.+switch-master redis-master 172.19.0.3 6379 172.19.0.2 6379
:将失效主节点的从节点 172.19.0.3 升级为新主节点.
主节点故障全过程
-
主观下线: 哨兵节点通过心跳包,判定 redis 服务器是否正常工作,如果心跳包没有如约而至,则说明 redis 服务器故障.
-
客观下线: 多个哨兵节点都认为该节点故障了(达到法定票数).
-
选举 Leader: 这些哨兵节点选举出一个 Leader,由 Leader 负责故障转移.
-
故障转移: Leader 选取一个从节点,将其升级为新主节点,其他从节点同步到新主节点.
一般通过以下参数选举:
- 优先级:每个 Redis 数据节点,都会在配置文件中,有一个优先级的设置:slave-priority,优先级越高的从节点,就会胜出.
- offset:最大的 offset 值,就胜出.
- runid:每个 redis 节点启动时随即生成一串数字,哪个大选哪个.
注意事项
- 哨兵节点不能只有一个.否则哨兵节点挂了也会影响系统可用性.
- 哨兵节点最好是奇数个.方便选举 Leader,得票更容易超过半数.
- 哨兵节点不负责存储数据.仍然是 Redis 主从节点负责存储.
- 哨兵 + 主从复制解决的问题是 “提高可用性”,不能解决 “数据极端情况下写丢失” 的问题.
riority,优先级越高的从节点,就会胜出. - offset:最大的 offset 值,就胜出.
- runid:每个 redis 节点启动时随即生成一串数字,哪个大选哪个.
注意事项
- 哨兵节点不能只有一个.否则哨兵节点挂了也会影响系统可用性.
- 哨兵节点最好是奇数个.方便选举 Leader,得票更容易超过半数.
- 哨兵节点不负责存储数据.仍然是 Redis 主从节点负责存储.
- 哨兵 + 主从复制解决的问题是 “提高可用性”,不能解决 “数据极端情况下写丢失” 的问题.
- 哨兵 + 主从复制不能提高数据的存储容量.当我们需要存的数据接近或者超过机器的物理内存,这样的结构就难以胜任了.