[Redis小技巧26]亿级流量背后的守护神:手写式解析 Redis 哨兵监控、选举与灾难恢复

张开发
2026/5/2 22:29:29 15 分钟阅读

分享文章

[Redis小技巧26]亿级流量背后的守护神:手写式解析 Redis 哨兵监控、选举与灾难恢复
一、核心原理深度解析哨兵模式并非简单的“监控 切换”它是一个分布式的共识系统。理解其核心必须掌握三个关键词监控Monitoring、通知Notification、故障转移Failover。1. 架构全景图在物理机部署中通常采用1 主 2 从 3 哨兵的最小高可用架构。哨兵进程独立于数据节点运行避免资源争抢。这张图展示了一个经典的 3 节点数据层 3 节点管控层 的部署模型。在物理机/虚拟机环境中这种“独立部署、交叉监控”的拓扑是保障高可用的基石。1分层设计哲学 (Layered Architecture)数据层 (Data Plane)vs管控层 (Control Plane)物理隔离原则图中明确将 Redis 数据进程Master/Slave与 Sentinel 监控进程分置于不同的逻辑组。实战教训如果Sentinel 1和Master同在Machine A一旦Machine A宕机断电或硬件故障不仅主库丢失唯一的“故障目击者”也随之下线。剩余的哨兵可能因无法达成Quorum多数派共识而无法触发自动切换导致集群瘫痪。最佳实践采用交叉部署策略。例如机器 A: Master Sentinel 2机器 B: Slave 1 Sentinel 3机器 C: Slave 2 Sentinel 1确保任意单点故障数据层和管控层均保留多数派存活。2数据复制链路 (Replication Links)异步复制机制Master和Slave之间的箭头表示数据单向流动。Master 将写命令传播给 Slaves。潜在风险点这是异步的。如果在故障转移发生的瞬间Master 还有未同步到 Slave 的写入数据写在内存但未刷盘或未传网这部分数据在切换后会永久丢失。3全网格监控 (Full-Mesh Monitoring)去中心化监控每个哨兵Sentinel 1/2/3都独立地向所有数据节点Master Slaves发送PING命令。主观下线 (s_down) 的产生如果Sentinel 1在down-after-milliseconds(例如 5秒) 内没收到Master的回复它会标记 Master 为s_down。关键点此时其他哨兵可能还能正常连接 Master。单个哨兵的判断不代表集群共识。跨网段监控在物理机部署中要特别注意防火墙规则。哨兵需要能telnet通所有数据节点的 6379 端口。很多故障是因为只开了应用访问端口却忘了开哨兵监控端口。4哨兵间通信 (Sentinel Gossip Pub/Sub)通信端口哨兵除了监控端口默认 26379还有一个总线端口默认是监控端口 10000即 36379用于集群间通信。这个端口常被防火墙误杀两大功能存活检测 (Gossip)哨兵之间互相确认“你还活着吗”。如果哨兵自己挂了其他哨兵会感知到。状态同步 (Pub/Sub)当Sentinel 1发现 Masters_down时它通过__sentinel__:hello频道广播这个消息。其他哨兵收到后也会去探测 Master。一旦达到quorum(例如 2 个哨兵) 都确认下线状态升级为客观下线 (o_down)。领导者选举只有达成o_down后哨兵们才会开始投票选举一个“领导者 (Leader)”来执行故障转移。图中的Sentinel 1 [Leader Candidate]暗示了它可能在某次选举中胜出。5客户端交互模式 (Client Interaction)动态发现机制应用程序不应该硬编码 Master 的 IP 地址如192.168.1.10。正确流程客户端启动时连接任意一个哨兵通常配置多个哨兵地址做容错。发送命令SENTINEL get-master-addr-by-name master-name。哨兵返回当前真实的 Master IP。客户端缓存该 IP 并建立连接。故障切换后的行为当发生故障转移新主产生后哨兵会通过 Pub/Sub 发送切换消息。成熟的客户端如 Jedis, Lettuce, Go-Redis监听该消息自动更新本地缓存的 Master IP并重连新主对业务层透明。2. 监控与下线判定机制哨兵通过发送PING命令来检测实例状态。这里有两个关键的时间阈值概念直接决定了系统的敏感度主观下线 (Subjectively Down, s_down)单个哨兵认为实例不可达。判定条件在down-after-milliseconds时间内未收到有效回复。Redis 7.2 变化对连接超时的处理更加精细化减少了因短暂网络抖动导致的误判。客观下线 (Objectively Down, o_down)集群共识认为实例不可达。判定条件当多数派Quorum哨兵配置中的quorum值都标记该主节点为s_down时触发o_down。注意quorum设置通常为哨兵总数 / 2 1。例如 3 个哨兵quorum 设为 2。3. 故障转移全流程推演一旦主节点被判定为o_down故障转移立即启动。这是一个基于Raft 算法变体的选举过程。阶段一确认客观下线 (ODOWN)故障转移的第一步是准确判断主节点是否真的挂了。Sentinel 采用了一种“双重确认”机制以避免因网络抖动导致的误判。1. 主观下线 (Subjectively Down, SDOWN)当某个 Sentinel例如图中的S1即Sentinel 1在配置的超时时间内默认 30 秒没有收到 Master 的有效回复PING 响应它会暂时将 Master 标记为SDOWN。注意此时只是 S1 的“个人观点”其他 Sentinel 可能还认为 Master 是健康的。2. 客观下线 (Objectively Down, ODOWN)为了确认这不是 S1 的网络问题S1 会向集群中的其他 Sentinel 发送is-master-down-by-addr命令进行询问。如果同意的 Sentinel 数量达到了配置的Quorum法定人数S1 就会将 Master 的状态正式升级为ODOWN。ODOWN 意味着集群达成共识Master 真的不可用了。只有达到 ODOWN 状态后续的故障转移流程才会被触发。阶段二领导者选举 (Leader Election)一旦确认 Master 挂掉集群中所有的 Sentinel 都可能会尝试发起故障转移。但为了避免“多头指挥”导致的数据混乱Sentinel 必须选出一个**唯一的领导者Leader**来执行具体的切换操作。这个过程类似于 Raft 协议核心概念是配置纪元 (Config Epoch)。配置纪元 (Config Epoch)每次故障转移都会生成一个新的全局唯一版本号防止旧主恢复后产生数据冲突。发现者发起选举第一个发现 ODOWN 的 SentinelS1会将当前的配置纪元 1并向其他 Sentinel 发送CKUQ(Can I be the Leader?) 请求声称自己是新纪元的候选人。投票机制其他 SentinelS2, S3收到请求后会检查自己是否已经在这个纪元投过票如果未投票它们会同意 S1 的请求将票投给 S1并记录“该纪元已投票”。如果已投票给他人它们会拒绝 S1 的请求。当选 Leader如果 S1 获得了超过半数Quorum的选票它就成为了本次故障转移的Leader。为什么需要选举如果没有选举多个 Sentinel 可能同时选中不同的 Slave 作为新 Master导致脑裂Split-Brain数据一致性将无法保证。阶段三选择新主与提升 (Promotion)当选出 Leader 后真正的“权力交接”开始了。Leader 需要从现有的 Slave 节点中挑选一个最合适的晋升为新的 Master。1. 筛选策略Leader 会根据以下规则对 Slave 进行打分排序优先级从高到低优先级 (Priority)在redis.conf中配置的slave-priority值越小优先级越高。数值越小优先级越高0 表示永不晋升复制进度 (Replication Offset)谁同步的数据最多最接近原 Master谁优先。这能最大程度减少数据丢失。RunID如果以上都相同选择 RunID 较小的那个确定性选择。2. 执行提升假设Slave节点被选中Leader 向该 Slave 发送SLAVEOF NO ONE命令。该 Slave 立即断开与原 Master 的复制关系将自己提升为Master。3. 调整其余从节点紧接着Leader 会向集群中其他的 Slave如图中的Slave2发送SLAVEOF NewMasterIP Port命令。这些 Slave 会立刻切断旧连接转而连接到新的 Master 开始数据同步。至此新的主从架构已经搭建完成服务恢复写入能力。阶段四通知与更新 (Notification)故障转移完成后集群的状态发生了变化必须让所有相关方知道。Sentinel 集群同步Leader 通过 Pub/Sub 频道向其他 Sentinel 广播新的拓扑结构。其他 Sentinel 收到后更新本地缓存确保持久化配置的一致性。客户端通知Leader 会通过switch-master消息发布到 Pub/Sub 频道。支持 Sentinel 模式的客户端如 Jedis, Lettuce, Go-Redis订阅了该频道收到消息后会立即更新本地连接池将写请求指向新的 Master读请求重新分发。对于不支持自动感知的旧客户端可能需要重启或依靠外部配置中心如 Nacos, Apollo进行刷新。总结Redis Sentinel 的故障转移是一个严谨的分布式协作过程SDOWN - ODOWN从“怀疑”到“确诊”避免误杀。Leader 选举利用配置纪元和投票确保“令出一门”。智能选主基于数据完整性和优先级确保“优中选优”。全局通知快速同步状态实现“无感切换”。二、配置最佳实践1. 关键参数详解表参数名推荐值 (生产环境)说明与注意事项down-after-milliseconds5000-10000判定主观下线时间。切忌过短否则网络抖动会导致频繁切换。parallel-syncs1故障转移后并行同步新主的从节点数量。强烈建议设为 1。若设为多会导致大量从节点同时请求全量复制瞬间打爆主节点带宽和 CPU引发二次故障。failover-timeout180000故障转移超时时间3 分钟。包含重试选举、等待从节点同步等全过程。sentinel announce-ip物理机内网 IP物理机部署必填。若服务器有多个网卡如管理网 业务网必须显式指定哨兵对外通告的 IP否则客户端可能连接到错误的接口。sentinel auth-pass强密码建议为哨兵配置独立的访问控制列表而不仅仅是requirepass。min-replicas-to-write(旧称:min-slaves-to-write)1(视架构而定)含义(在主节点配置)主节点执行写操作前必须至少有 N 个从节点处于“正常连接且低延迟”状态。推荐策略• 标准主从 (1主1从)设为 1。确保只要从节点挂掉或断连主节点立即停止写入防止脑裂数据丢失。这是防止主节点在“光杆司令”状态下写入数据导致后续切换数据丢失的关键防线。• 高可用集群 (1主多从)可设为 2 或更多提供更高冗余但会降低可用性从节点波动会导致主节点不可写。• 设为 0关闭此保护默认值允许在主节点孤立时继续写入高风险。副作用当从节点同步慢或网络抖动时主节点会拒绝写入并返回错误NOREPLICAS Not enough good replicas to write。min-replicas-max-lag(旧称:min-slaves-max-lag)10(秒)含义判定从节点是否“有效”的最大延迟阈值秒。如果从节点超过 N 秒未向主节点发送心跳REPLCONF ACK则被视为“坏节点”不计入上面的 N 值中。推荐策略• 局域网/同机房设为 5~10 秒。网络通常很稳设小一点能快速感知故障。• 跨机房/广域网设为 10~30 秒。防止因网络波动导致的误判避免主节点频繁停止服务。注意该值不宜过小否则正常的网络抖动会导致主节点频繁“自杀”停止写入也不宜过大否则失去防脑裂的时效性。2. 物理机环境下的系统与内核调优在虚拟机或物理机上默认的内核参数往往无法支撑高并发下的哨兵心跳和复制流量。文件描述符限制 (ulimit)Redis 能高效处理数万连接。务必在/etc/security/limits.conf中设置redis soft nofile65536redis hard nofile65536内存分配策略 (overcommit_memory)必须设置为1允许内核过度分配内存防止在后台保存 RDB 或进行复制时因内存不足导致进程被 OOM Killer 杀掉。sysctlvm.overcommit_memory1透明大页 (THP)必须关闭。THP 会导致 Redis 在 fork 子进程时产生严重的延迟抖动直接影响故障转移的秒级指标。echonever/sys/kernel/mm/transparent_hugepage/enabled网络 backlog增加 TCP 半连接队列长度防止高并发下连接被丢弃。sysctlnet.core.somaxconn65535sysctlnet.ipv4.tcp_max_syn_backlog8192三、常用命令与实战1. 高频命令速查查看哨兵监控的主节点信息redis-cli-p26379SENTINEL masters# 关注 flags (是否含有 s_down/o_down), down-after-milliseconds, quorum查看特定主节点下的从节点列表redis-cli-p26379SENTINEL slavesmaster-name# 检查每个从节点的 master-link-status 是否为 up模拟主节点下线测试用# 在主节点执行模拟进程挂起redis-cli-hmaster-ipDEBUG SLEEP30# 观察哨兵日志看是否触发切换获取当前主节点地址客户端集成逻辑redis-cli-p26379SENTINEL get-master-addr-by-namemaster-name2. 典型故障场景模拟与排查场景网络分区导致的“脑裂” (Split-Brain)现象客户端向旧主写入数据但旧主实际上已经与大多数哨兵失联同时新主已经选举产生并对外服务。导致部分数据写入旧主后永久丢失。排查步骤检查哨兵日志搜索switch-master关键字确认切换时间点。检查旧主状态登录旧主执行INFO replication。如果它认为自己还是 Master且有从节点连接实际上是网络分区内的少数派则发生了脑裂。数据一致性校验对比新旧主的数据差异使用redis-diff工具或抽样比对。解决方案预防在主节点配置min-slaves-to-write 1和min-slaves-max-lag 10。这样当主节点失去与所有从节点的联系即网络分区超过 10 秒它将自动停止接受写入返回错误从而保护数据不分裂。恢复网络恢复后旧主会自动降级为从节点并强制清空自己的数据全量同步新主的数据。这就是为什么min-slaves-to-write如此重要——它牺牲了分区期间的可用性换取了数据的一致性。3. 哨兵模式适用边界分析维度哨兵模式 (Sentinel)Redis Cluster决策建议数据容量受限于单机内存 (通常 64GB)理论上无限 (分片扩展)单实例数据量 32GB 时慎重考虑哨兵规划迁移至 Cluster。写性能受限于单主节点多主并行写入写吞吐量要求极高时选 Cluster。运维复杂度低 (配置简单易于理解)高 (槽位管理、重平衡复杂)团队缺乏中间件专家时哨兵是更稳妥的选择。事务支持完美支持跨键事务仅支持单键事务 (多键需特殊处理)强依赖多键事务 (如 Lua 脚本操作多个 Key) 的业务哨兵更友好。高可用粒度实例级 (整个库切换)分片级 (单个槽故障不影响全局)对局部故障隔离要求高的场景选 Cluster。结论如果你的业务数据量能控制在单机内存的 50% 以内且对运维透明度要求高哨兵模式依然是“黄金标准”。四、哨兵集群部署实战指南1. 架构规划在开始之前我们需要规划好节点角色。假设我们有三台服务器或同一台服务器的不同端口模拟节点 IPRedis 角色端口Sentinel 角色端口说明192.168.1.10Master6379Sentinel 126379主节点 哨兵1192.168.1.11Slave 16379Sentinel 226379从节点1 哨兵2192.168.1.12Slave 26379Sentinel 326379从节点2 哨兵3 提示如果是单机测试可以将所有 IP 改为127.0.0.1并将端口依次错开如 Redis: 6379, 6380, 6381; Sentinel: 26379, 26380, 26381。下文以多机部署为例。2. 第一步部署 Redis 主从集群Sentinel 是建立在主从复制基础上的因此必须先搭建好主从关系。配置 Master 节点 (192.168.1.10)编辑redis.confbind 0.0.0.0 # 允许外部访问 port 6379 daemonize yes # 后台运行 pidfile /var/run/redis_6379.pid loglevel notice logfile /var/log/redis/redis.log dir /var/lib/redis # 数据目录 # 【重要】设置密码生产环境必须 requirepass YourStrongPassword123 masterauth YourStrongPassword123 # 主从同步时需要 # 【防脑裂核心配置】 min-replicas-to-write 1 min-replicas-max-lag 10配置 Slave 节点 (192.168.1.11 192.168.1.12)在两台从节点机器上编辑redis.conf大部分配置同 Master但需额外添加# ... 其他配置同上 ... # 【关键】指向 Master replicaof 192.168.1.10 6379 # 如果 Master 有密码必须配置 masterauth masterauth YourStrongPassword123 requirepass YourStrongPassword123验证主从关系在 Master 节点执行redis-cli-aYourStrongPassword123 INFO replication看到connected_slaves:2且状态为online即表示主从搭建成功。3. 第二步部署 Sentinel 哨兵集群在三台机器上分别创建 Sentinel 配置文件通常命名为sentinel.conf。配置 Sentinel 1 (192.168.1.10)port 26379 daemonize yes pidfile /var/run/redis-sentinel.pid logfile /var/log/redis/sentinel.log dir /var/lib/redis # 【核心配置】监控主节点 # 语法sentinel monitor 自定义名称 Master IP Master 端口 法定人数 Quorum sentinel monitor mymaster 192.168.1.10 6379 2 # 认证配置如果 Redis 设置了密码 sentinel auth-pass mymaster YourStrongPassword123 # 判定主观下线时间 (毫秒)默认 30000生产建议调小如 5000 sentinel down-after-milliseconds mymaster 5000 # 故障转移超时时间 (毫秒)默认 180000 sentinel failover-timeout mymaster 180000 # 并行同步的从节点数量数字越小越安全越大恢复越快 sentinel parallel-syncs mymaster 1配置 Sentinel 2 3 (192.168.1.11 192.168.1.12)配置文件内容几乎完全相同只需注意port如果在一台机器上跑多个哨兵需错开多机部署则保持 26379 即可。多机部署所有机器上的 Sentinel 必须使用同一个端口号默认 26379。单机部署在同一台机器上启动多个 Sentinel 进程它们的端口号 必须错开例如 26379, 26380, 26381否则会发生端口冲突导致启动失败。sentinel monitor那一行的Master IP必须指向真实的 Master (192.168.1.10)。不需要在配置文件中写其他 Sentinel 的地址它们会自动互相发现。启动 Sentinel在三台机器上分别执行# 注意使用 redis-sentinel 命令启动或者用 redis-server 指定 sentinel 模式redis-sentinel /path/to/sentinel.conf# 或者redis-server /path/to/sentinel.conf--sentinel4. 第三步验证与测试检查哨兵状态连接任意一个哨兵节点redis-cli-p26379127.0.0.1:26379SENTINEL masters预期输出name: “mymaster”ip: “192.168.1.10”flags: “master”num-slaves: 2num-other-sentinels: 2 (关键说明发现了另外两个哨兵)quorum: 2再检查从节点列表127.0.0.1:26379SENTINEL slaves mymaster应列出两个健康的 Slave。模拟故障转移 (Failover Test)** 警告生产环境请勿随意操作**手动 Kill 掉 Master 进程# 在 192.168.1.10 上执行pkillredis-server观察日志查看任意 Sentinel 的日志 (tail -f /var/log/redis/sentinel.log)。你会看到类似以下的流程sdown(主观下线)odown(客观下线达成 Quorum)new-epoch(开启新纪元)vote-for-leader(选举 Leader)elected-leader(选出 Leader)failover-state-select-slave(挑选新主)failover-state-send-slaveof-noone(提升新主)switch-master(切换完成更新配置)验证新主再次执行SENTINEL masters你会发现ip已经变成了原来的某个 Slave (如 192.168.1.11)且 flags 变为master。恢复旧主重新启动原来的 Master (192.168.1.10)。它会自动变成新 Master 的Slave实现自动恢复。5. 常见问题排查 (FAQ)问题现象可能原因解决方案Sentinel 找不到 Master密码错误或网络不通检查sentinel auth-pass是否与 Redisrequirepass一致检查防火墙端口 (6379, 26379)。Quorum 无法达成哨兵之间网络分区确保所有 Sentinel 节点之间 TCP 互通检查sentinel monitor中的 IP 是否可达。故障转移后旧主变从失败旧主配置未清空或版本不一致重启旧主前可尝试清空redis.conf中的replicaof(Sentinel 会自动改写配置但有时需重启生效)。脑裂风险未配置min-replicas-to-write务必在 Redis 主节点配置该参数见上文表格防止分区时双写。五、常见面试题Q1: 在哨兵集群中如果配置了 3 个哨兵Quorum 设为 2。此时网络分区导致 2 个哨兵与主节点失联但这 2 个哨兵之间网络正常。会发生故障转移吗为什么答案会触发选举并产生新的“局部”Master但会导致严重的“脑裂”Split-Brain风险而非健康的故障转移。详细解析三步走逻辑判定下线成功失联的 2 个哨兵设为 S1, S2互相通信确认对方也连不上 Master。票数达到 2 票满足Quorum2的要求。结果S1 和 S2 将 Master 标记为客观下线 (ODOWN)。领导者选举成功S1 发起选举请求。由于 S1 和 S2 网络互通S2 会投票给 S1。S1 获得 2 票超过总数 3 的半数成功当选为故障转移领导者 (Leader)。执行转移与后果危险 - 脑裂动作S1 (Leader) 会在它所能连接到的 Slave 中挑选一个将其提升为新 Master。现状此时集群中出现两个“活着的”Master旧 Master在第 3 个哨兵 (S3) 的视角里依然健康继续接受部分客户端的写入。新 Master在 S1/S2 的视角里是新主接受另一部分客户端的写入。结论这就是典型的脑裂 (Split-Brain)。数据被写入到了两个不同的节点网络恢复后旧 Master 的数据通常会被覆盖丢失。Q2: 为什么parallel-syncs推荐设置为 1设置为 0 或更大的值会有什么后果答案设置为 1 是为了平衡恢复速度与主节点负载。解析若设为0从节点不会自动同步需要人工干预违背高可用初衷。若设为N (1)故障转移后N 个从节点会同时向新主发起全量复制BGSAVE 传输。这会瞬间消耗新主大量的 CPU用于生成 RDB、内存缓冲区和网络带宽。极易导致新主响应超时甚至被误判为故障引发连环雪崩。设置为 1 意味着逐个同步虽然总恢复时间稍长但保证了系统的稳定性。Q3: 简述哨兵模式下“脑裂”产生的原因及 Redis 如何从配置层面规避答案原因是网络分区导致旧主认为自己是主并继续接收写入而新主已被选举。解析规避的核心配置是min-slaves-to-write和min-slaves-max-lag。当主节点发现连接的从节点数量少于设定值或延迟过大它将拒绝写入请求。这遵循了 CP 模型一致性优先在网络分区时牺牲可用性防止数据分裂。Q4: Redis 7.2 中哨兵与主从节点之间的认证机制有什么变化如果配置错误会发生什么答案7.2 更深入地集成了 ACL (Access Control List)。解析以前主要靠requirepass。现在可以为哨兵创建特定的用户赋予sentinel权限组。如果配置错误如密码错误或权限不足哨兵日志会频繁打印AUTH failed或NOAUTH Permission denied且无法获取主从状态导致一直报s_down却无法达成o_down因为无法正确通信或者无法下发SLAVEOF命令导致故障转移卡死。Q5: 假设一个 5 哨兵的集群Quorum 设为 3。现在挂了 2 个哨兵主节点也挂了。还能自动故障转移吗答案能。解析剩余 3 个哨兵存活。3 个哨兵足以构成多数派3 Quorum 3。它们可以互相通信确认主节点下线并选举出领导者完成转移。只要存活的哨兵数量 Quorum系统就能正常工作。这也是为什么建议哨兵数量为奇数且至少 3 个的原因。

更多文章