Redis一站式指南三:用 Docker+Redis 哨兵,教你搞懂自动故障转移

Docker+Redis哨兵实现自动故障转移

一.主从复制中的主节点问题

主从复制最大的问题在于主节点。若主节点出现故障,从节点虽能提供读操作,但无法自动升级为主节点,也不能替换原有主节点对应的角色,此时需人工(程序猿或运维)手动恢复主节点,过程繁琐。

举个栗子~:

1.断开主节点

service redis-service stop

2.子节点查看详细

还是能查看数据,但是依然不能进行修改操作

1.1Redis 哨兵自动替换主节点

从节点和主节点断开连接的两种情况

  1. 从节点主动和主节点断开连接(slaveof no one):意味着要主动修改 Redis 的组成结构,此时从节点能够晋升成主节点。
  2. 主节点挂了:从节点不会晋升成主节点,必须通过人工干预恢复主节点,这是脱离掌控的高可用典型问题。

1.2哨兵机制

原理:

哨兵机制通过独立进程体现,与 redis - server 是不同进程。redis - sentinel 不负责存储数据,只对其他 redis - server 进程起监控作用。通常有多个哨兵节点构成集合,单个哨兵节点挂掉不影响整体。

实际开发中监控程序的重要性

服务器需高可用性,7 * 24 小时运行,长期运行会有意外,不能全靠人工监控。需编写监控程序,发现服务器运行异常,还需搭配报警程序(短信、电话、邮件等),及时通知程序猿,报警不仅给程序猿,还会给其领导。

程序猿恢复主节点故障的步骤

  1. 先查看主节点能否抢救。
  2. 若主节点无法短时间解决或原因不明,挑一个从节点设为新主节点:
    • 把选中的从节点通过 slaveof no one 自立山头。
    • 把其他从节点修改 slaveof 的主节点 ip port,连上新主节点。
    • 告知客户端修改配置,连接新主节点进行数据操作。
    • 之前挂掉的主节点修好后可作为新从节点挂到机器中。

人工干预的问题

人工干预繁琐且易出错,恢复过程可能需半小时以上,期间 Redis 不能写,不合适。

1.3Redis 哨兵核心功能

  1. 监控:哨兵进程监控现有的 redis master 和 slave,进程间建立 tcp 长连接,定期发送心跳包,及时发现主机是否挂掉。
  2. 自动的故障转移:若主节点挂掉,多个哨兵节点共同认同此事防止误判,然后推举一个 leader,由 leader 从从节点中挑选新主节点,挑选后哨兵节点自动控制被选中节点执行 slaveof no one,并控制其他从节点修改 slaveof 到新主节点。
  3. 通知:哨兵节点自动通知客户端程序新主节点是谁,客户端后续针对新主节点操作。

哨兵节点设置原则

在分布式系统中应避免单点,哨兵节点最好搞奇数个,最少 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:登录阿里云

  1. 打开 阿里云官网

  2. 登录你的阿里云账号(没有的话先注册一个,免费)

步骤 2:找到镜像加速器地址

  1. 登录后,搜索 容器镜像服务(英文可能是 Container Registry

  2. 进入后,在左侧菜单找到 镜像加速器

  3. 这里会显示一个你的专属加速器地址,长这样:

    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 并且客户端或者外部脚本主动切换)

    • 这样就导致了集群中出现两个“主节点”,造成数据不一致风险。

    没影响当前操作,先搁置先~

    2.6.4 leader选择规则

    2.6.5 leader需要做啥事

    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值