《7天学会Redis》Day 4 - 高可用架构设计与实践

本期内容为自己总结归档,7天学会Redis。其中本人遇到过的面试问题会重点标记。

Day 1 - Redis核心架构与线程模型

Day2 - 深入Redis数据结构与底层实现

Day 3 - 持久化机制深度解析

Day 4 - 高可用架构设计与实践

Day 5 - Redis Cluster集群架构

Day 6 - 内存&性能调优

Day 7 - Redisson 框架

(若有任何疑问,可在评论区告诉我,看到就回复)

Day 4 - 高可用架构设计与实践

4.1 主从复制全流程解析

4.1.1 Redis主从复制概述

Redis主从复制是Redis高可用架构的基础,它允许将一台Redis服务器的数据复制到多台从服务器上。主从复制不仅提供了数据冗余,还实现了读写分离和故障恢复能力。

核心价值:

  1. 数据冗余:多副本保证数据安全

  2. 读写分离:主库写,从库读,提升系统吞吐量

  3. 故障恢复:主库故障时,从库可提升为主库继续服务

  4. 负载均衡:多个从库分担读请求压力

4.1.2 主从复制全流程详解

初始化连接建立
全量复制过程

当从节点首次连接主节点,或者主从复制中断时间过长导致复制偏移量不在积压缓冲区中时,会触发全量复制。

部分复制(增量复制)

当主从连接短暂中断后重连,如果从节点的复制偏移量仍在主节点的复制积压缓冲区中,则可以只同步中断期间的数据。

复制积压缓冲区详解

复制积压缓冲区是主节点维护的一个固定大小的循环队列,用于保存最近传播的写命令。

与repl_backlog的区别:

  • repl_backlog:环形,用于部分复制,大小固定

  • repl_buffer:每个从节点独立,线性,存放全量复制期间的增量命令

配置参数:

bash 复制代码
# redis.conf配置
repl-backlog-size 1mb      # 积压缓冲区大小,默认1MB
repl-backlog-ttl 3600      # 主节点无连接时保留时间,默认1小时
无盘复制优化

传统的全量复制需要主节点将RDB文件写入磁盘,然后通过网络发送给从节点。无盘复制允许主节点直接将RDB数据通过网络发送给从节点,避免磁盘I/O。

启用无盘复制:

bash 复制代码
# redis.conf配置
repl-diskless-sync yes      # 启用无盘复制
repl-diskless-sync-delay 5  # 延迟秒数,等待更多从节点连接

无盘复制适用场景:

  1. 磁盘I/O瓶颈:主节点磁盘性能较差时

  2. 网络带宽充足:网络带宽大于磁盘I/O带宽时

  3. 多个从节点同时同步:避免重复磁盘读写

4.1.3 主从复制状态监控

关键指标监控:

bash 复制代码
# 查看复制信息
redis-cli info replication

# 关键指标解释:
# role:master/slave              # 角色
# connected_slaves:2             # 连接的从节点数
# master_replid:...              # 主节点复制ID
# master_repl_offset:123456      # 主节点复制偏移量
# slave_repl_offset:123450       # 从节点复制偏移量
# repl_backlog_active:1          # 积压缓冲区是否激活
# repl_backlog_size:1048576      # 积压缓冲区大小
# repl_backlog_first_byte_offset:123000  # 积压缓冲区起始偏移
复制代码

4.2 Sentinel哨兵机制

4.2.1 Sentinel架构概述

Sentinel(哨兵)是Redis官方提供的高可用解决方案,它监控Redis主从集群,并在主节点故障时自动进行故障转移。

Sentinel核心功能:

  1. 监控:持续检查主从节点是否正常运行

  2. 通知:当被监控节点出现问题时,通过API通知管理员

  3. 自动故障转移:主节点故障时,自动将一个从节点提升为主节点

  4. 配置提供者:客户端连接时,提供当前主节点的地址

4.2.2 主观下线与客观下线

主观下线(Subjectively Down)

当单个Sentinel实例在配置的down-after-milliseconds时间内没有收到目标节点的有效回复(PING响应),该Sentinel就会将目标节点标记为主观下线

配置示例:

bash 复制代码
# sentinel.conf
sentinel monitor mymaster 192.168.1.100 6379 2
sentinel down-after-milliseconds mymaster 5000  # 5秒无响应认为主观下线
客观下线(Objectively Down)

当足够数量的Sentinel(由quorum参数决定)都将某个主节点标记为主观下线时,这个主节点就会被标记为客观下线,这时可以触发故障转移流程。

客观下线判定条件:

复制代码
客观下线 = (标记主节点为主观下线的Sentinel数量) ≥ quorum

quorum配置说明:

bash 复制代码
# sentinel.conf
sentinel monitor mymaster 192.168.1.100 6379 2  # 最后的2就是quorum值
  • quorum=1:只要1个Sentinel认为主观下线就触发故障转移(容易误判)

  • quorum=2:需要2个Sentinel都认为主观下线

  • quorum=多数:通常设置为Sentinel数量的多数(如3个Sentinel时quorum=2)

4.2.3 领导者选举算法(Raft协议变种)

当主节点被判定为客观下线后,Sentinel集群需要选举一个领导者来执行故障转移操作。Sentinel使用类似于Raft协议的选举算法。

选举流程:

选举算法关键点:

  1. 纪元(epoch):每个Sentinel维护一个递增的纪元,每次选举尝试都会增加纪元

  2. 先到先得:每个Sentinel在每个纪元只能投票给第一个请求的候选者

  3. 多数原则:需要获得超过半数的投票才能成为领导者

  4. 随机延迟:Sentinel在发现客观下线后,会等待一个随机时间再发起选举,避免多个Sentinel同时发起

选举配置参数:

bash 复制代码
# sentinel.conf
sentinel failover-timeout mymaster 180000  # 故障转移超时时间,默认3分钟

4.2.4 故障转移完整流程

步骤1:选择新的主节点

Sentinel根据以下规则从从节点中选择新的主节点:

  1. 排除已经下线或断线的从节点

  2. 排除最近5秒内没有回复过Sentinel INFO命令的从节点

  3. 排除与已下线主节点连接断开时间超过down-after-milliseconds * 10的从节点

  4. 选择优先级最高的从节点(由slave-priority配置)

  5. 如果优先级相同,选择复制偏移量最大的从节点

  6. 如果复制偏移量相同,选择runid最小的从节点

步骤2:提升新的主节点

bash 复制代码
# Sentinel执行的命令序列
1. 向选中的从节点发送:SLAVEOF NO ONE
2. 等待该节点提升为主节点(通过INFO命令确认role:master)
3. 向其他从节点发送:SLAVEOF <new_master_ip> <new_master_port>

步骤3:更新Sentinel配置

bash 复制代码
# Sentinel修改监控配置
# 将旧的主节点从配置中移除,添加新的主节点
sentinel monitor mymaster <new_master_ip> <new_master_port> <quorum>

步骤4:客户端通知

Sentinel通过发布/订阅机制通知客户端配置变更:

bash 复制代码
# 客户端监听Sentinel的频道
SUBSCRIBE +switch-master

# 当故障转移发生时,Sentinel会发布消息:
PUBLISH +switch-master mymaster <old_ip> <old_port> <new_ip> <new_port>

4.2.5 Sentinel集群部署最佳实践

Sentinel节点数量建议
Sentinel数量 Quorum设置 容忍故障数 优点 缺点
1 1 0 简单 单点故障,不推荐
3 2 1 推荐配置 需要3台服务器
5 3 2 高可用性 资源消耗多
6 4 2 避免脑裂 复杂

推荐配置:3个或5个Sentinel节点

部署架构示例
Sentinel配置示例
bash 复制代码
# sentinel.conf 完整示例

# 监控名为mymaster的主节点
sentinel monitor mymaster 192.168.1.100 6379 2

# 主观下线时间:5秒无响应
sentinel down-after-milliseconds mymaster 5000

# 故障转移超时时间:3分钟
sentinel failover-timeout mymaster 180000

# 故障转移时,最多有多少个从节点同时同步新的主节点
sentinel parallel-syncs mymaster 1

# 设置密码(如果Redis有密码)
sentinel auth-pass mymaster MyPassword

# Sentinel自身端口
port 26379

# 守护进程模式
daemonize yes

# 日志文件
logfile "/var/log/redis/sentinel.log"

# 工作目录
dir "/tmp"

4.3 脑裂问题与解决方案

4.3.1 什么是脑裂(Split-Brain)?

定义 :因网络分区,旧主节点未真正宕机,但被哨兵判死,新主节点上线,导致出现两个主节点,数据写入混乱。

脑裂发生场景:

  1. 网络故障导致主节点与部分从节点、Sentinel断开连接

  2. 网络分区后,每个分区都选举出自己的主节点

  3. 网络恢复后,出现两个主节点,数据不一致

4.3.2 脑裂的危害

  1. 数据不一致:两个主节点同时接受写请求,数据无法自动合并

  2. 数据丢失:网络恢复后,旧主节点的数据可能被丢弃

  3. 客户端混乱:客户端可能连接到不同的主节点

  4. 系统不可用:需要人工干预解决冲突

4.3.2 min-slaves配置策略

核心思想:主节点必须至少有N个从节点连接,才允许写入。

配置

bash 复制代码
# redis.conf
min-replicas-to-write 1  # 至少1个从节点连接,否则主节点拒绝写入
min-replicas-max-lag 10  # 从节点延迟<10秒才计入

工作原理:

  1. 当主节点连接的正常从节点数量少于min-slaves-to-write时,主节点拒绝写操作

  2. 当所有从节点的复制延迟都超过min-slaves-max-lag秒时,主节点拒绝写操作

  3. 这样确保在网络分区时,只有拥有足够从节点的主节点才能接受写请求

4.3.4 客户端连接验证机制

除了服务器端配置,客户端也需要采取措施来应对脑裂问题。

客户端验证策略
  1. 双重检查机制:客户端在写入前,从多个Sentinel获取当前主节点信息

  2. 写后验证:写入后立即读取验证,如果不一致则重新获取主节点

  3. 连接池监控:定期检查连接的主节点是否仍然有效

Sentinel防脑裂配置
bash 复制代码
# sentinel.conf
# 设置Sentinel的quorum值为Sentinel数量的多数
# 3个Sentinel时设置为2,5个时设置为3

# 增加故障转移的条件
sentinel monitor mymaster 192.168.1.100 6379 2

# 设置从节点晋升条件
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 180000
sentinel parallel-syncs mymaster 1

4.3.5 脑裂后的恢复策略

当脑裂确实发生后,需要按照以下步骤恢复:

步骤1:识别脑裂

bash 复制代码
# 检查所有节点的主从状态
redis-cli -h node1 info replication | grep role
redis-cli -h node2 info replication | grep role
redis-cli -h node3 info replication | grep role

如果有多个节点显示role:master,说明发生脑裂

步骤2:选择保留的主节点

  1. 选择数据更完整的节点(复制偏移量更大)

  2. 选择客户端连接更多的节点

  3. 选择与业务系统关联更紧密的节点

步骤3:恢复一致性

bash 复制代码
# 1. 将其他"主节点"降级为从节点
redis-cli -h old_master_ip SLAVEOF new_master_ip 6379

# 2. 强制同步数据(可能会丢失部分数据)
redis-cli -h old_master_ip SLAVEOF NO ONE
redis-cli -h old_master_ip FLUSHALL
redis-cli -h old_master_ip SLAVEOF new_master_ip 6379

# 3. 检查数据一致性
redis-cli -h new_master_ip info replication

4.4 面试高频考点

考点1:Sentinel的客观下线和主观下线是什么?

面试回答:

主观下线和客观下线是Sentinel监控机制中的两个核心概念:

主观下线(Subjectively Down):

  • 定义 :单个Sentinel实例在配置的down-after-milliseconds时间内没有收到目标节点的有效回复(PING响应)

  • 判断依据:基于单个Sentinel的视角

  • 配置sentinel down-after-milliseconds <master-name> <milliseconds>

  • 特点:主观判断,可能存在误判(如网络抖动)

客观下线(Objectively Down):

  • 定义:当足够数量的Sentinel(由quorum参数决定)都将某个主节点标记为主观下线时,这个主节点被标记为客观下线

  • 判断依据:基于多个Sentinel的共识

  • 配置sentinel monitor <master-name> <ip> <port> <quorum>

  • 特点:客观判断,需要多个Sentinel达成一致,更可靠

关系:主观下线是客观下线的必要条件。只有先有主观下线,才可能触发客观下线。客观下线是故障转移的前提条件。

考点2:Sentinel领导者选举过程是怎样的?

面试回答:

Sentinel领导者选举使用类似于Raft协议的算法:

  1. 触发条件:当主节点被判定为客观下线时,Sentinel集群需要选举一个领导者来执行故障转移

  2. 选举过程

    • 每个发现主节点客观下线的Sentinel都会自增纪元(epoch)

    • 每个Sentinel向其他Sentinel发送投票请求

    • 每个Sentinel在每个纪元只能投一票,遵循先到先得原则

    • 获得超过半数(包括自己)投票的Sentinel成为领导者

    • 如果本次选举没有产生领导者,等待一段时间后重新选举

  3. 关键机制

    • 纪元(epoch):递增的计数器,每次选举尝试增加

    • 随机延迟:Sentinel在发起选举前等待随机时间,避免多个Sentinel同时发起

    • 多数原则:需要获得超过半数的投票

  4. 选举失败处理 :如果选举超时(由failover-timeout配置),会重新发起选举

考点3:什么是脑裂?如何预防和解决Redis脑裂问题?

面试回答:

脑裂是指在分布式系统中,由于网络分区导致集群被分割成多个独立部分,每个部分都选举出自己的主节点,从而出现多个主节点的情况。

预防措施:

  1. 合理配置Sentinel

    • 设置适当的quorum值(通常为Sentinel数量的多数)

    • 部署足够数量的Sentinel节点(至少3个,推荐5个)

  2. Redis配置优化

    bash 复制代码
    # 主节点配置
    min-slaves-to-write 1      # 至少需要1个从节点
    min-slaves-max-lag 10      # 从节点延迟不超过10秒
  3. 网络和部署优化

    • 确保网络稳定性,避免网络分区

    • 将Sentinel部署在不同机架或可用区

    • 使用高质量的网络设备

  4. 客户端防护

    • 客户端实现双重验证机制

    • 写后验证,确保数据一致性

解决方案:

一旦发生脑裂:

  1. 识别脑裂:检查所有节点的role状态

  2. 选择保留的主节点:基于数据完整性、客户端连接数等因素

  3. 恢复一致性

    • 将其他"主节点"降级为从节点

    • 可能需要手动同步或丢弃部分数据

  4. 修复根本原因:检查网络配置,调整Sentinel参数

相关推荐
NineData2 小时前
第三届数据库编程大赛-八强决赛成绩揭晓
数据库·算法·代码规范
難釋懷2 小时前
认识Redis
数据库·redis·缓存
超级种码2 小时前
Redis:Redis脚本
数据库·redis·缓存
想唱rap2 小时前
表的约束条件
linux·数据库·mysql·ubuntu·bash
超级种码2 小时前
Redis:Redis 命令详解
数据库·redis·bootstrap
qq_401700413 小时前
Qt 事件处理机制
java·数据库·qt
Elastic 中国社区官方博客3 小时前
使用 jina-embeddings-v3 和 Elasticsearch 进行多语言搜索
大数据·数据库·人工智能·elasticsearch·搜索引擎·全文检索·jina
深海小黄鱼3 小时前
mysql 导入csv文件太慢, Error Code: 1290.
数据库·mysql
小宇的天下3 小时前
Calibre Connectivity Extraction(21-1)
数据库·oracle