第八章:哨兵模式

深入了解 Redis Sentinel 哨兵系统,实现 Redis 高可用。

最后更新: 2024-01-15
页面目录

Redis Sentinel 哨兵模式

Sentinel(哨兵)是 Redis 的高可用解决方案,用于监控主从架构、自动故障转移和通知。

Sentinel 概述

┌─────────────────────────────────────────────────────────────────┐
│                    Redis Sentinel 架构                          │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│   ┌─────────────────────────────────────────────────────────┐    │
│   │                   Sentinel 集群                         │    │
│   │                                                         │    │
│   │    (Sentinel 1)        (Sentinel 2)        (Sentinel 3) │    │
│   │       :26379              :26379             :26380   │    │
│   │                                                         │    │
│   └─────────────────────────────────────────────────────────┘    │
│                              │                                   │
│                              │ 监控                              │
│   ┌──────────────────────────┼────────────────────────────┐     │
│   │                          │                            │     │
│   │                     ┌────┴────┐                       │     │
│   │                     │  Master │                       │     │
│   │                     │  6379   │                       │     │
│   │                     └────┬────┘                       │     │
│   │                          │                            │     │
│   │          ┌───────────────┼───────────────┐             │     │
│   │          │               │               │             │     │
│   │    ┌─────┴─────┐   ┌─────┴─────┐   ┌─────┴─────┐       │     │
│   │    │ Replica1 │   │ Replica2 │   │ Replica3 │       │     │
│   │    │   6380   │   │   6381   │   │   6382   │       │     │
│   │    └──────────┘   └──────────┘   └──────────┘       │     │
│   │                                                         │     │
│   └─────────────────────────────────────────────────────────┘    │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

Sentinel 功能

功能 说明
监控 持续监控主从节点健康状态
通知 故障时发送告警通知
自动故障转移 主节点故障时自动提升从节点
配置提供者 客户端连接哨兵获取主节点地址

Sentinel 选举机制

选举流程

1. Sentinel 定时检测主节点
2. 发现主节点不可达(主观下线)
3. 多个 Sentinel 确认(客观下线)
4. Sentinel 竞争成为 leader
5. Leader 执行故障转移
6. 选举新主节点
7. 更新配置,通知客户端

Leader 选举算法

# 使用 Raft 算法选举 leader
# 1. 获得其他 Sentinel 确认
# 2. 优先级排序
# 3. 票数过半成为 leader
# 4. 执行故障转移

配置 Sentinel

主节点配置

# /etc/redis/redis.conf
bind 0.0.0.0
port 6379
requirepass master_password
daemonize yes

Sentinel 配置

# /etc/redis/sentinel.conf

# Sentinel 端口
port 26379

# 守护进程
daemonize yes
pidfile /var/run/redis-sentinel.pid

# 日志
logfile /var/log/redis-sentinel.log

# 工作目录
dir /tmp

# 监控的主节点配置
# sentinel monitor <master-name> <ip> <port> <quorum>
sentinel monitor mymaster 127.0.0.1 6379 2

# 主节点密码
sentinel auth-pass mymaster master_password

# 主观下线时间(毫秒)
sentinel down-after-milliseconds mymaster 30000

# 故障转移超时
sentinel failover-timeout mymaster 180000

# 并行同步数量
sentinel parallel-syncs mymaster 1

# 客户端配置更新
sentinel notification-script mymaster /etc/redis/notify.sh
sentinel client-reconfig-script mymaster /etc/redis/reconfig.sh

最小配置

# 最简 Sentinel 配置
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel auth-pass mymaster password

启动 Sentinel

启动命令

# 直接启动
redis-sentinel /etc/redis/sentinel.conf

# 或使用 redis-server
redis-server /etc/redis/sentinel.conf --sentinel

Docker 启动

# docker-compose.yml
version: '3.8'
services:
  sentinel1:
    image: redis:7-alpine
    container_name: redis-sentinel1
    ports:
      - "26379:26379"
    command: |
      redis-sentinel /usr/local/etc/redis/sentinel.conf
    volumes:
      - ./sentinel1.conf:/usr/local/etc/redis/sentinel.conf

  sentinel2:
    image: redis:7-alpine
    container_name: redis-sentinel2
    ports:
      - "26380:26379"
    command: |
      redis-sentinel /usr/local/etc/redis/sentinel.conf
    volumes:
      - ./sentinel2.conf:/usr/local/etc/redis/sentinel.conf

  sentinel3:
    image: redis:7-alpine
    container_name: redis-sentinel3
    ports:
      - "26381:26379"
    command: |
      redis-sentinel /usr/local/etc/redis/sentinel.conf
    volumes:
      - ./sentinel3.conf:/usr/local/etc/redis/sentinel.conf

Sentinel 命令

监控命令

# 查看 Sentinel 信息
redis-cli -p 26379 INFO

# 查看主节点
redis-cli -p 26379 SENTINEL master mymaster

# 查看所有从节点
redis-cli -p 26379 SENTINEL slaves mymaster

# 查看 Sentinel 列表
redis-cli -p 26379 SENTINEL sentinels mymaster

# 获取主节点地址
redis-cli -p 26379 SENTINEL get-master-addr-by-name mymaster

管理命令

# 手动故障转移
redis-cli -p 26379 SENTINEL failover mymaster

# 强制重新加载配置
redis-cli -p 26379 SENTINEL flushconfig

# 检查主节点状态
redis-cli -p 26379 SENTINEL is-master-down-by-addr 127.0.0.1 6379

客户端连接

Python 连接

from redis.sentinel import Sentinel

# 创建 Sentinel 连接
sentinel = Sentinel([
    ('localhost', 26379),
    ('localhost', 26380),
    ('localhost', 26381),
], socket_timeout=0.1)

# 获取主节点
master = sentinel.master_for('mymaster')

# 获取从节点
slave = sentinel.slave_for('mymaster')

# 使用主节点写
master.set('key', 'value')

# 使用从节点读
value = slave.get('key')

Java 连接

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisSentinelPool;
import redis.clients.jedis.exceptions.JedisException;

public class SentinelDemo {
    public static void main(String[] args) {
        Set<String> sentinels = new HashSet<>();
        sentinels.add("localhost:26379");
        sentinels.add("localhost:26380");
        sentinels.add("localhost:26381");

        JedisSentinelPool pool = new JedisSentinelPool(
            "mymaster",
            sentinels,
            new JedisPoolConfig(),
            2000,
            "password"
        );

        // 获取连接
        Jedis master = pool.getResource();
        master.set("key", "value");
        master.close();

        // 归还连接
        pool.close();
    }
}

故障转移流程

详细步骤

┌─────────────────────────────────────────────────────────────────┐
│                     故障转移流程                                  │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  1. 主观下线                                                      │
│     ┌─────────┐                                                │
│     │Sentinel │──► ping master (超时)                          │
│     └─────────┘──► 主观下线 S_DOWN                              │
│                                                                  │
│  2. 客观下线                                                      │
│     ┌─────────┐                                                 │
│     │Sentinel1│──► 通知其他 Sentinel                           │
│     └─────────┘                                                 │
│         │                                                        │
│     超过 quorum 个确认 → 客观下线 O_DOWN                         │
│                                                                  │
│  3. 选举 Leader                                                   │
│     ┌─────────┐                                                 │
│     │Sentinel1│──► 发送 SENTINEL is-master-down                │
│     │Sentinel2│──► 投票                                        │
│     │Sentinel3│──► 票数过半成为 Leader                         │
│     └─────────┘                                                 │
│                                                                  │
│  4. 故障转移                                                      │
│     ┌─────────┐                                                 │
│     │ Leader  │──► 选择最优先的从节点                           │
│     │         │──► SLAVEOF NO ONE                             │
│     │         │──► 更新其他从节点指向新主                      │
│     │         │──► 更新 Sentinel 配置文件                     │
│     └─────────┘                                                 │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

从节点选择标准

优先级 标准
1 优先级(replica-priority)
2 复制偏移量(offset)
3 Run ID(字典序最小)
# 从节点优先级配置(redis.conf)
replica-priority 100

通知脚本

故障通知

#!/bin/bash
# /etc/redis/notify.sh

case $1 in
    # 主节点或从节点下线
    +sdown)
        echo "节点下线: $2"
        ;;
    # 重新上线
    -sdown)
        echo "节点重新上线: $2"
        ;;
    # 客观下线
    +odown)
        echo "客观下线: $2"
        ;;
    # 故障转移开始
    +switch-master)
        echo "故障转移: $3 -> $4"
        ;;
    # 故障转移完成
    +slave-reconf-sent)
        echo "从节点重新配置: $2"
        ;;
esac

# 发送告警(邮件、钉钉等)
# curl -X POST "https://oapi.dingtalk.com/robot/send?access_token=xxx" \
#   -H "Content-Type: application/json" \
#   -d '{"msgtype":"text","text":{"content":"Redis 故障告警"}}'

权限配置

sentinel notification-script mymaster /etc/redis/notify.sh
chmod +x /etc/redis/notify.sh

常见问题

1. Sentinel 无法发现节点

# 检查网络连通性
redis-cli -h master ping

# 检查端口
nc -zv master 6379

# 检查配置
redis-cli -p 26379 SENTINEL master mymaster

2. 故障转移失败

# 检查从节点状态
redis-cli INFO replication

# 检查 Sentinel 日志
tail -f /var/log/redis-sentinel.log

# 手动故障转移
redis-cli -p 26379 SENTINEL failover mymaster

3. 客户端未感知故障转移

# 确保使用正确的 Sentinel 配置
from redis.sentinel import Sentinel

sentinel = Sentinel([
    ('host1', 26379),
    ('host2', 26379),
    ('host3', 26379),
], socket_timeout=0.1)

# 每次操作获取最新主节点
master = sentinel.master_for('mymaster')

高可用部署建议

部署拓扑

环境 Sentinel 数量 Quorum 说明
开发/测试 1 1 开发测试使用
生产环境 3 2 最低高可用配置
生产环境 5 2 推荐配置
生产环境 7 3 强一致性配置

网络架构

┌─────────────────────────────────────────────────────────────────┐
│                      推荐部署架构                                 │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│   ┌─────────────┐    ┌─────────────┐    ┌─────────────┐        │
│   │  DataCenter1│    │  DataCenter2│    │  DataCenter3│        │
│   │             │    │             │    │             │        │
│   │ ┌─────────┐ │    │ ┌─────────┐ │    │ ┌─────────┐ │        │
│   │ │ Master  │ │◄──►│ │ Sentinel│ │    │ │ Sentinel│ │        │
│   │ └─────────┘ │    │ └─────────┘ │    │ └─────────┘ │        │
│   │ ┌─────────┐ │    │             │    │             │        │
│   │ │ Sentinel│ │    │ ┌─────────┐ │    │ ┌─────────┐ │        │
│   │ └─────────┘ │    │ │ Sentinel│ │    │ │ Sentinel│ │        │
│   └─────────────┘    └─────────────┘    └─────────────┘        │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

配置参数详解

参数 默认值 说明
sentinel monitor - 监控配置
sentinel auth-pass - 认证密码
sentinel down-after-ms 30000 主观下线时间
sentinel failover-timeout 180000 故障转移超时
sentinel parallel-syncs 1 并行同步数
sentinel notification-script - 通知脚本
sentinel client-reconfig-script - 重新配置脚本

下一步

接下来让我们学习 Redis 安全配置。

👉 安全配置