Redis 哨兵机制: 实现高可用的利器

Redis 作为一款高性能的键值对存储系统, 在缓存、数据库等场景中被广泛应用。然而, 在传统的主从复制架构中, 仍然存在一些问题, 特别是在主节点故障时的处理上。为了解决这些问题,Redis 引入了哨兵机制, 本文将详细介绍 Redis 哨兵机制的概念、工作原理以及如何搭建一个哨兵系统。

1. 哨兵机制的由来

在传统的 Redis 主从复制架构中, 主要存在两个问题:

  1. 主节点故障时, 需要手动进行主备切换, 这个过程复杂且需要人工参与, 无法保证故障恢复的时效性。
  2. 虽然主节点可以将读压力分散到从节点, 但写压力和存储压力仍然集中在主节点, 受到单机性能的限制。

哨兵机制主要解决了第一个问题, 即高可用性问题。它能够在主节点故障时自动完成故障发现和故障转移, 并通知应用程序, 从而实现真正的高可用。

2. 哨兵机制概述

Redis 的哨兵机制是一个分布式系统, 包含多个哨兵节点和 Redis 数据节点。每个哨兵节点会监控数据节点和其他哨兵节点。当发现节点不可达时, 哨兵会对该节点进行下线标识。如果下线的是主节点, 哨兵们会进行"协商", 当大多数哨兵对主节点不可达达成共识后, 它们会选举出一个领导者来完成自动故障转移, 并实时通知 Redis 客户端。整个过程是完全自动的, 无需人工干预。

3. 搭建哨兵系统

接下来, 我们将使用 Docker 来搭建一个 Redis 哨兵环境, 包括 3 个数据节点 (1 主 2 从) 和 3 个哨兵节点。

3.1 搭建数据节点

首先, 我们需要创建一个 docker-compose.yml 文件来定义数据节点:

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

这个配置文件定义了三个服务: 一个主节点和两个从节点。每个节点都使用 Redis 5.0.9 镜像, 并启用了 AOF 持久化。从节点通过--slaveof 参数指定了主节点的地址和端口。

使用以下命令启动数据节点:

sudo docker-compose up -d

3.2 搭建哨兵节点

接下来, 我们需要为哨兵节点创建配置文件。在 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

这个配置指定了哨兵监听的主节点信息, 以及判断主节点失效的条件。

然后, 创建另一个 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
  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 

使用以下命令启动哨兵节点:

sudo docker-compose up -d

4. 哨兵机制的工作原理

哨兵机制的工作流程主要包括以下几个步骤:

4.1 主观下线

当主节点宕机时, 与主节点和哨兵之间的心跳包通信中断。此时, 每个哨兵节点会将主节点标记为主观下线 (Subjective Down, SDown), 并投票表示故障。

4.2 客观下线

当故障得票数达到或超过配置的法定票数时, 主节点被认定为客观下线 (Objective Down, ODown) 。

4.3 选举哨兵 leader

为了协调选举新主节点的工作, 哨兵节点们需要先选出一个 leader 。这个过程使用了 Raft 算法:

  1. 每个哨兵节点向其他所有哨兵节点发起"拉票请求"。
  2. 收到请求的节点会回复"投票响应", 可能投票或不投票。
  3. 如果某个哨兵获得超过半数的票, 它就成为 leader 。

4.4 选举新主节点

leader 哨兵负责从从节点中选择一个作为新的主节点。选择标准如下:

  1. 优先级高 (配置项 slave-priority 或 replica-priority 值小) 的优先。
  2. 复制偏移量 (replication offset) 大的优先。
  3. 运行 ID(run id) 小的优先。

4.5 故障转移

选出新主节点后,leader 哨兵会执行以下操作:

  1. 向选中的从节点发送 SLAVEOF NO ONE 命令, 使其成为新主节点。
  2. 向其他从节点发送 SLAVEOF 命令, 使它们连接到新主节点。
  3. 更新客户端配置, 将写操作转向新主节点。

5. 哨兵机制的注意事项

  1. 哨兵节点不应只有一个, 否则哨兵节点故障会影响整个系统的可用性。
  2. 哨兵节点数量最好是奇数, 便于 leader 选举。
  3. 哨兵节点不存储数据, 数据存储仍由 Redis 主从节点负责。
  4. 哨兵机制解决了高可用性问题, 但不能解决数据丢失或存储容量受限的问题。
  5. 当数据量接近或超过机器物理内存时, 可能需要考虑使用 Redis 集群来扩展存储容量。

6. 结论

Redis 哨兵机制是一个强大的工具, 能够大大提高 Redis 系统的可用性。通过自动故障检测和故障转移, 它降低了系统维护的复杂度, 减少了人工干预的需求。然而, 在使用哨兵机制时, 我们也需要注意它的局限性, 并根据实际需求选择合适的 Redis 架构方案。

参考文献

  1. [Redis] 哨兵机制-CSDN 博客. https://blog.csdn.net/a_zhee1/article/details/140165865

发表评论