Redis 哨兵机制

Redis 哨兵机制

九月 19, 2025 次阅读

Redis 主从复制的结构当中,一旦主节点出现故障,整个集群就会不可用。为了提高 Redis 集群的高可用性,Redis 提供了哨兵(Sentinel)机制。哨兵是一个独立的进程,负责监控 Redis 主从节点的状态,并在主节点出现故障时自动进行故障转移(failover),将一个从节点提升为新的主节点,从而保证集群的持续可用性。

先说一说如果没有哨兵机制,程序员 24 小时蹲在服务器前面,若能及时发现主节点宕机,则需要立即从众多的从节点当中选择一个提升为主节点,并且还要修改应用程序的配置文件,将新的主节点地址更新进去,这样才能保证应用程序继续正常工作。显然,这种方式既不高效,也不可靠。

而有了哨兵机制,哨兵进程会定期向主节点和从节点发送心跳检测请求,以监控它们的状态。当哨兵发现主节点无法响应时,会将其标记为下线状态,并开始选举一个新的主节点。选举过程通常基于从节点的优先级、复制偏移量等因素,确保选择一个最合适的从节点提升为主节点。

哨兵的工作原理

哨兵通常由多个奇数节点来部署,以避免选举过程中出现平票的情况。每个哨兵节点都会监控主节点和从节点的状态,并与其他哨兵节点进行通信。当一个哨兵节点发现主节点不可用时,若只是它一个节点发现,则不会立即进行故障转移,而是会等待其他哨兵节点的确认,这时只是主观判断。当超过半数的哨兵节点都确认主节点不可用时,就说明客观存在故障,才会启动故障转移过程。

此时,这些哨兵节点并不会马上开始选举从节点,这个任务应该给一个 leader 节点来完成,而这个 leader 节点是通过哨兵节点之间的投票选举出来的。通常网络延迟低的节点会最先出来内推自己成为 leader 节点,其他节点会投票给它。选举完成后,leader 节点会从所有的从节点中选择一个最合适的节点来提升为新的主节点。

如何选择一个最合适的从节点呢?通常会考虑以下几个因素:

  1. 优先级:每个从节点可以设置一个优先级,优先级高的节点更有可能被选为新的主节点。
  2. 复制偏移量:选择复制偏移量最大的从节点,这样可以确保数据的完整性,减少数据丢失的风险。
  3. 延迟:选择与主节点延迟较低的从节点,以确保新的主节点能够快速响应客户端请求。

sentinel

下面我们将通过实例来演示如何配置和使用 Redis 哨兵机制,从中验证我们的理解。

Redis Sentinel 高可用集群部署与实践

实验环境架构

本实验采用三台服务器构建 Redis Sentinel 高可用集群:

  • 主节点服务器:82.156.255.140 - 运行 Redis 主节点和 Sentinel1
  • 从节点服务器 1:139.59.228.224 - 运行 Redis 从节点和 Sentinel2
  • 从节点服务器 2:152.42.240.210 - 运行 Redis 从节点和 Sentinel3

目录结构设计

主节点服务器目录结构

.
├── config
│   ├── redis-master
│   │   └── redis.conf
│   └── redis-sentinel
│       └── sentinel.conf
├── data
│   └── master
│       ├── appendonlydir
│       │   ├── appendonly.aof.2.base.rdb
│       │   ├── appendonly.aof.2.incr.aof
│       │   └── appendonly.aof.manifest
│       └── dump.rdb
├── docker-compose.yml
└── sentinel-data

从节点服务器目录结构

.
├── config
│   ├── redis-sentinel
│   │   └── sentinel.conf
│   └── redis-slave
│       └── redis.conf
├── data
│   └── master
│       ├── appendonlydir
│       │   ├── appendonly.aof.4.base.rdb
│       │   ├── appendonly.aof.4.incr.aof
│       │   └── appendonly.aof.manifest
│       └── dump.rdb
├── docker-compose.yml
└── sentinel-data

关键配置文件详解

主节点 Docker Compose 配置

services:
  redis-master:
    image: redis:8.0.3
    container_name: redis-master
    ports:
      - "6390:6390" # 关键:容器内外端口一致,避免网络问题
    volumes:
      - ./data/master:/data:z
      - ./config/redis-master:/usr/local/etc/redis:z
    command: ["redis-server", "/usr/local/etc/redis/redis.conf"]

  sentinel:
    image: redis:8.0.3
    container_name: sentinel1
    ports:
      - "26379:26379" # 关键:Sentinel端口内外一致
    volumes:
      - ./config/redis-sentinel:/usr/local/etc/redis:z
      - ./sentinel-data:/data:z
    command:
      ["redis-server", "/usr/local/etc/redis/sentinel.conf", "--sentinel"]
    depends_on:
      - redis-master

主节点 Redis 配置

bind 0.0.0.0          # 允许所有网络接口连接
port 6390             # Redis服务端口
dir /data             # 数据存储目录
appendonly yes        # 启用AOF持久化

主节点 Sentinel 配置

bind 0.0.0.0
port 26379
dir "/data"
sentinel announce-ip "82.156.255.140"        # 当前Sentinel的对外IP
sentinel announce-port 26379                 # 当前Sentinel的对外端口
sentinel monitor mymaster 82.156.255.140 6390 2  # 监控主节点,quorum=2
sentinel down-after-milliseconds mymaster 20000  # 20秒无响应判定为下线
sentinel failover-timeout mymaster 10000     # 故障转移超时时间

从节点 Redis 配置

bind 0.0.0.0
port 6390
dir /data
appendonly yes
replicaof 82.156.255.140 6390  # 关键:指定主节点地址和端口

从节点 Sentinel 配置(以从节点 1 为例)

bind 0.0.0.0
port 26379
dir "/data"
sentinel announce-ip "139.59.228.224"        # 当前节点的对外IP
sentinel announce-port 26379                 # 当前节点的对外端口
sentinel monitor mymaster 82.156.255.140 6390 2  # 监控同一个主节点
sentinel down-after-milliseconds mymaster 20000
sentinel failover-timeout mymaster 10000

重要配置注意事项

1. 端口映射一致性

强烈建议将宿主机端口和容器端口设置为相同的映射,否则 Sentinel 节点之间无法正确通信。这是因为 Sentinel 通过配置文件中指定的端口来发现和通信其他 Sentinel 节点。

2. 网络配置要点

  • 所有节点必须在同一网络环境中能够相互通信
  • Sentinel 节点需要能够访问所有 Redis 实例
  • 防火墙需要开放相应的 Redis 和 Sentinel 端口

3. Quorum 配置

sentinel monitor mymaster <ip> <port> <quorum> 中的 quorum 值:

  • 表示判定主节点故障所需的最小 Sentinel 投票数
  • 本实验设置为 2,表示需要至少 2 个 Sentinel 同意才能进行故障转移

Redis Sentinel 集群拓扑图:

graph TB
    %% 客户端层
    Client1[客户端应用]
    Client2[客户端应用]
    Client3[客户端应用]

    %% Sentinel层
    subgraph "Sentinel 哨兵集群"
        S1[Sentinel1
82.156.255.140:26379] S2[Sentinel2
139.59.228.224:26379] S3[Sentinel3
152.42.240.210:26379] end %% Redis实例层 subgraph "Redis 数据层" Master[主节点
82.156.255.140:6390
角色: master] Slave1[从节点1
139.59.228.224:6390
角色: slave] Slave2[从节点2
152.42.240.210:6390
角色: slave] end %% 监控关系 S1 -.-> Master S2 -.-> Master S3 -.-> Master %% 复制关系 Slave1 -->|replicaof| Master Slave2 -->|replicaof| Master %% 客户端连接 Client1 --> S1 Client2 --> S2 Client3 --> S3 %% Sentinel相互发现 S1 -- 相互发现
自动配置 --> S2 S2 -- 相互发现
自动配置 --> S3 S3 -- 相互发现
自动配置 --> S1 %% 样式定义 classDef master fill:#ff9999,stroke:#333,stroke-width:2px classDef slave fill:#99ccff,stroke:#333,stroke-width:1px classDef sentinel fill:#ccffcc,stroke:#333,stroke-width:1px classDef client fill:#ffcc99,stroke:#333,stroke-width:1px class Master master class Slave1,Slave2 slave class S1,S2,S3 sentinel class Client1,Client2,Client3 client

故障转移测试实验

初始状态监控

主节点 Sentinel 启动日志显示正常监控状态:

# +monitor master mymaster 82.156.255.140 6390 quorum 2

模拟主节点故障

通过停止主节点容器来模拟故障,观察 Sentinel 的自动故障转移过程。

故障转移过程日志分析

从节点 1(Sentinel2)日志:

1:X 20 Sep 2025 04:08:22.719 * 投票过程
1:X 20 Sep 2025 04:08:23.057 * +slave-reconf-inprog 从节点重新配置中
1:X 20 Sep 2025 04:08:23.057 * +slave-reconf-done 从节点重新配置完成
1:X 20 Sep 2025 04:08:23.157 # +failover-end 故障转移完成
1:X 20 Sep 2025 04:08:23.157 # +switch-master 主节点切换
1:X 20 Sep 2025 04:08:23.157 * +slave 添加从节点信息

从节点 2(Sentinel3)日志:

1:X 20 Sep 2025 04:08:22.259 # +config-update-from 配置更新
1:X 20 Sep 2025 04:08:22.259 # +switch-master 主节点切换
1:X 20 Sep 2025 04:08:22.259 * +slave 从节点同步开始

故障转移结果验证

Sentinel 配置自动重写:
检查主节点的 Sentinel 配置文件,发现自动更新为新的主节点信息:

sentinel monitor mymaster 152.42.240.210 6390 2  # 主节点已切换

原主节点状态验证:
通过 Redis CLI 查看原主节点状态,确认已变为从节点:

role:slave
master_host:152.42.240.210  # 新的主节点
master_port:6390
master_link_status:down

Redis Sentinel 故障转移工作流程图:

flowchart TD
    Start[主节点故障转移流程] --> DetectFailure

    subgraph A [阶段一: 故障检测]
        DetectFailure[检测主节点故障] --> SD1[Sentinel1 检测到主节点无响应]
        SD1 --> SD2[Sentinel2 确认主节点故障]
        SD2 --> SD3[Sentinel3 确认主节点故障]
        SD3 --> QuorumCheck[Quorum检查 ≥2/3]
    end

    QuorumCheck -->|通过| LeaderElection
    QuorumCheck -->|不通过| Wait[等待更多确认]

    subgraph B [阶段二: 领导者选举]
        LeaderElection[Sentinel领导者选举] --> Vote1[Sentinel1 投票]
        Vote1 --> Vote2[Sentinel2 投票]
        Vote2 --> Vote3[Sentinel3 投票]
        Vote3 --> ElectLeader[选举出Leader Sentinel]
    end

    ElectLeader --> FailoverInit

    subgraph C [阶段三: 故障转移执行]
        FailoverInit[初始化故障转移] --> SelectSlave[选择最佳从节点]
        SelectSlave --> Promote[提升从节点为新主节点]
        Promote --> ReconfigSlaves[重新配置其他从节点]
        ReconfigSlaves --> UpdateSentinels[更新所有Sentinel配置]
    end

    UpdateSentinels --> NotifyClients

    subgraph D [阶段四: 客户端通知]
        NotifyClients[通知客户端主节点变更] --> ClientRediscover[客户端重新发现主节点]
        ClientRediscover --> NewConnections[建立新连接]
    end

    NewConnections --> End[故障转移完成]

    %% 样式定义
    classDef phase1 fill:#ffe6e6,stroke:#ff9999
    classDef phase2 fill:#e6f3ff,stroke:#99ccff
    classDef phase3 fill:#e6ffe6,stroke:#99ff99
    classDef phase4 fill:#fff0e6,stroke:#ffcc99

    class A phase1
    class B phase2
    class C phase3
    class D phase4

实验结论与经验总结

1. Sentinel 自动管理能力

Redis Sentinel 成功实现了自动故障检测和转移:

  • 自动检测主节点故障
  • 自动选举新的主节点(152.42.240.210)
  • 自动更新所有 Sentinel 节点的配置
  • 自动将其他节点重新配置为从节点

2. 配置持久化机制

Sentinel 会自动重写配置文件(CONFIG REWRITE),保存当前的集群状态:

  • 记录已知的 Sentinel 节点信息
  • 记录已知的从节点信息
  • 保存当前的 epoch 配置信息

3. 人工干预注意事项

重要:当下次启动时,系统会保持新的主节点配置(152.42.240.210)。如果希望原来的服务器(82.156.255.140)重新成为主节点,需要人工手动进行配置调整。

4. 生产环境建议

  • 适当调整down-after-millisecondsfailover-timeout参数
  • 确保网络稳定性,避免误判
  • 定期监控 Sentinel 集群状态
  • 建立完善的告警机制