资讯动态

分布式系统——Redis哨兵:自动故障转移与选举原理

发布时间:2026/10/16 12:25:48 来源:尧图企业网站定制
文章目录一、概念简述1.1 手动恢复主从为什么不靠谱1.2 哨兵是什么1.3 哨兵自动恢复流程1.4 哨兵的核心功能二、实战搭建2.1 配置主从节点2.2 配置哨兵节点2.3 模拟主节点故障2.4 旧主节点恢复三、故障转移的原理3.1 主观下线与客观下线3.2 选举 leader 哨兵3.3 leader 如何挑选新的主节点3.4 新主确定之后四、总结与局限一、概念简述上一篇讲了主从复制它提高了读的并发和可用性但留下了一个致命的问题主节点挂了怎么办从节点不会自动晋升为主节点整个系统就没法写了。哨兵Sentinel就是用自动化的手段解决这个问题的。1.1 手动恢复主从为什么不靠谱主节点挂了之后如果靠人工处理流程是这样的监控系统报警通知程序员。程序员登录上去看看能不能抢救。抢救不了就从从节点里挑一个作为新的主节点执行slaveof no one。修改其他从节点通过slaveof让它们认新的主节点。告知客户端让它们连接新的主节点。旧主节点修好之后作为一个新的从节点挂回集群。这样的手动修复有两个问题繁琐容易出错步骤多一旦出错后果更严重。慢即使程序员第一时间响应也需要一段时间这段时间系统是不可写的。1.2 哨兵是什么哨兵是独立的进程redis-sentinel不负责存储数据只负责监控。哨兵通常不是单个而是一个集合后面会解释原因。它监控的是 Redis 的数据节点主节点和从节点并在主节点出问题时自动处理。1.3 哨兵自动恢复流程哨兵节点不断给 Redis 数据节点发送心跳包PING检测是否正常。主节点挂了一个哨兵发现后还需要多个哨兵认同才能确认主节点真的挂了以防误判。哨兵们选举出一个 leader由它来负责这次故障转移。leader 从从节点中挑选出新的主节点自动控制它执行slaveof no one并控制其他从节点执行slaveof改认新的主节点。客户端通过哨兵得知新的主节点是谁之后的写操作就会发给新的主节点。旧主节点恢复后哨兵会自动把它变成新主节点的从节点。1.4 哨兵的核心功能监控持续检查主节点、从节点是否正常。自动故障转移主节点挂了自动选出新主并调整主从关系。通知把故障转移的结果通知给客户端和管理员。细节客户端其实不会直接写死 Redis 的地址而是先连哨兵问它当前的主节点是谁sentinel get-master-addr-by-name所以哨兵还承担了配置提供者的角色。为什么哨兵一个节点也能完成完整的功能却还要部署多个①哨兵本身也可能挂如果只有一个哨兵它挂了这时候再碰上 Redis 主节点也挂了就没人做自动恢复了。分布式系统中应当避免出现单点。②误判的概率高网络传输容易延迟、丢包一个哨兵连不上主节点不代表主节点真挂了可能只是这个哨兵到主节点的网络有问题。需要多个哨兵投票才能降低误判。哨兵节点为什么最好是奇数个哨兵的决策都是靠多数派超过半数达成的。3 个哨兵多数是 2允许挂 1 个4 个哨兵多数是 3还是只允许挂 1 个。多出来的那一个并没有提升容错能力反而多了一份开销。所以选奇数个3、5就够了。二、实战搭建准备 6 个节点1 主 2 从 3 哨兵使用Docker Compose来搭建。注意这里为了演示把所有节点放在同一台服务器上。实际应用中所有节点放在一台服务器上是没有意义的服务器挂了就全挂了应该分布在不同的主机上。2.1 配置主从节点创建master-slave/docker-compose.ymlversion:3.7services:master:image:redis:5.0.9container_name:redis-masterrestart:alwayscommand:redis-server--appendonly yesports:-6379:6379slave1:image:redis:5.0.9container_name:redis-slave1restart:alwayscommand:redis-server--appendonly yes--slaveof redis-master 6379ports:-6380:6379slave2:image:redis:5.0.9container_name:redis-slave2restart:alwayscommand:redis-server--appendonly yes--slaveof redis-master 6379ports:-6381:6379启动容器docker-composeup-d细节--slaveof redis-master 6379中直接使用了容器名因为同一个docker网络内容器之间可以通过名字互相访问。2.2 配置哨兵节点创建redis-sentinel/docker-compose.ymlversion:3.7services:sentinel1:image:redis:5.0.9container_name:redis-sentinel-1restart:alwayscommand:redis-sentinel /etc/redis/sentinel.confvolumes:-./sentinel1.conf:/etc/redis/sentinel.confports:-26379:26379sentinel2:image:redis:5.0.9container_name:redis-sentinel-2restart:alwayscommand:redis-sentinel /etc/redis/sentinel.confvolumes:-./sentinel2.conf:/etc/redis/sentinel.confports:-26380:26379sentinel3:image:redis:5.0.9container_name:redis-sentinel-3restart:alwayscommand:redis-sentinel /etc/redis/sentinel.confvolumes:-./sentinel3.conf:/etc/redis/sentinel.confports:-26381:26379networks:default:external:name:master-slave_default注意networks这一段是让哨兵容器加入主从节点所在的网络master-slave_default这样哨兵才能通过容器名访问到redis-master。再创建sentinel1.conf、sentinel2.conf、sentinel3.conf三份文件内容完全相同都放在/root/redis-sentinel/目录中bind0.0.0.0 port26379sentinel monitor redis-master redis-master63792sentinel down-after-milliseconds redis-master1000逐行解释bind 0.0.0.0允许任意地址访问。port 26379哨兵的端口Redis 默认是 6379哨兵默认是 26379。sentinel monitor 名字 ip port quorum名字给被监控的主节点起的名字这里叫redis-master。ip port主节点的地址这里用的是容器名。quorum法定票数。至少有多少个哨兵认为主节点挂了才会判定为客观下线。这里是 2通常设为哨兵总数的一半加一。sentinel down-after-milliseconds 名字 毫秒多久收不到心跳回复就认为主节点主观下线。这里设为 1000ms是为了演示效果实际默认是 30000ms。细节三份配置文件必须是三份独立的文件不能共用一个。因为哨兵运行时会改写自己的配置文件记录自己的 id、发现的从节点和其他哨兵等信息。配置里只写了主节点没有写从节点和其他哨兵因为哨兵会自动发现通过主节点的info命令得到所有从节点再通过主节点上的发布订阅频道互相发现其他哨兵。说明用容器名作为ip是演示的写法Redis 6.2 需要额外配置resolve-hostnames yes才支持主机名生产环境建议直接写 IP。启动哨兵docker-composeup-d2.3 模拟主节点故障手动把主节点停掉dockerstop redis-master主节点一挂哨兵节点就开始工作了。在哨兵的目录下用docker-compose logs查看哨兵节点的工作情况日志里几个关键的事件正好对应故障转移的过程日志事件含义sdown主观下线这个哨兵认为主节点挂了odown客观下线达到法定票数确认主节点挂了try-failover开始尝试故障转移vote-for-leader/elected-leader哨兵之间投票选出 leaderselected-slaveleader 选中了某个从节点作为新主promoted-slave该从节点已晋升为主节点switch-master主节点切换完成通知客户端新主节点的地址2.4 旧主节点恢复再把原来的主节点启动起来观察它的状态docker-composestart master redis-cli-p6379可以发现旧的主节点恢复后变成了从节点挂在新的主节点下面没有抢回主节点的位置。这也是哨兵自动完成的不需要人工干预。三、故障转移的原理哨兵重新选择主节点大致分三步判定主节点挂了 → 选出 leader 哨兵 → leader 选出新的主节点。3.1 主观下线与客观下线主观下线SDOWN一个哨兵给节点发的心跳包在down-after-milliseconds内没有收到有效回复这个哨兵就单方面认为该节点挂了。客观下线ODOWN主观下线只是一个哨兵的看法可能误判。它会询问其他哨兵认为主节点挂了的哨兵数量达到了法定票数quorum才算客观下线才能开始故障转移。这里的挂不一定是进程崩了只要是无法正常访问都可以视为是挂了比如网络不通、进程卡死。3.2 选举 leader 哨兵确认主节点客观下线后需要由一个哨兵来执行故障转移不能多个哨兵各干各的所以要先选出 leader。举个例子1 号哨兵最先发现主节点客观下线它就向其他哨兵发起投票请求给自己投一票另外两个哨兵也给 1 号哨兵投了一票1 号哨兵得票过半成为 leader。本质上是谁反应快、谁先发起谁就更容易当选。这里用的是 Raft 算法的简化版细节quorum只决定能不能判定客观下线真正执行故障转移还需要这个 leader 得到多数超过哨兵总数一半哨兵的授权。这也是哨兵要部署奇数个的原因。3.3 leader 如何挑选新的主节点leader 会去从节点中挑选一个作为新的主节点先排除掉不健康的节点已经下线、断线太久的剩下的按下面三个条件依次比较优先级每个 Redis 数据节点在配置文件中都有一个优先级配置replica-priority默认 100值越小优先级越高设为 0 表示永远不会被选为主节点。offset复制偏移量优先级相同就看同步进度offset 越大说明数据越新越容易胜出。run id前两项都一样就看 run id字典序最小的胜出。run id 是每个 Redis 节点启动时随机生成的一串字符这里只是为了保证最终能选出唯一的节点。为什么要看 offset因为主从复制是异步的从节点的数据可能落后于旧主节点。选 offset 最大的意味着选出的新主丢失的数据最少。3.4 新主确定之后leader 让被选中的节点执行slaveof no one晋升为主节点。leader 让其他从节点执行slaveof 新主节点改认新的主节点。默认一次只让 1 个从节点去同步避免新主压力过大由parallel-syncs配置哨兵把新主节点的信息通知给客户端switch-master。旧主节点恢复后被设置为新主节点的从节点。四、总结与局限哨兵 主从复制 自动故障转移解决了主节点挂了需要人工处理的问题提高了系统的可用性。但它依然有局限写能力和容量没有提升写操作依然只能在一个主节点上每个节点保存的还是全量数据受单机内存限制。切换期间有短暂的不可用从主节点挂了到新主节点选出来这段时间内写操作是失败的。可能丢数据主从复制是异步的旧主节点上还没来得及同步给从节点的数据在切换后会丢失。要解决写能力和存储容量的问题就需要把数据分片存储到多组节点上这就是下一篇要讲的Redis 集群Cluster。非常感谢您能耐心读完这篇文章。倘若您从中有所收获还望多多支持呀

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑