在这里插入图片描述

📃个人主页:island1314

⛺️ 欢迎关注:👍点赞 👂🏽留言 😍收藏 💞 💞 💞

  • 生活总是不会一帆风顺,前进的道路也不会永远一马平川,如何面对挫折影响人生走向 – 《人民日报》


一、前言

由于对 Redis 的许多概念都有不同的名词解释,所以在介绍 Redis Sentinel之前,先对几个名词概念进行必要的说明

  1. 主节点:独立的 redis-server 进程。
  2. 从节点:独立的 redis-server 进程,作为主节点的数据备份并分担读压力。
  3. 数据节点:包括主节点和从节点。
  4. 哨兵节点:监控数据节点的独立 redis-sentinel 进程。
  5. 哨兵节点集合:多个 redis-sentinel 进程的组合。
  6. Redis 哨兵(Sentinel):Redis 提供的高可用方案,哨兵节点 和 Redis 主从节点
  7. 应用方:一个或多个连接Redis的进程。

1. 主从复制的问题

Redis 的主从复制模式可以将主节点的数据改变同步给从节点,这样从节点就可以起到两个作用:

  • 第一,作为主节点的一个备份,一旦主节点出了故障不可达的情况,从节点可以作为后备“顶”上来,并且保证数据尽量不丢失(主从复制表现为最终一致性)
  • 第二,从节点可以分担主节点上的读压力,让主节点只承担写请求的处理,将所有的读请求负载均衡到各个从节点上

但是主从复制模式并不是万能的,它同样遗留下以下几个问题:

  1. 主节点发生故障时,进行主备切换的过程是复杂的,需要完全的 人工参与,导致故障恢复时间无法保障。
  2. 主节点可以将读压力分散出去,但 写压力/存储压力是无法被分担的,还是受到单机的限制。

其中第一个问题是高可用问题,即 Redis 哨兵主要解决的问题。第二个问题是属于存储分布式的问题,留给 Redis 集群去解决,这里我们集中讨论第一个问题。

2. 人工恢复主节点故障

之前我们学到的 人工干预流程如下:

  1. 故障发现:运维人员通过监控系统检测到Redis主节点出现 宕机 情况。image-20250708111530459
  2. 选择新的主节点:运维人员从现有的从节点中挑选一个(例如slave1),并通过执行命令 SLAVEOF NO ONE 将其转换为新的主节点。image-20250708111502384
  3. 更新其他从节点配置:对剩余的从节点(如slave2),运维人员执行命令 SLAVEOF <newMasterIp> <newMasterPort>,让这些从节点开始与新的主节点同步数据。image-20250708111513625
  4. 更新应用连接信息:更新应用程序配置,使其指向新的主节点地址 {newMasterIp}:{newMasterPort} ,确保客户端能够继续正常访问服务。image-20250708111446535
  5. 处理恢复的原主节点:如果原先宕机的主节点恢复正常,运维人员应在其上执行 SLAVEOF <newMasterIp> <newMasterPort> 命令,使其转变为从节点,加入到新的复制拓扑结构中。image-20250708111414756

二、基本概述

1. Redis Sentinel 是什么?

Redis Sentinel 是 Redis 提供的一个分布式监控和故障转移系统,专门用于管理 Redis 主从架构的高可用问题。

它是一个独立运行的进程,不处理客户端请求,只负责:监控主从节点状态、自动故障转移(failover)、提供服务发现(如新主节点地址),实际功能特点如下:

  1. 当主节点出现故障时,Redis Sentinel能自动完成故障发现和故障转移,并通知应用方,从而实现真正的高可用。
  2. 哨兵最主要的核心功能 就是 监控,自动故障转移,通知新的主节点到客户端.
  3. Redis Sentinel是一个分布式架构,其中包含若干个 Sentinel节点和 Redis 数据节点,每个Sentinel节点会对数据节点和其余 Sentinel节点进行监控,当它发现节点不可达时,会对节点做下线表示。
  4. 如果下线的是主节点,它还会和其他的 Sentinel节点进行 “协商”,当大多数 Sentinel节点对主节点不可达这个结论达成共识之后,它们会在内部“选举”出一个领导节点来完成自动故障转移的工作,同时将这个变化实时通知给 Redis 应用方。
  5. 整个过程是 完全自动 的,不需要人工介入。

💡这里的分布式架构是指:Redis 数据节点、Sentinel节点集合、客户端分布在多个物理节点上,不要与后边章节介绍的 Redis Cluster分布式混淆。

整体的架构如图所示

image-20250708111833815

2. 哨兵节点的作用与配置

Redis Sentinel 是独立的 redis-sentinel 进程,系统中通常配置多个哨兵节点来共同监控数据存储节点(包括主节点和从节点)。部署多个哨兵节点的主要目的是为了增强系统的健壮性和可靠性。

那么为什么需要多个 Sentinel 节点?

  1. 防止单点故障:如果只有一个 Sentinel,它挂了整个系统就失效了
  2. 防止误判主节点宕机:单个哨兵节点(Sentinel) 可能因 网络隔离延迟或丢包等问题 而误判主节点故障,而 多个哨兵节点可以相互验证,减少误判的可能性。
  3. 达成共识(Quorum):多个 Sentinel 共同投票决定是否执行故障转移

推荐配置

  • 至少部署 3 个 Sentinel 节点
  • 建议为奇数个(如 3、5),便于达成多数共识
  • 每个 Sentinel 节点应部署在不同机器上,避免物理故障影响整体系统

核心功能

功能 描述
监控(Monitoring) 定期检查主节点、从节点和其他 Sentinel 节点的状态
通知(Notification) 故障发生时通知管理员或客户端
自动故障转移(Automatic Failover) 当主节点不可用时,自动选出一个从节点作为新的主节点
配置提供(Configuration Provider) 客户端可以通过 Sentinel 获取当前主节点地址
节点发现(Node Discovery) Sentinel 会自动发现其他 Sentinel 和从节点

补充:监控与心跳检测

心跳检测机制:哨兵节点通过与数据存储节点建立 TCP长连接,并定期发送 心跳包 以确保数据节点处于运行状态。

  • 如果从节点挂掉,影响较小,因为可以从主节点重新同步数据。
  • 主节点挂掉则需要哨兵节点介入,启动故障恢复流程。

4. 哨兵故障恢复流程详解

当主节点无响应时,多个哨兵节点之间的交互过程如下:

  1. 主节点故障 → 从节点连接中断:此时所有从节点无法继续复制数据、客户端写入失败(读操作仍可继续)
  2. 哨兵节点发现主节点异常:Sentinel 定期向主节点发送 PING 命令,如果超过一定时间未响应(默认 30 秒),标记为 SRI_S_DOWN(主观下线)
  3. 达成客观下线(ODOWN)
    • Sentinel 之间相互通信,确认主节点是否真的下线
    • 如果达到预设的“法定人数”(quorum),则将主节点标记为 SRI_O_DOWN(客观下线)
    • 示例sentinel monitor mymaster 127.0.0.1 6379 2 表示至少有 2 个 Sentinel 认为主节点下线,才认为是真正的故障
  4. 选举Leader:通过 **选举算法(如Raft)**选出一个 Leader哨兵节点,Leader 将负责后续的故障转移流程
  5. 选择新主节点(Failover):由Leader负责 从现有的从节点中挑选一个作为新的主节点,负责后续的故障转移工作。选择标准(优先级排序)如下:
    1. 从节点是否在线
    2. 复制偏移量(offset)最大 (说明数据最新)
    3. 从节点的优先级(replica-priority)最低
    4. 运行 ID 最小(作为最后兜底条件)
  6. 执行故障转移:哨兵领导者开始执行故障转移
    • Leader 控制被选中的从节点执行 SLAVEOF NO ONE 命令,使其成为新的主节点。
    • 控制其他从节点修改其 SLAVEOF <new_master_ip> <new_master_port> 配置到新的主节点上。
  7. 更新客户端配置:Sentinel 会更新其内部记录的新主节点信息,客户端通过 Sentinel 获取最新的主节点地址,从而继续正常访问

三、Docker 部署 Redis Sentinel

场景介绍

  • 在理想情况下,Redis Sentinel 的六个节点应该部署在六台不同的服务器上。然而,在实际操作中,我们可能没有足够的物理服务器资源。而且在实际工作中,把多个节点放在一个云服务器上,是没有意义的 !!!
  • 如果我们按照传统的主从复制模式来配置,需要修改每台服务器的端口号、配置文件和数据文件,这不仅配置复杂,而且容易引起端口冲突问题。此外,这种方式与多主机部署存在较大差异。

为了解决这些问题,我们可以 引入Docker 这个非常有用的工具。

什么是 Docker?

  • 虚拟化技术对比:传统虚拟机通过软件模拟硬件环境,但其对硬件资源消耗较大,这对于资源有限的服务器来说是一个挑战。
  • Docker 特点:Docker可以视为 “轻量级” 的 虚拟机,它提供了类似虚拟机的环境隔离效果,但不会大量占用硬件资源。它使得应用程序可以在几乎任何地方以相同的方式运行

Docker 核心概念

  • 镜像 (Image):类似于模板或蓝图,包含了应用程序及其所有依赖文件、环境配置等。它是 只读 的,并且是创建容器的基础。
  • 容器 (Container):基于镜像创建的运行实例,每个容器都是一个独立且隔离的进程空间。镜像与容器 的关系类似于操作系统中的“可执行程序”与“进程”。

以下是操作步骤

① 安装 Docker 和 Docker Compose:Docker 的安装和配置(包括镜像源)相对复杂,建议参考官方文档或相关文章进行详细操作。例如,可以参阅 Docker官方文档 或者其他社区提供的教程。(注意:最新的 docker 已经集成了 docker-compose 功能,所以只用安装 docker 即可)

② 停止之前的redis主节点和从节点的服务

lighthouse@VM-8-10-ubuntu:~$ ps -aux | grep redis
lightho+ 2523474  0.0  0.0   6480  2240 pts/3    S+   20:45   0:00 grep --color=auto redis

③ 配置 Redis 和 Sentinel

在 Redis 下创建两个目录,来存取 数据节点 和 哨兵节点,如下:

root@VM-8-10-ubuntu:~/redis# pwd
/root/redis
root@VM-8-10-ubuntu:~/redis# mkdir redis-data		# 数据节点
root@VM-8-10-ubuntu:~/redis# mkdir redis-sentinel	# 哨兵节点

为什么要把redis的哨兵和主从节点的配置文件分开创建?

  1. 为了方便观察日志
  2. 为了确保redis主从节点启动之后再启动哨兵节点
    • 如果我们把六个容器都配置在一个yml文件中的话,有可能先启动哨兵,日志的执行可能会产生变数,我们分成两组来启动就可以保证上述顺序的正确.

为了便于管理和确保正确的启动顺序,建议将 Redis 哨兵节点的配置与主从节点分开。

  • 使用 Docker Hub 上现成的 Redis 和 Redis Sentinel 镜像,或者自己构建自定义镜像。

    # 使用docker获取到redis镜像
    docker pull redis:5.0.9
    
    # 查看 docker 镜像
    lighthouse@VM-8-10-ubuntu:~$ docker images
    REPOSITORY    TAG       IMAGE ID       CREATED        SIZE
    hello-world   latest    74cc54e27dc4   5 months ago   10.1kB
    redis         5.0.9     987b553c835f   4 years ago    98.3MB
    
  • 编写 docker-compose.yml 文件来定义服务(如 Redis 主节点、从节点和哨兵节点),并通过 Docker Compose 启动这些服务。

Docker Compose 编排 Redis 主从及哨兵节点

为了简化 Redis 主从复制和哨兵集群的部署,我们使用 docker-compose.yml 文件来编排容器。该配置文件定义了所有需要创建的容器及其运行参数,允许我们通过一个简单的命令批量启动或停止这些容器。

编排 Redis 主从节点:首先,在 /root/redis/redis-data 目录下创建名为 docker-compose.yml 的文件(注意:文件名必须固定,类似于 Spring 中的 application.yml 和 C++ 的 Makefile 文件)。在文件中添加如下内容:

version: '3.7'
services:
  master:
    image: 'redis:5.0.9'
    container_name: redis-master
    restart: always
    command: redis-server --appendonly yes --requirepass 123456
    ports: 
      - 6379:6379
 
  slave1:
    image: 'redis:5.0.9'
    container_name: redis-slave1
    restart: always
    command: redis-server --appendonly yes --slaveof redis-master 6379 --masterauth 123456
    ports:
      - 6380:6379
 
  slave2:
    image: 'redis:5.0.9'
    container_name: redis-slave2
    restart: always
    command: redis-server --appendonly yes --slaveof redis-master 6379 --masterauth 123456
    ports:
      - 6381:6379

字段解释:

  • version:版本号
  • services 下的名称代表每个服务的名字,可以根据需求自定义。
    • images:基于哪个镜像
    • ports 字段用于端口映射,如 6380:6379 表示 宿主机的 6380 端口映射到容器内的 6379 端口。
    • command 启动 Redis 的命令行参数,从节点的 --slaveof 参数可以直接使用主节点的服务名,Docker 会自动解析为主节点的 IP 地址。
    • 如果实在是向在后面直接写 ip 地址的话,也不一定写得上去,这是以为在容器启动之后,会动态分配ip地址,被分配的ip地址是什么,我们自己也不清楚,当然,我们可以通过某些手段来配置静态的 ip.
  • 至于 --masterauth 是因为我这里之前设置了密码,如果没有设置密码可以把上面的 --requirepass 123456--masterauth 123456 去除

该代码完成了三个数据节点的创建,通过命令完成主从关系的配置。执行之前,记得先把主机上的redis停止,把6379、6380、6381三个端口空出来给docker启动的redis(这里使用之前我是停了的)

④ 启动服务:使用命令 docker-compose up -d 启动所有定义的服务,确保它们在后台以分离模式运行。

在目录 redis-data中执行:docker compose up -d

root@VM-8-10-ubuntu:~/redis/redis-data# docker-compose up -d
Creating network "redis-data_default" with the default driver
Creating redis-slave2 ... done
Creating redis-master ... done
Creating redis-slave1 ... done

此时查看 docker 状态如下:

image-20250711212630951

这样就创建好了三个redis服务端,可以通过redis-cli -p 6379redis-cli -p 6380redis-cli -p 6381来验证是否启动成功。

编排 Redis 哨兵节点

/root/redis-sentinel/ 目录下创建另一个 docker-compose.yml 文件:

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
    networks:
      - redis-data_default
 
  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
    networks:
      - redis-data_default
 
  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:
      - redis-data_default
 
networks:
  default:
    external:
      name: redis-data_default

字段解释

  • volumes 用于挂载哨兵配置文件到容器内路径。
  • networks如果没有这个字段,我们在启动redis哨兵的时候,哨兵和数据节点就处于两个局域网中.默认情况下,两个局域网是不互通的.这里我们加入了这个字段,来把redis的数据节点和哨兵节点放入同一个局域网中.
  • 其中我们先需要使用 docker network ls 查询到redis数据节点的局域网,之后我们把哨兵节点的局域网和数据节点修改成一样的即可.上面我们都修改成了 redis-data_default,该节点就是redis数据节点的局域网.

创建哨兵配置文件

在同一目录 (/root/redis-sentinel/) 下创建三个哨兵配置文件 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
sentinel auth-pass redis-master 123456

字段解释

  • bind 0.0.0.0:允许所有网络接口上的连接。
  • port 26379:指定哨兵节点监听的端口号。
  • sentinel monitor redis-master redis-master 6379 2:此行定义了哨兵监控的目标主节点。
    • 第一个 redis-master 是哨兵内部使用的名称;
    • 第二个 redis-master 是主节点的服务名(Docker会自动解析为主节点的IP地址);
    • 第三个 6379 是主节点的端口号;
    • 第四个 2 表示法定票数,即至少需要两个哨兵确认故障才能进行切换。
  • sentinel down-after-milliseconds redis-master 1000:设置哨兵认为主节点不可达的时间阈值为1000毫秒。
root@VM-8-10-ubuntu:~/redis/redis-sentinel# vim sentinel1.conf
root@VM-8-10-ubuntu:~/redis/redis-sentinel# cp sentinel1.conf sentinel2.conf
root@VM-8-10-ubuntu:~/redis/redis-sentinel# cp sentinel1.conf sentinel3.conf
root@VM-8-10-ubuntu:~/redis/redis-sentinel# ll
total 24
drwxr-xr-x 2 root root 4096 Jul 11 21:39 ./
drwxr-xr-x 4 root root 4096 Jul 11 21:34 ../
-rw-r--r-- 1 root root  946 Jul 11 21:35 docker-compose.yml
-rw-r--r-- 1 root root  164 Jul 11 21:39 sentinel1.conf
-rw-r--r-- 1 root root  164 Jul 11 21:39 sentinel2.conf
-rw-r--r-- 1 root root  164 Jul 11 21:39 sentinel3.conf

⑤ 验证部署:检查各个容器是否正常启动,并验证 Redis 主从复制和哨兵监控功能是否按预期工作。

启动服务

# 启动Redis主从节点
cd /root/redis/redis-data/
docker-compose up -d
 
# 启动哨兵节点
cd /root/redis/redis-sentinel/
docker-compose up -d
  • 如果需要停止并删除容器,可以使用 docker-compose down 命令。确保在 docker-compose.yml 文件所在的同级目录中执行这些命令。

启动后,哨兵节点会自动修改配置文件,将其监控的主节点名称解析为实际的 IP 地址,并记录其他哨兵节点的信息。

哨兵节点配置文件的自动修改

启动哨兵节点后,配置文件会被 Docker 自动修改以反映实际运行时的状态。例如,原本的 redis-master 名称被解析为具体的 IP 地址,并添加了其他哨兵节点的信息。修改后的配置文件示例:

root@VM-8-10-ubuntu:~/redis/redis-sentinel# cat sentinel1.conf
bind 0.0.0.0
port 26379
sentinel myid 710a77f8c58fc68ca655b758160fb3c9e9efa907
sentinel deny-scripts-reconfig yes
sentinel monitor redis-master 172.18.0.2 6379 2
# Generated by CONFIG REWRITE
dir "/data"
sentinel down-after-milliseconds redis-master 1000
sentinel auth-pass redis-master 123456
sentinel config-epoch redis-master 0
sentinel leader-epoch redis-master 0
sentinel known-replica redis-master 172.18.0.3 6379
sentinel known-replica redis-master 172.18.0.4 6379
sentinel known-sentinel redis-master 172.18.0.7 26379 4d4c401f02248ec812b75e7965d0ef69a8857836
sentinel known-sentinel redis-master 172.18.0.5 26379 b5ec54e61d0afc4856a5f90b1ee14f078c1cfb16
sentinel current-epoch 0

可以看到,配置文件中的 redis-master 已经被自动解析成了 IP 地址,并且记录了已知的副本和哨兵节点信息。


问题与解决

问题:确保所有服务引用的网络已正确定义

root@VM-8-10-ubuntu:~/redis/redis-sentinel# docker-compose up -d
ERROR: Service "sentinel1" uses an undefined network "redis-data_default"
  • 确保在 docker-compose.yml 中正确地定义了所有服务使用的网络,并且这些网络确实存在于你的环境中。

原因:在 docker-compose.yml 文件中指定了容器要使用名为 redis-data_default 的自定义网络:networks: redis-data_default,在当前 docker-compose.yml 文件的 networks 配置段中,你没有定义这个网络,而是试图引用一个 外部网络

解决办法如下

1. 查看当前系统中的 Docker 网络(判断 redis-data_default 存在)

root@VM-8-10-ubuntu:~/redis/redis-sentinel# docker network ls
NETWORK ID     NAME                 DRIVER    SCOPE
0d4aafc751e0   bridge               bridge    local
87c6f08d6a64   host                 host      local
9c17335e3703   none                 null      local
e85c16584ecb   redis-data_default   bridge    local

2. 创建缺失的网络(不存在)

docker network create redis-data_default

3. 如果存在,修改如下:

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
    networks:
      - redis-data-network
 
  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
    networks:
      - redis-data-network
 
  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:
      - redis-data-network
 
networks:
  redis-data-network:
    external: true
    name: redis-data_default

完成以上步骤后,再次尝试启动服务:docker compose up -d

注意事项:如果你之前有运行过的容器或网络,可能需要先清理它们,以避免冲突。

  • 确保你在正确的目录中执行命令,即包含 docker-compose.yml 文件的目录。
  • 如果仍然遇到问题,请检查 Docker 和 Docker Compose 的日志输出,或者提供更详细的错误信息以便进一步诊断。

四、选举机制— 解决监控主机宕机问题(常考)

哨兵存在的意义在于能够在 Redis 主从结构出现问题时(如主节点挂掉),自动选举一个新的主节点来代替故障的主节点,从而保证整个 Redis 系统仍然可用。

主节点的选举过程可以分为几个关键步骤:

  1. 判断主观下线

    • 哨兵节点通过给 Redis 服务器发送心跳包来判定服务器是否正常工作。

    • 如果心跳包没有得到响应,当前哨兵节点会认为该服务器已挂掉。但此时只是单个哨兵节点的主观判断。

  2. 判断客观下线:当 多个 哨兵节点通过投票确认服务器确实挂掉,并且票数 超过了在配置文件中设定的法定票数时,所有哨兵节点达成一致意见,认为服务器确实已宕机。

  3. 选取哨兵Leader:多个哨兵节点需要通过 Raft 算法选举出一个 Leader 节点,负责从现有从节点中提拔新的主节点。

    • 简而言之,Raft 算法的核心就是"先下手为强" 谁率先发出了拉票请求,谁就有更大的概率成为 leader,这里的决定因素成了 “网络延时”。
  4. Leader 提拔新主节点(提拔原则如下:)

    • 优先级:每个 Redis 数据节点在配置文件中都有一个 slave-priority 设置,优先级越高越可能被选中。
    • 数据复制偏移量 (offset):偏移量越大表示该从节点与原主节点的数据同步程度越高,更接近最新的数据状态,因此 优先考虑 offset 较大的节点。
    • runid:如果上述条件相同,则随机挑选一个节点。runid 是每个 Redis 节点启动时自动生成的一串随机数字。
  5. 设置新主节点:Leader 控制选定的节点执行 SLAVEOF NO ONE 命令,使其成为新的主节点。接着 Leader 再控制其他从节点执行 SLAVEOF <newMasterIp> <newMasterPort> 命令,让它们跟随新的主节点进行数据同步。

关于 Raft 算法

  1. 每个哨兵节点都给其他所有哨兵节点发起一个拉票请求"
  2. 收到拉票请求的节点,会回复一个投票响应,当哨兵节点收到多个拉票请求,只对第一个节点投票,后续节点都不投票
  3. 一轮投票完成之后,发现得票超过半数的节点,自动成为 leader 如果出现平票的情况,就重新再投一次即可。

因此建议哨兵节点设置成 奇数 ,如果是偶数个,则增大了平票的概率,带来不必要的开销。最终leader 节点负责挑选一个 slave 成为新的 master 当其他的 sentenal发现新的 master 出现了,就说明选举结束了。

实验 – 哨兵恢复

步骤一:现在通过docker关掉master的容器,来模拟主节点崩溃

root@VM-8-10-ubuntu:~/redis/redis-sentinel# docker stop redis-master
redis-master
root@VM-8-10-ubuntu:~/redis/redis-sentinel# docker compose logs
...
redis-sentinel-1  | 1:X 11 Jul 2025 14:08:29.231 # +sdown master redis-master 172.18.0.2 6379
redis-sentinel-1  | 1:X 11 Jul 2025 14:08:29.317 # +new-epoch 1
redis-sentinel-1  | 1:X 11 Jul 2025 14:08:29.320 # +vote-for-leader 4d4c401f02248ec812b75e7965d0ef69a8857836 1
redis-sentinel-1  | 1:X 11 Jul 2025 14:08:30.375 # +odown master redis-master 172.18.0.2 6379 #quorum 3/2
redis-sentinel-1  | 1:X 11 Jul 2025 14:08:30.375 # Next failover delay: I will not start a failover before Fri Jul 11 14:14
...

在日志中,vote-for-leader就是在投票选举leader哨兵

img

这是第二个哨兵的日志

  1. sdown master:这代表哨兵节点发现了master节点掉线,sdown表示主观认为,也就是说哨兵还不能保证master一定掉线
  2. odown master:经过与其它哨兵交流,多个哨兵都认为master节点掉线,odown表示客观认为,#quorum 3/2表示法定票数为2票,目前有三个哨兵都投票认为master掉线
  3. switch-master:切换主节点,此时已经有新的节点变成主节点了

进入6380端口的数据节点,输入info replication

root@VM-8-10-ubuntu:~/redis/redis-sentinel# redis-cli -p 6381 info replication
# Replication
role:master
connected_slaves:0
master_replid:2d4e3507ec4960a73dce8ccd6cb392380fbd8fc2
master_replid2:5ccd5a199bca383e47929a58000736f42d58e6cc

  • 可以看到role:master6381成为了新的主节点,当然也有可能是6380

尝试重启redis-master

root@VM-8-10-ubuntu:~/redis/redis-sentinel# redis-cli -p 6379 -a 123456 info replication 
role:slave
master_host:172.18.0.4
master_port:6379
master_link_status:up
master_last_io_seconds_ago:0
master_sync_in_progress:0
  • 这个redis-master重启后,就变成了从节点,不再是主节点了

五、小结

哨兵故障恢复流程

  1. 主观下线 sdown:单个哨兵节点认为主节点掉线
  2. 客观下线 odown:投票后客观认为主节点掉线
  3. 选取哨兵leader:依据网络情况,选出一个哨兵成为leader,由leader完成选举master
  4. 选举master:由leader依据优先级,数据同步进度,run id来选出一个节点成为master
  5. 重构主从关系:由leader哨兵,指定数据节点执行指令,重构主从关系

注意事项

  1. 哨兵节点数量:建议哨兵节点为奇数个,以避免在投票选举 Leader 时出现平票情况。
  2. 哨兵职责:哨兵不负责存储数据,仅用于监控和故障恢复。
  3. 数据丢失风险:哨兵模式不能完全防止极端情况下写数据丢失的问题,例如,在数据未完全同步到从节点前主节点就宕机了,这种情况下丢失的数据将无法恢复。
  4. 存储容量:哨兵模式不会提高数据的存储容量,它主要关注的是高可用性和故障转移。
  5. 哨兵节点 可以使用一些 配置不高的机器来部署

Redis 的主从复制模式可以将主节点的数据改变同步给从节点,这样从节点就可以起到两个作用:

  1. 作为主节点的一个备份,一旦主节点出了故障不可达的情况,从节点可以作为后备,并且保证数据尽量不丢失(主从复制表现为最终一致性)。
  2. 从节点可以分担主节点上的读压力,让主节点只承担写请求的处理,将所有的读请求负载均衡到各个从节点上。

但是主从复制模式并不是万能的,它同样遗留下以下几个问题:

  1. 主节点发生故障时,进行主备切换的过程是复杂的,需要完全的人工参与,导致故障恢复时间无法保障
  2. 主节点可以将读压力分散出去,但 写压力/存储压力是无法被分担的,还是受到单机的限制。

其中第一个问题是高可用问题,即 Redis 哨兵主要解决的问题。第二个问题是属于存储分布式的问题,留给 Redis 集群去解决,本篇博客集中讨论了第一个问题,下一篇将对第二个问题进行讨论

★,°:.☆( ̄▽ ̄)/$:.°★ 】那么本篇到此就结束啦,如果有不懂 和 发现问题的小伙伴可以在评论区说出来哦,同时我还会继续更新关于【Redis】的内容,请持续关注我 !!

在这里插入图片描述

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐