尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Redis哨兵集群实战:从主从复制到自动故障转移

Redis哨兵集群实战:从主从复制到自动故障转移 做个高可用的Redis到底难不难说难也难说容易也容易。如果只是搭主从复制半小时就能搞定但主节点一挂整个写入链路就断了还得人工上去切换半夜被叫起来处理这种事干过运维的都懂。想要让Redis在节点故障时自己“选”出新的主节点、自动完成切换就得靠哨兵Sentinel这套机制。这篇文章我会用1主2从加3个哨兵的完整架构把Linux下的Redis哨兵集群从规划、配置、启动到故障演练、问题排查整个流程走一遍适合正在学Redis高可用、准备在生产环境部署哨兵模式或者被面试题问到“哨兵怎么实现自动故障转移”的同学。我之前在不少项目里踩过哨兵相关的坑比如主观下线误判、哨兵配置被自动改掉、故障转移后客户端连不上等。这些细节官方文档写得比较“标准”但实际部署时遇到的问题往往更具体。下面就把我实操过的步骤和心得拆开讲每一步都有配置示例和验证方法照着做即可复现一套完整的Redis哨兵集群。1. 为什么要搭“1主2从3哨兵”主从复制的痛点与哨兵的解法先想清楚一个问题Redis主从复制到底解决了什么又没解决什么。主从复制解决了数据冗余和读写分离的问题——主节点负责写从节点负责读还能定时做备份。但它有一个硬伤如果主节点挂掉从节点不会自动上位整个系统的写入能力直接就没了。这时候要么人工登录服务器手动执行replicaof no one把某个从节点提升为主节点再让其他从节点重新指向它这个过程一般得几分钟甚至更久业务影响很大。哨兵Sentinel就是专门干这个的。它是一个独立运行的进程负责监控Redis主从节点的健康状况并在主节点故障时自动执行故障转移。它干了三件事监控、通知、自动故障转移。监控是周期性地向所有节点发PING命令判断它们是不是活着通知是把节点状态变化推送给客户端或其他哨兵故障转移则是当主节点被判定为不可用后从从节点中选出一个新的主节点并把其他从节点重新指向新主节点。1.1 哨兵集群为什么一定要奇数个而且推荐3个很多人把“3个哨兵”当成标配但不知道背后的逻辑。哨兵在判定主节点是否真的挂了时采用“投票”机制。单个哨兵发现主节点没响应会先标记为主观下线sdown然后把这个判断通过sentinel集群内部频道广播给其他哨兵。当超过quorum数量的哨兵都认为主节点不可用时才会标记为客观下线odown这时才允许触发故障转移。这个quorum通常是N/2 1也就是超过一半。如果只有1个哨兵那它自己说了算存在误判风险如果有2个哨兵其中一个挂了剩下1个永远无法满足“超过一半”的条件整个故障转移就瘫痪了而3个哨兵即使挂掉1个还剩2个依然能满足半数规则。这就是为什么哨兵必须部署奇数个生产环境最低建议3个。1.2 哨兵是单点吗它自己会不会挂哨兵本质上一个Redis服务器跑在特殊模式下但它本身不做数据存储只是维护监控状态。它是独立进程如果和Redis主节点放在同一台机器上机器宕机时Redis和哨兵一起挂这种方法在资源有限时可以接受但生产环境最好把哨兵分散到不同物理机或不同机柜避免“同生共死”。本文演示环境受限于机器数量采用Redis与哨兵同机部署但原理和配置完全一致生产上你按这个思路把哨兵拆到独立节点即可。2. 环境规划与安装准备三台节点怎么分配动手之前先把拓扑图画清楚。本文环境是3台Linux服务器IP分别规划为192.168.1.101、192.168.1.102、192.168.1.103每台机器上运行一个Redis实例外加一个哨兵进程整体架构是1主2从3哨兵。节点角色分配如下表。节点IPRedis角色哨兵角色Redis端口哨兵端口node1192.168.1.101主节点master哨兵1637926379node2192.168.1.102从节点replica哨兵2637926379node3192.168.1.103从节点replica哨兵36379263792.1 Redis安装与目录结构规划Redis版本这里以6.0.x或7.0.x为例需要说明的是6.0之前的版本主从复制的配置项叫slaveof6.0之后改成了replicaof虽然老配置兼容但建议直接用新写法。下载源码包后解压编译操作流程如下。# 下载并解压以redis-7.0.12为例 wget https://download.redis.io/releases/redis-7.0.12.tar.gz tar xzf redis-7.0.12.tar.gz cd redis-7.0.12 make -j$(nproc) make install PREFIX/usr/local/redismake完成之后二进制文件会安装到/usr/local/redis/bin目录下里面包含redis-server、redis-cli、redis-sentinel等可执行文件。生产环境不建议直接用源码目录下的默认配置而是单独建一套属于自己的目录结构方便后续管理和备份恢复。mkdir -p /data/redis/{conf,data,logs,run} cp /usr/local/redis/conf/redis.conf /data/redis/conf/我习惯把配置文件、数据文件、日志文件分开放目录隔离在故障排查时真的很省事。比如数据文件放/data/redis/data日志放/data/redis/logsPID文件放/data/redis/run这样需要清理磁盘或做备份时路径一看就知道。2.2 redis.conf基础配置这些参数必须先改编译安装完配置文件里很多默认参数并不适合直接用于集群部署特别是bind、protected-mode、daemonize这几项新手翻车基本都翻在这里。下面以主节点为例列出启动前必须处理的关键配置项。# 主节点 /data/redis/conf/redis.conf bind 0.0.0.0 protected-mode no port 6379 daemonize yes pidfile /data/redis/run/redis_6379.pid logfile /data/redis/logs/redis_6379.log dir /data/redis/data appendonly yes appendfilename appendonly.aof逐项解释一下为什么要这么设。bind 0.0.0.0表示监听所有网卡这样从节点和哨兵才能通过网络访问如果bind设为127.0.0.1外部节点连不上主从复制直接失败。protected-mode no是和bind配合使用的Redis默认开启保护模式在没有密码且bind本地地址时只允许本机访问跨节点访问会被拒绝。daemonize yes让Redis在后台运行避免占用前台终端。appendonly yes开启AOF持久化故障转移后新主节点能最大程度保留数据。关于持久化多说一句如果只在内存里跑主节点挂了数据从从节点同步还能找回但如果在主节点故障的同时从节点也异常数据可能就没了。生产环境建议AOF和RDB都开着AOF做实时恢复RDB做冷备和快速启动。3. 主从复制配置先把数据同步链路打通哨兵发挥作用的前提是主从复制本身是好的。如果主从复制都没搭建成功哨兵即使完成了切换新主节点也没有完整数据业务照样出问题。所以先把主从复制搞定再上哨兵。3.1 从节点配置关键就一个replicaof两个从节点的redis.conf除了节点自身的角色设置其余基本和主节点一样。唯一的关键区别是要加一行replicaof配置指向主节点的IP和端口。# 从节点 /data/redis/conf/redis.confnode2和node3都这样配 bind 0.0.0.0 protected-mode no port 6379 daemonize yes pidfile /data/redis/run/redis_6379.pid logfile /data/redis/logs/redis_6379.log dir /data/redis/data appendonly yes replicaof 192.168.1.101 6379小细节从节点本身也建议开启appendonly这样即使从节点被提升为主节点它自己的AOF文件也能提供数据保障。replicaof这个配置项一旦生效从节点启动后会自动向主节点发起全量同步请求把主节点的数据拉过来。3.2 主从启动与复制状态验证启动顺序上先启主节点再启从节点这个顺序能减少同步报错的概率。分别在三台机器上执行启动命令。# 主节点 node1 redis-server /data/redis/conf/redis.conf # 从节点 node2、node3 redis-server /data/redis/conf/redis.conf启动完成后在任意一台机器上执行redis-cli info replication重点看几个字段。正常情况下主节点上可以看到connected_slaves:2两个从节点的IP都在列表里从节点上可以看到master_link_status:up表示和主节点的连接正常master_last_io_seconds_ago应该是一个很小的数字。redis-cli -h 192.168.1.101 -p 6379 info replication如果master_link_status是down不要急着往下走。常见原因有三种bind配置不对、protected-mode没关、防火墙挡了6379端口。关防火墙的命令各发行版不一样CentOS系是systemctl stop firewalldUbuntu系是ufw disable。测试环境图省事可以关掉生产环境还是建议加白名单规则只放行集群内互相访问的IP和端口。3.3 用一条测试命令验证复制是否真的在跑光看状态还不够最好实际写一条数据验证同步链路。在主节点写入到从节点读取。# 主节点写入 redis-cli -h 192.168.1.101 -p 6379 set hello sentinel-cluster # 从节点读取 redis-cli -h 192.168.1.102 -p 6379 get hello # 另一个从节点读取 redis-cli -h 192.168.1.103 -p 6379 get hello三个节点都能返回sentinel-cluster说明主从复制链路是通的。这一步非常关键它能提前暴露网络和配置问题避免后续哨兵配置完成后才发现是因为主从没复制导致切换后丢数据。4. 三个哨兵的配置与启动最难抠的其实是参数主从复制搞定后终于到重头戏——哨兵。哨兵配置看似简单就几个参数但每个参数背后都有讲究理解透了才能在故障转移时做到心里有数。4.1 sentinel.conf关键参数逐项拆解三个哨兵的配置大同小异先看一份完整配置然后逐个参数解释。# 哨兵配置文件 /data/redis/conf/sentinel.conf以node1为例 port 26379 daemonize yes pidfile /data/redis/run/redis-sentinel_26379.pid logfile /data/redis/logs/sentinel_26379.log dir /data/redis/data sentinel monitor mymaster 192.168.1.101 6379 2 sentinel down-after-milliseconds mymaster 5000 sentinel failover-timeout mymaster 15000 sentinel parallel-syncs mymaster 1sentinel monitor mymaster 192.168.1.101 6379 2是配置的核心。mymaster是监控主节点的自定义名称后面是主节点的IP、端口和quorum。这里quorum填2意思是至少要2个哨兵达成一致才判定主节点客观下线。前面说过推荐3个哨兵配quorum2因为2已经超过半数了同时3个哨兵即使挂1个还能正常工作。sentinel down-after-milliseconds mymaster 5000表示哨兵在5秒内没有收到主节点的有效响应就认为该节点进入主观下线状态。这个值不能设太小否则网络抖动会导致频繁判定故障触发不必要的切换也不能太大否则主节点真挂了系统要等很久才反应。一般建议3000到10000毫秒之间按实际网络质量调整。sentinel failover-timeout mymaster 15000是故障转移超时时间包括从节点被判定为客观下线后的等待时间、向从节点发起选举到完成切换的整个流程的超时限制。15秒是我比较常用的值如果机器性能差或者网络延迟高可以适当调到20秒或30秒。sentinel parallel-syncs mymaster 1表示故障转移完成后同时有几个从节点向新主节点发起数据同步。这里设1的目的是让从节点一个一个地去同步避免多个从节点同时全量同步把新主节点的带宽和CPU打满。如果从节点数量很多依次同步是最稳的方式。4.2 三个哨兵配置的差异点与统一点三个哨兵的配置大部分是相同的区别只在port、pidfile、logfile、dir这四个体现节点身份的文件路径参数上。比如node2的哨兵配置只需要在node1的配置基础上把以下几个关键项替换掉其余保持一致即可。# node2 /data/redis/conf/sentinel.conf 差异项 port 26379 pidfile /data/redis/run/redis-sentinel_26379.pid logfile /data/redis/logs/sentinel_26379.log dir /data/redis/data这里有个非常容易踩的坑哨兵启动后会自动改写sentinel.conf文件把所有已经发现的master、replica、sentinel信息都写进去。比如你在配置里写的sentinel monitor mymaster 192.168.1.101 6379 2运行一段时间后可能变成sentinel monitor mymaster 192.168.1.102 6379 2如果发生过故障转移新主节点IP会替换进去。所以千万不要在哨兵运行期间手动编辑这个文件否则你改完它又自动改回来或者配置被覆盖导致监控对象混乱。4.3 启动哨兵并确认集群视角启动哨兵很简单用redis-sentinel命令指定配置文件即可。三个节点都执行一遍。redis-sentinel /data/redis/conf/sentinel.conf启动完成后用redis-cli -p 26379连上任意一个哨兵执行信息查看命令。以下三个命令能展示哨兵视角下的完整集群拓扑。redis-cli -p 26379 sentinel master mymaster redis-cli -p 26379 sentinel replicas mymaster redis-cli -p 26379 sentinel sentinels mymastersentinel master mymaster会输出当前主节点的详细信息重点看num-slaves和num-other-sentinels两个字段分别表示从节点数量和除自己以外的哨兵数量。正常情况下num-slaves是2num-other-sentinels也是2。如果数字少了说明节点注册有问题需要回头检查对应节点配置和网络连通性。从哨兵视角确认集群状态这个动作很容易被忽略但它其实是一次全面的健康检查。如果这里显示的拓扑不完整后续故障转移大概率会出幺蛾子。5. 故障转移完整演练kill掉主节点会发生什么配置都搭好了不实际演练一次故障转移等于没验证过。这一步我要把主节点杀掉然后观察哨兵如何一步步完成主从切换的完整过程。5.1 模拟故障与观察节奏在node1上执行redis-cli -p 6379 debug sleep 60是模拟Redis卡死的常用方式但这里为了直接看到进程级别的故障用kill命令更直观。# 在node1上模拟主节点宕机 kill -9 $(cat /data/redis/run/redis_6379.pid)杀掉之后不要急着看结果先等十几秒钟让哨兵完成主观判断和客观确认。然后到node2或node3上看哨兵日志重点是/data/redis/logs/sentinel_26379.log这个文件。tail -n 50 /data/redis/logs/sentinel_26379.log日志会按时间顺序记录下整个过程大致包含以下几个关键事件第一个哨兵发现主节点没响应标记为sdownquorum达到2后标记为odown然后发起选举vote-for-leader选出一个从节点作为新主节点switch-master最后通知其他从节点执行replicaof指向新主节点。5.2 验证新主节点是否真的可用切换完成后第一步是确认192.168.1.102或192.168.1.103中的某一个成为了新主节点。用info replication在三个节点上分别看一下。redis-cli -h 192.168.1.102 -p 6379 info replication如果在node2上看到的role字段是master而node3上看到的master_host指向node2说明故障转移成功了。接下来验证数据完整性之前在主节点写入的hello键现在应该还能在新主节点上读到。redis-cli -h 192.168.1.102 -p 6379 get hello这里我有一个心得故障转移之后最好写一条新的数据然后看看它是不是被复制到了另一个从节点。这样能确认新主节点和新从节点的复制链路也是通的而不只是角色切换成功。5.3 老的“主节点”恢复后会发生什么把node1上的Redis进程重新启动观察它会自动变成什么角色。redis-server /data/redis/conf/redis.conf sleep 5 redis-cli -h 192.168.1.101 -p 6379 info replication正常情况下node1重启后会发现自己已经不是主节点了哨兵已经把它降级为从节点并自动执行replicaof指向新主节点。你会看到它的role字段变成slavemaster_host指向node2或node3。这个过程无需人工干预——旧主节点重启后自动归队整个集群恢复到健康状态。这就是哨兵最大的价值所在。6. 常见问题与排障记录实测中最容易翻车的几个坑搭建哨兵集群的过程基本就是把各种坑踩一遍的过程。下面这些问题我基本都遇到过有些在测试环境折腾了几个小时才想明白写出来帮你省点时间。6.1 主从复制一直显示down排查顺序是什么先看从节点日志/data/redis/logs/redis_6379.log会直接告诉你连不上的原因。常见的报错包括Master is down、Cant connect、DENIED Redis is running in protected mode。看到Cant connect就去检查网络和端口防火墙、安全组是否放行6379看到DENIED Redis is running in protected mode就去检查protected-mode是不是nobind是不是0.0.0.0。我个人的排查顺序是先日志、再网络、后配置这个顺序效率最高。6.2 哨兵日志出现sdown但没有odown正常吗非常正常。sdown是单个哨兵的主观判断——它自己觉得主节点挂了但还没有拉到足够的“同意票”所以不会触发故障转移。这种情况在生产环境可能出现的原因有两种一是网络卡顿导致个别哨兵对主节点请求超时二是down-after-milliseconds设得太小哨兵之间网络抖动就误判了。如果频繁出现sdown - odown - switch-master的循环多半是网络环境不好调大down-after-milliseconds到8000或10000毫秒能明显减少抖动带来的误切换。6.3 哨兵配置文件为什么变了改回去行不行monitor事件发生后哨兵会自动把发现的节点信息写进配置文件以便重启后恢复状态。很多人第一次看到sentinel.conf被改写以为是被黑或者崩溃了其实这是正常机制。千万不要在运行期间手动改sentinel.conf更不要改完又重启哨兵否则会用老配置覆盖新发现的状态引发混乱。如果需要调整参数比如改quorum用sentinel set命令在线修改或者停机维护时统一修改配置再一次性重启所有哨兵。6.4 故障转移后客户端连不上新主节点怎么办这是应用侧最常见的问题。老代码里硬编码了主节点的IP主节点一切换客户端还连老的IP自然就失败了。正确的做法是使用支持哨兵的客户端SDK比如Jedis的JedisSentinelPool、Lettuce的RedisClient它们会通过哨兵节点获取当前主节点地址switch-master消息推送给客户端后客户端自动更新连接池中的主节点。使用这类客户端时配置里填的是哨兵的IP和端口而不是Redis主节点的IP和端口。6.5 真的会发生脑裂吗怎么避免哨兵模式下脑裂通常发生在主节点和哨兵之间网络分区。可能出现的情况是主节点实际上活得好好的但哨兵之间无法访问它于是判定故障并提升了一个从节点为新主节点。等网络恢复后旧主节点发现自己不再是主会变成从节点并把数据同步到新主节点。如果旧主节点在分区期间接受了新的写入这部分数据在同步时会被覆盖造成丢失。解决思路有两层。第一层是合理设置down-after-milliseconds不要太敏感给网络抖动留出缓冲。第二层是在主节点上配置min-replicas-to-write和min-replicas-max-lag限制主节点在从节点失联时不再接受写入比如从节点少于1个且延迟超过10秒时拒绝写入这样即使发生分区丢失的数据窗口也会被压缩到很小。这个参数不能完全避免脑裂但能有效控制脑裂造成的数据丢失范围。6.6 哨兵本身挂了一个集群还能正常工作吗3个哨兵的架构挂1个哨兵集群依然能正常工作。因为quorum是2剩下2个哨兵还能达成一致故障转移照常触发。但如果哨兵挂了2个剩下1个哨兵无论怎么判定都无法达到quorum2故障转移会失效。这就是为什么生产环境至少部署3个哨兵——它能容忍一个哨兵节点的故障。如果你希望更稳可以部署5个哨兵quorum设为3这样能容忍2个哨兵节点故障。7. 从测试环境到生产环境还要注意这些细节测试环境搭通了离生产部署还有一段距离下面这几个点是我在生产上吃过的亏值得提前考虑。生产环境和测试环境最大的区别在于网络不确定性、配置规范性和监控完备性。7.1 密码认证场景下的配置方式生产环境没人敢不设密码。如果Redis开启了requirepass从节点和哨兵都需要额外配置认证信息。从节点的redis.conf要加一行masterauth哨兵的sentinel.conf要在monitor配置后面追加认证信息。# redis.conf 增加 masterauth masterauth YourStrongPassword # sentinel.conf 追加认证 sentinel auth-pass mymaster YourStrongPassword这里有个很隐蔽的坑如果你只设置了requirepass而没设置masterauth主从复制的连接会被拒绝哨兵也无法正常监控节点状态。我之前帮同事排过一个“哨兵一直报sdown”的问题最后发现就是masterauth漏了。7.2 选择合适的高可用组件哨兵还是Cluster哨兵解决的是主从模式下的高可用问题它负责故障转移但数据分片还是靠手动拆多个Redis实例。如果数据量非常大需要水平扩展可以考虑Redis Cluster。两者不是替代关系而是解决不同场景的问题。数据量可控、主要诉求是高可用选哨兵数据量大、需要自动分片和水平扩展选Cluster。很多团队的做法是先用哨兵模式把高可用做好等数据量上来后再平滑迁移到Cluster。7.3 如何快速验证生产环境哨兵配置是否合理新环境搭建完成后别急着把业务切上去。建议先做一次完整的故障演练从kill主节点开始记录切换耗时验证新主节点数据和复制状态再重启旧主节点观察归队情况。整个过程跑完没问题集群才算真正可用。切换耗时如果大于业务可接受的故障时间就要检查down-after-milliseconds和failover-timeout设置是否过大或者从节点同步是否需要优化。我的习惯是每个季度做一次演练顺便更新一下文档里的拓扑图和切换时间记录。这套方法看着简单但能在节点变更、机房网络调整后及时发现潜在问题比等到真出故障时再手忙脚乱强太多了。8. 写在最后哨兵集群搭建的几个核心心得按着上面这套流程从零搭建一个1主2从3哨兵的Redis高可用集群顺利的话一个小时以内就能完成。整个过程踩过的坑其实就那么几个我把它们总结成一句话版本主从复制不先验收就别上哨兵哨兵配置别在运行期间手动改订阅模式比轮询更适合客户端感知切换网络抖动是误判切换的最大来源down-after-milliseconds别设太小。个人体会最深的一点是哨兵集群搭完只是开始真正的难度在于持续运维。节点状态怎么看、日志怎么排查、切换时间怎么优化、故障演练怎么安排这些才是衡量一个Redis基础设施是否可靠的标准。建议你在自己电脑上用三台虚拟机或Docker容器完整演练一遍把日志里的每个关键词都看懂再把kill主节点这个动作重复几次直到你对整个切换流程的时序烂熟于心。最后分享一个小技巧运维巡检时直接把哨兵的状态查询命令写成脚本定时采集主节点IP、从节点列表、哨兵数量、最近一次切换时间一旦发现角色和预期不一致立刻报警。有了这套监控Redis哨兵集群才真正算得上“高可用”。
返回列表