做个高可用的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哨兵。节点角色分配如下表。
| 节点 | IP | Redis角色 | 哨兵角色 | Redis端口 | 哨兵端口 |
|---|---|---|---|---|---|
| node1 | 192.168.1.101 | 主节点(master) | 哨兵1 | 6379 | 26379 |
| node2 | 192.168.1.102 | 从节点(replica) | 哨兵2 | 6379 | 26379 |
| node3 | 192.168.1.103 | 从节点(replica) | 哨兵3 | 6379 | 26379 |
2.1 Redis安装与目录结构规划
Redis版本这里以6.0.x或7.0.x为例,需要说明的是,6.0之前的版本主从复制的配置项叫slaveof,6.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/logs,PID文件放/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.conf(node2和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 firewalld,Ubuntu系是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个哨兵配quorum=2,因为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是2,num-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日志会按时间顺序记录下整个过程,大致包含以下几个关键事件:第一个哨兵发现主节点没响应,标记为sdown;quorum达到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字段变成slave,master_host指向node2或node3。这个过程无需人工干预——旧主节点重启后自动归队,整个集群恢复到健康状态。这就是哨兵最大的价值所在。
6. 常见问题与排障记录:实测中最容易翻车的几个坑
搭建哨兵集群的过程,基本就是把各种坑踩一遍的过程。下面这些问题我基本都遇到过,有些在测试环境折腾了几个小时才想明白,写出来帮你省点时间。
6.1 主从复制一直显示down,排查顺序是什么
先看从节点日志,/data/redis/logs/redis_6379.log会直接告诉你连不上的原因。常见的报错包括Master is down、Can't connect、DENIED Redis is running in protected mode。看到Can't connect就去检查网络和端口,防火墙、安全组是否放行6379;看到DENIED Redis is running in protected mode就去检查protected-mode是不是no,bind是不是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个哨兵无论怎么判定都无法达到quorum=2,故障转移会失效。这就是为什么生产环境至少部署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哨兵集群才真正算得上“高可用”。