一.主从复制中的主节点问题
主从复制最大的问题在于主节点。若主节点出现故障,从节点虽能提供读操作,但无法自动升级为主节点,也不能替换原有主节点对应的角色,此时需人工(程序猿或运维)手动恢复主节点,过程繁琐。
举个栗子~:
1.断开主节点
service redis-service stop
2.子节点查看详细
还是能查看数据,但是依然不能进行修改操作
1.1Redis 哨兵自动替换主节点
从节点和主节点断开连接的两种情况
- 从节点主动和主节点断开连接(slaveof no one):意味着要主动修改 Redis 的组成结构,此时从节点能够晋升成主节点。
- 主节点挂了:从节点不会晋升成主节点,必须通过人工干预恢复主节点,这是脱离掌控的高可用典型问题。
1.2哨兵机制
原理:
哨兵机制通过独立进程体现,与 redis - server 是不同进程。redis - sentinel 不负责存储数据,只对其他 redis - server 进程起监控作用。通常有多个哨兵节点构成集合,单个哨兵节点挂掉不影响整体。
实际开发中监控程序的重要性
服务器需高可用性,7 * 24 小时运行,长期运行会有意外,不能全靠人工监控。需编写监控程序,发现服务器运行异常,还需搭配报警程序(短信、电话、邮件等),及时通知程序猿,报警不仅给程序猿,还会给其领导。
程序猿恢复主节点故障的步骤
- 先查看主节点能否抢救。
- 若主节点无法短时间解决或原因不明,挑一个从节点设为新主节点:
- 把选中的从节点通过 slaveof no one 自立山头。
- 把其他从节点修改 slaveof 的主节点 ip port,连上新主节点。
- 告知客户端修改配置,连接新主节点进行数据操作。
- 之前挂掉的主节点修好后可作为新从节点挂到机器中。
人工干预的问题
人工干预繁琐且易出错,恢复过程可能需半小时以上,期间 Redis 不能写,不合适。
1.3Redis 哨兵核心功能
- 监控:哨兵进程监控现有的 redis master 和 slave,进程间建立 tcp 长连接,定期发送心跳包,及时发现主机是否挂掉。
- 自动的故障转移:若主节点挂掉,多个哨兵节点共同认同此事防止误判,然后推举一个 leader,由 leader 从从节点中挑选新主节点,挑选后哨兵节点自动控制被选中节点执行 slaveof no one,并控制其他从节点修改 slaveof 到新主节点。
- 通知:哨兵节点自动通知客户端程序新主节点是谁,客户端后续针对新主节点操作。
哨兵节点设置原则
在分布式系统中应避免单点,哨兵节点最好搞奇数个,最少 3 个,因为单个哨兵节点易出问题,若其挂掉且后续 Redis 节点也挂,就无法自动恢复,且网络数据易出问题,单哨兵节点误判概率高,影响大。
二.实操环节
Redis 哨兵模式里,6 个节点(3 个哨兵 + 1 主 2 从 ),理论上要部署在 6 台不同服务器 。这样每个节点独立,不会因单机故障、资源冲突影响整个集群,保障高可用 。
考虑到如果是学生,在实际学习或测试时,可能只有 1 台云服务器 ,只能把 6 个节点塞到同一台机器。但这么做 生产环境没意义 (因为单机故障会让整个集群崩,失去高可用价值 ),纯粹是没办法的妥协 。
1.单服务器部署哨兵集群的痛点:
把多个节点放同一服务器,会遇到 “资源冲突” 问题:
- 节点间依赖的 端口、配置文件、数据文件 容易打架(比如多个 Redis 实例都想用 6379 端口,直接冲突 )。
- 想正常部署,得 小心翼翼避坑 :手动改端口、分配置文件路径、隔数据存储目录…… 操作和最开始手动配主从结构一样 繁琐 ,而且和 “多服务器部署” 差异极大,后续维护、模拟真实场景也麻烦 。
2.Docker 解决思路:轻量隔离,简化部署
为解决单服务器多节点冲突问题,引入 Docker 。先理解 Docker 是啥:
核心实体概念:
- Docker 容器:轻量级虚拟机,可基于镜像运行,隔离应用环境
- Docker 镜像:类似 “可执行程序”,容器从镜像创建;可自己构建,或从 Docker Hub(类似镜像仓库,有大佬分享的镜像,也有 Redis 官方镜像 )拉取
- Docker Compose:辅助 Docker 批量管理容器的工具
补充:
- 镜像和容器关系:像 “可执行程序” 与 “进程”,镜像静态存配置,容器动态运行
- 镜像内容:拉取的 Redis 镜像,包含精简 Linux 系统 + 装好的 Redis,用它建容器就能直接跑 Redis 服务,简化部署
(一)Docker 类比虚拟机(但更轻量)
- 虚拟机(VM):在一个电脑上,用软件模拟 “新电脑”(硬件级隔离 ),能跑独立系统,但 特别吃资源 (要模拟 CPU、内存、硬盘,云服务器扛不住多开 )。
- Docker:类似 “轻量级虚拟机”,隔离应用环境 (不是硬件级,是进程、文件级 ),不用模拟完整硬件,资源占用少 。哪怕配置差的云服务器,也能轻松开几个 Docker 容器,模拟多节点部署 。
(二)Docker 解决单服务器部署痛点
用 Docker 给每个节点(哨兵、主从 Redis )套个 “容器” ,每个容器:
- 有独立的网络、端口、文件系统 。比如给主 Redis 容器开 6379 端口,从 Redis 容器开 6380、6381,互不干扰 。
- 配置、数据文件放容器内部(或挂载到主机特定目录),自动隔离,不用手动改一堆路径避冲突 。
- 相当于在 1 台服务器上,用 Docker 虚拟出多个 “小环境”,模拟多服务器部署的效果,还能简化配置、避免冲突 。
2.1安装docker和docker-compose
核心实体与概念:
- 配置文件作用:定义要创建的容器、容器运行参数,实现批量启动 / 停止容器
- 配置文件格式:采用 YAML(yml)格式,类比 Spring 框架也用 yml 做配置文件
应用逻辑:
通过编写 yml 配置文件,描述容器创建信息(含容器列表、各容器参数 ),之后用 Docker Compose 等工具,一条命令(如 docker-compose up -d
启动、docker-compose down
停止 )就能批量管理容器生命周期,简化多容器部署运维 。
ubantu命令:
apt install docker-compose
2.2停掉之前的redis服务器
2.3dockers下载redis镜像
docker pull redis:5.0.9
如果显示连接不了docker hub ,按照下列步骤来
步骤 1:登录阿里云
-
打开 阿里云官网
-
登录你的阿里云账号(没有的话先注册一个,免费)
步骤 2:找到镜像加速器地址
-
登录后,搜索 容器镜像服务(英文可能是 Container Registry)
-
进入后,在左侧菜单找到 镜像加速器
-
这里会显示一个你的专属加速器地址,长这样:
https://xxxxxx.mirror.aliyuncs.com (xxxxxx 是你的账号 ID)
步骤 3:配置到 Docker
在你的服务器上运行:
sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<EOF { "registry-mirrors": [ "你的阿里云加速器地址" ] } EOF
⚠️ 记得把 "你的阿里云加速器地址" 换成刚才在阿里云看到的那个地址。
步骤 4:重启 Docker
sudo systemctl daemon-reload
sudo systemctl restart docker
步骤 5:重新拉镜像
docker pull redis:5.0.9
这次应该会直接从阿里云节点下载,速度很快。
98.3MB的操作系统部分和 Redis 本体部分
2.4.docker-compose来进行容器编排
2.4.1创建三个容器,作为redis的数据节点(一个主两个从)
- mkdir redis:在当前目录创建名为 redis 的文件夹,用于收纳后续 Redis 相关文件。
- cd redis:切换工作目录到刚创建的 redis 文件夹,后续操作在此目录内进行。
- mkdir redis - data:在 redis 文件夹里,创建 redis - data 子文件夹,常用来存 Redis 数据文件(如持久化数据 )。
- mkdir redis - sentinel:在 redis 文件夹内,创建 redis - sentinel 子文件夹,用于放置哨兵模式相关配置、脚本等 。
- cd redis - data/:切换工作目录到 redis - data 文件夹,后续操作聚焦于此 。
- vim docker - compose.yml:用 vim 编辑器打开(或新建)docker - compose.yml 文件,用于编写 Docker Compose 的配置,定义 Redis 相关服务、部署规则等 。
version: '3.7'
services:
master:
image: 'redis:5.0.9'
container_name: redis-master
restart: always
command: redis-server --appendonly yes
ports:
- 6379:6379
slave1:
image: 'redis:5.0.9'
container_name: redis-slave1
restart: always
command: redis-server --appendonly yes --slaveof redis-master 6379
ports:
- 6380:6379
slave2:
image: 'redis:5.0.9'
container_name: redis-slave2
restart: always
command: redis-server --appendonly yes --slaveof redis-master 6379
ports:
- 6381:6379
~
~
查看三个容器是否成功
2.4.2创建三个容器,作为redis的哨兵节点
version: '3.7'
services:
sentinel1:
image: 'redis:5.0.9'
container_name: redis-sentinel-1
restart: always
command: redis-sentinel /etc/redis/sentinel.conf
volumes:
- ./sentinel1.conf:/etc/redis/sentinel.conf
ports:
- 26379:26379
sentinel2:
image: 'redis:5.0.9'
container_name: redis-sentinel-2
restart: always
command: redis-sentinel /etc/redis/sentinel.conf
volumes:
- ./sentinel2.conf:/etc/redis/sentinel.conf
ports:
- 26380:26379
sentinel3:
image: 'redis:5.0.9'
container_name: redis-sentinel-3
restart: always
command: redis-sentinel /etc/redis/sentinel.conf
volumes:
- ./sentinel3.conf:/etc/redis/sentinel.conf
ports:
- 26381:26379
networks:
default:
external:
name: redis-data_default
配置哨兵节点配置文件
bind 0.0.0.0
port 26379
sentinel monitor redis-master redis-master 6379 2
sentinel down-after-milliseconds redis-master 1000
再复制两份
启动:
docker-compose up -d
查看日志:
docker-compose logs
2.5演示哨兵节点功能
root@LHY:~/redis/redis-sentinel# docker ps -a
2.5.1停止主节点:
docker stop redis-master
2.5.2查看哨兵节点日志情况
- Sentinel 发现主节点 redis-master (172.19.0.2:6379) 处于主观下线状态(+sdown 和 +odown,也就是 Sentinel 自己判断主节点挂了)
- Sentinel 启动了自动故障转移流程(+try-failover)
- Sentinel 投票选举主节点领导,但投票后失败了(-failover-abort-not-elected)
- 并且设置了下一次尝试故障转移的延迟(Next failover delay)
2.5.3查看子节点replication,谁成了主节点
- 端口 6380 的实例是 从节点(role:slave),它的主节点是 172.19.0.4:6379,连接正常(master_link_status:up)。
- 端口 6381 的实例是 主节点(role:master),且有一个从节点连接(connected_slaves:1),从节点 IP 是 172.19.0.3:6379,状态在线。
是端口为6381的子节点变成主节点了
2.5.4重新启动端口6379节点
重写启动命令:
docker start redis-master
redis-cli -p 6379
docker start redis-master:启动名为 redis-master 的 Redis 容器(确保 Redis 服务运行)。
redis-cli -p 6379:连接本地的 Redis 服务,进入交互式命令行,方便你查看或操作 Redis。
查看6381端口,发现变成两个子节点连接了
*2.6 哨兵重新选取主节点的流程
2.6.1 主观下线
2.6.2 客观下线
2.6.3 哨兵投票leader
这段日志是在 Sentinel 的故障转移(failover)选举阶段:
-
三个 Sentinel 实例分别给自己投了票:
-
7e306443152983e1a064d99e4774455be261892e
投给了自己 -
60d432153554cfdcf9964d3b658e94a93c7d6c42
投给了自己 -
e579d34bdf549845cc935fb74218aeecb0e3d933
投给了自己
-
按理说应该会有投票过半来选出leader的,现在这个没有选出leader的情况我也不知咋整,但是也能实现子节点变为主节点,主节点还能修改数据(说明不是临时性的)
你说的情况其实挺典型,Sentinel 故障转移失败(没选出leader),但某个从节点却“自己”变成了主节点,这通常叫 “脑裂”(split-brain)现象。
现象解读
-
Sentinel 之间无法达成共识,导致没有选出新的主节点领导者(leader)
-
但某些从节点自己判断主节点不可用,自动升级为主节点,这种自动晋升是 Redis 自身的保护机制(不过默认 Redis 从节点不会自动升为主节点,除非你启用了
slave-serve-stale-data no
并且客户端或者外部脚本主动切换) -
这样就导致了集群中出现两个“主节点”,造成数据不一致风险。
没影响当前操作,先搁置先~