type
Post
status
Published
date
Dec 2, 2025
slug
redis2
summary
tags
技术探索
category
icon
password
很多人学 Redis,一上来就会背:
Redis 是一个基于内存的 key-value 数据库,性能很高。
这句话当然没错。
但在真实业务里,Redis 光“快”是不够的。
因为 Redis 一旦被放到线上系统里,马上就会遇到几个非常现实的问题:
如果 Redis 挂了怎么办?如果 Redis 数据丢了怎么办?如果一个 Redis 扛不住读流量怎么办?如果主节点故障了,业务怎么自动恢复?
这就引出了 Redis 高可用架构的演化。
Redis高可用到底是什么?
Redis 高可用,是在 Redis 节点故障时,系统能够尽快发现故障、自动完成主从切换,并让客户端恢复访问,把故障影响控制在较小范围内。
我们从最简单的单机 Redis 开始看。
一、最开始:单机 Redis
最简单的 Redis 部署方式,就是业务服务直接连接一个 Redis 实例。
这种方式很好理解。
业务服务把热点数据写到 Redis,查询时优先查 Redis,查不到再回源数据库。
比如商品详情、用户信息、配置数据、验证码、登录态,都可以放在 Redis 里。
但是单机 Redis 最大的问题也很明显:
Redis 一旦挂了,整个缓存层就不可用了。
如果业务只是把 Redis 当普通缓存,Redis 挂了以后还能回源数据库,那系统可能只是变慢。
但如果业务强依赖 Redis,比如分布式锁、限流、登录态、验证码、库存预扣等场景,一旦 Redis 不可用,业务可能直接失败。
除此之外,单机 Redis 还有两个限制。
第一,读写能力受限于单个 Redis 实例。
虽然 Redis 很快,但它毕竟还是一个进程,CPU、内存、网络都有上限。
第二,数据容量受限于单机内存。
Redis 是内存数据库,如果所有数据都堆在一个实例里,数据量越来越大,迟早会碰到单机内存瓶颈。
所以,单机 Redis 适合入门和小规模场景,但不适合直接承载高可用要求比较高的线上核心业务。
二、先区分两个概念:高可用不等于持久化
讲 Redis 高可用时,很多初学者容易把两个问题混在一起:
Redis 挂了怎么办?Redis 数据丢了怎么办?
这两个问题有关联,但不是一回事。
Redis 的可靠性可以拆成两层来看。
第一层是副本冗余。
也就是通过主从复制,把主节点的数据复制到其他 Redis 实例上。
这样主节点挂了以后,从节点上还有一份数据副本,可以作为故障恢复的基础。
第二层是本地持久化。
也就是通过 RDB、AOF 或混合持久化,把内存数据落到磁盘上。
这样 Redis 进程重启或者机器重启之后,数据可以从磁盘恢复。
简单来说:
主从复制解决的是“节点挂了有没有副本接管”;RDB/AOF 解决的是“Redis 重启后能不能恢复数据”。
所以,高可用和持久化不是一回事。
只做主从复制,不代表数据绝对不丢。
只做持久化,也不代表 Redis 节点故障后业务能自动恢复。
线上 Redis一般会把这两类能力结合起来使用。
三、第一步演化:主从复制
既然一个 Redis 不够稳,那很自然的想法就是:
能不能多加几个 Redis?
于是就有了 Redis 主从复制。
在主从模式里,Redis 节点分成两类:
主节点负责写入;从节点复制主节点的数据,通常用于读取或故障恢复。
这样做有两个好处。
第一个好处是:提高读能力。
如果读请求很多,可以把一部分读请求分发到从节点,减轻主节点压力。
第二个好处是:提高数据副本可用性。
主节点的数据会复制到从节点。这样主节点故障时,从节点上通常还保留着一份较新的数据副本,可以作为恢复基础。
注意,这里我说的是“较新的数据副本”,而不是“完全一致的数据副本”。
因为 Redis 主从复制默认是异步复制。
四、主从复制能不能保证数据不丢?
这是面试里非常容易被追问的问题。
答案是:
不能保证绝对不丢。
因为 Redis 主从复制通常是异步的。
客户端写入主 Redis 后,主节点会先返回写入成功,然后再把写命令同步给从节点。
如果这时候主节点突然宕机,而这部分写命令还没有来得及同步到从节点,那么 Sentinel 后面即使把某个从节点提升为新主,这部分数据也可能已经丢了。
流程大概是这样:
所以,主从复制提升的是可用性和副本冗余,但不等于强一致。
这也是 Redis 高可用架构里非常重要的边界:
Redis Sentinel 可以减少故障影响时间,但不能保证主节点宕机时数据零丢失。
生产环境中可以通过一些配置降低风险,比如要求主节点至少有一定数量的从节点处于正常复制状态,否则拒绝写入。
但这类配置只能降低风险,不能把 Redis 变成真正的强一致数据库。
五、读从节点也有代价:主从延迟
主从复制还有一个常见用途:
读写分离。
写请求打到主节点,读请求打到从节点。
这听起来很美好,但也有一个副作用:
从节点的数据可能比主节点慢一点。
因为主从复制是异步的,所以主节点刚写完的数据,从节点不一定马上就有。
比如用户刚修改了昵称,写入了主 Redis,下一秒业务又从从 Redis 读取用户信息,就可能读到旧昵称。
所以,不是所有读请求都适合走从节点。
比较适合读从节点的场景是:
商品详情、配置数据、排行榜缓存、热点内容缓存。
这些场景通常能接受短暂的旧数据。
不适合简单读从节点的场景是:
刚写完马上读的用户状态、库存扣减结果、支付状态、权限状态。
这些场景对一致性更敏感,不能只为了分担读流量就盲目读从库。
主从复制可以做读扩展,但读扩展会带来主从延迟问题,需要根据业务一致性要求决定哪些读可以走从节点。
六、主从节点不能部署在同一台机器上
很多初学者一听主从复制,就觉得:
那我在一台服务器上启动三个 Redis 进程,不就高可用了?
这不是真正的高可用。
因为如果这台服务器宕机,主 Redis 和从 Redis 会一起挂掉。
所以,主从复制的正确姿势一般是:
主节点和从节点部署在不同服务器上。
这样即使某台机器宕机,其他机器上的 Redis 实例仍然可以继续工作。
高可用架构的本质是要避免单机、单进程、单机房、单链路带来的单点风险。
七、从节点是怎么同步数据的?
主从复制听起来简单,但有一个关键问题:
新增一个从节点时,它怎么快速拿到主节点上的所有数据?
假设主 Redis 已经运行了很久,里面有大量 key-value 数据。
这时候你新加一个从 Redis,它不可能凭空拥有主节点的数据。
所以 Redis 需要先做一次同步。
同步主要分两种:
全量同步;增量同步,也叫部分重同步。
先看全量同步。
大致流程是这样的:
主节点会生成一份 RDB 快照文件,然后把这个文件发送给从节点。
从节点拿到 RDB 文件后,会把里面的数据加载到内存中。
这样,从节点就拥有了主节点某一时刻的全量数据。
但这里有一个细节。
主节点在生成 RDB 文件期间,并不会停止对外服务。
也就是说,在 RDB 生成和传输过程中,主 Redis 可能还在处理新的写请求。
那这些新增写操作怎么办?
Redis 会把这期间的写命令缓存下来,等从节点加载完 RDB 之后,再把这些写命令同步给从节点。
这样从节点才能追上主节点的数据进度。
八、全量同步太重,所以还需要增量复制
全量同步虽然能解决从节点初始化的问题,但它很重。
因为生成 RDB、传输 RDB、加载 RDB,都会消耗 CPU、磁盘、网络和内存资源。
如果每次主从之间网络闪断一下,都重新做全量同步,那 Redis 很容易被拖垮。
所以 Redis 还需要一种更轻量的方式:
增量复制。
Redis 2.8 之后通过 PSYNC 支持部分重同步。
主从之间会维护几个关键信息:
replication ID;复制偏移量 offset;复制积压缓冲区 repl backlog。
可以简单理解为:
主节点知道自己当前写到了哪里;从节点知道自己已经同步到了哪里;主节点会在复制积压缓冲区里保留最近一段时间的写命令。
当从节点短暂断线后重新连回来,它会告诉主节点:
我之前复制到哪个 replication ID、哪个 offset 了。
主节点会判断:
你要补的那段数据,我的 repl backlog 里还有没有?
如果还有,就可以做增量同步,只补发缺失的写命令。
但如果从节点断线太久,落后的数据已经被复制积压缓冲区覆盖了,那就没办法增量同步,只能重新走全量同步。
所以这里有一个重要结论:
Redis 主从复制不是每次都全量同步,而是优先尝试部分重同步;只有条件不满足时,才会退回全量同步。
这也是回答 Redis 主从复制时很关键的专业点。
九、主从复制解决了副本问题,但没解决自动切换
主从模式看起来已经不错了。
有主节点,有从节点。
主节点负责写,从节点负责读。
但这里还有一个非常关键的问题:
如果主节点挂了,谁来接管写请求?
在普通主从模式下,主节点挂了以后,从节点并不会自动变成主节点。
也就是说,从节点虽然有数据,但是它默认还是从节点。
这时候如果没人处理,系统就会出现:
读请求可能还能走从节点;写请求基本不可用。
当然,你可以人工处理。
比如运维人员登录机器,把某个从节点手动提升为主节点,再修改业务连接地址。
但人工处理有几个问题。
第一,响应慢。
故障发生后,人不一定马上发现。
第二,容易出错。
到底选哪个从节点当新主?
哪个从节点数据最新?
切换后其他从节点怎么重新挂到新主上?
客户端连接地址怎么更新?
这些都需要处理。
第三,不适合线上高可用场景。
高可用系统不能依赖人肉救火。
所以,Redis 还需要一个自动监控和自动故障转移的机制。
这就是 Redis Sentinel,也就是哨兵模式。
十、为什么不能只靠 Keepalived?
有些人可能会想到:
既然要做高可用,能不能用 Keepalived 这种通用高可用组件?
Keepalived 确实可以做主机级别、进程级别的高可用,比如检测进程是否存活、机器是否宕机、VIP 是否漂移。
但 Redis 高可用不只是判断一个进程还活不活。
Redis 还需要判断:
主节点是否真的不可用?哪个从节点数据最新?哪个从节点可以被提升为主节点?故障转移后,其他从节点应该跟随谁?客户端应该如何发现新的主节点?旧主恢复后应该怎么处理?
这些都是 Redis 内部语义。
通用高可用工具并不天然理解 Redis 的复制状态、复制偏移量、主从关系和故障转移流程。
所以 Redis 自己提供了一套更适合自身架构的高可用机制:
Redis Sentinel。
十一、哨兵是什么?
Sentinel 可以理解为运行在特殊模式下的 Redis 进程。
它负责:
监控 Redis 主从节点;判断主节点是否故障;在主节点故障后自动选主;完成主从切换;向客户端提供当前主节点发现能力。
架构大概是这样:
哨兵会定期向主节点和从节点发送 PING 命令。
如果某个 Redis 节点长时间没有响应,哨兵就会认为它可能下线了。
但注意,是“可能”。
因为单个哨兵也可能误判。
所以 Sentinel 里有两个非常重要的概念:
主观下线;客观下线。
十二、主观下线和客观下线
一个哨兵发现主节点没响应,只能说明:
在这个哨兵看来,主节点可能挂了。
这叫主观下线,也就是 Subjective Down,简称 SDOWN。
但单个哨兵可能误判。
比如哨兵和主节点之间网络抖动,主节点本身其实没问题。
如果只靠一个哨兵做决定,就可能发生错误切换。
所以 Redis Sentinel 通常会部署多个哨兵。
当多个哨兵都认为主节点不可用,并且达到配置的 quorum(法定人数) 阈值时,才会认为主节点进入客观下线,也就是 Objective Down,简称 ODOWN。
这一步很关键。
它降低了单个哨兵误判导致错误故障转移的概率。
但确认客观下线之后,也不是所有 Sentinel 一起冲上去切主。
它们还需要做一件事:
选出一个 leader Sentinel。
十三、Sentinel 故障转移不只需要达到 quorum,还需要 leader 选举
多个 Sentinel 都监控同一个主从集群。
当 master 被判断为客观下线后,如果所有 Sentinel 都同时去执行故障转移,就可能造成混乱。
所以 Sentinel 之间会先选出一个 leader。
由这个 leader Sentinel 负责执行后续的故障转移流程。
完整流程可以概括为:
画成图就是这样:
十四、主节点挂了以后,哨兵怎么选新主?
当主节点被确认客观下线,并且 Sentinel 选出了 leader 之后,leader Sentinel 会从从节点里选一个出来,提升为新的主节点。
问题是:
多个从节点里,应该选谁?
Sentinel 通常会先过滤掉一些不适合的从节点,比如:
已经下线的从节点;长时间没有和主节点正常通信的从节点;配置为不允许晋升的从节点;数据状态明显落后的从节点。
然后再根据规则排序。
常见判断因素包括:
replica-priority;复制偏移量 offset;run ID。
这里有一个容易说错的细节:
replica-priority数值越小,优先级越高;如果配置为 0,则这个从节点不会被 Sentinel 提升为 master。
如果两个从节点的优先级一样,那么通常复制偏移量越大的从节点越优先。
因为 offset 越大,通常说明这个从节点同步到的数据越新。
如果优先级和 offset 都一样,再根据 run ID 等信息做稳定选择。
选出新主后,leader Sentinel 会让这个从节点执行:
这个命令的意思是:
不再复制别人,自己变成主节点。
然后 Sentinel 会让其他从节点改为复制这个新的 master。
最终,主从关系完成重建。
十五、用一个故障案例串起来:主 Redis 所在机器宕机后发生了什么?
假设现在有一个商品服务,依赖 Redis 缓存商品详情。
Redis 部署方式是:
1 个 master;2 个 slave;3 个 Sentinel。
某天,master Redis 所在机器突然宕机。
接下来大致会发生这些事情。
T1:Sentinel 发现 master PING 不通。
每个 Sentinel 都会周期性检测 Redis 节点状态。
某个 Sentinel 发现 master 在指定时间内没有正常响应,于是把 master 标记为主观下线。
T2:多个 Sentinel 交换判断结果。
一个 Sentinel 说 master 挂了还不够。
它会询问其他 Sentinel:
你们觉得 master 还活着吗?
当认为 master 下线的 Sentinel 数量达到 quorum,master 被标记为客观下线。
T3:Sentinel 之间选举 leader。
既然要故障转移,就必须有一个 Sentinel 负责执行切换。
多个 Sentinel 会选出一个 leader Sentinel。
T4:leader Sentinel 选择新 master。
leader Sentinel 会从 slave 中筛选候选节点。
它会优先选择健康、复制偏移量较新、优先级更合适的 slave。
T5:slave 晋升为新 master。
被选中的 slave 执行
SLAVEOF NO ONE,成为新的 master。T6:其他 slave 改为复制新 master。
原来的其他 slave 会被重新配置,开始复制新的 master。
T7:客户端重新发现新 master。
支持 Sentinel 的 Redis 客户端会从 Sentinel 获取新的 master 地址,重建连接,然后恢复写入。
整个流程的目标就是:
master 挂掉以后,不需要人手动登录机器切主,Redis 集群能够自动完成故障发现、选主和主从关系重建。
十六、客户端为什么不能写死 Redis 地址?
真正在线上,服务端切换成功还不够。
业务客户端也要知道:
新 master 是谁?
如果业务代码里直接写死了旧 master 的 IP 和端口,那么 Sentinel 即使已经选出了新 master,业务服务还是可能继续连接旧 master。
这时候故障转移完成了,但业务仍然不可用。
所以在 Sentinel 模式下,客户端不应该写死某个 Redis 实例地址,而应该连接 Sentinel。
更准确地说:
Sentinel 维护当前 master 信息;客户端通过 Sentinel 查询当前 master 地址;支持 Sentinel 的 Redis 客户端会在故障转移后刷新 master 地址,并重建连接。
架构大概是这样:
故障转移之后:
这也是 Redis Sentinel 能否在线上发挥作用的关键:
Sentinel 完成的是服务端主从切换;客户端必须具备 Sentinel 主节点发现能力,业务才能自动恢复。
十七、为什么哨兵也要部署多个?
如果只部署一个哨兵,会出现新的单点问题。
假设只有一个 Sentinel。
它如果挂了,就没人监控 Redis 主从集群。
它如果误判,也可能导致错误切换。
所以生产环境里,Sentinel 通常也要部署成集群。
多个哨兵之间会互相通信,共同判断主节点状态。
当主节点疑似故障时,不是一个哨兵说了算,而是多个哨兵达成一定共识后,才会触发故障转移。
这就是哨兵集群存在的意义。
它是为了让故障判断和故障转移更加可靠。
十八、哨兵模式解决了什么?没解决什么?
到这里,Redis 架构已经从单机演化到了主从复制,再演化到了哨兵模式。
我们可以总结一下。
主从复制解决的是:
数据副本问题;读能力扩展问题;单个 Redis 节点故障后的数据恢复基础。
Sentinel 解决的是:
主节点故障检测;客观下线判断;Sentinel leader 选举;自动选主;自动故障转移;客户端主节点发现。
但是 Sentinel 不是万能的。
它仍然有几个明显边界。
第一,不能保证数据零丢失。
因为 Redis 主从复制通常是异步复制。
主节点宕机前尚未复制到从节点的写入,可能会丢失。
第二,不能解决主从延迟问题。
从节点可以分担读请求,但可能读到旧数据。
第三,不能解决单主写入瓶颈。
Sentinel 模式下,写请求仍然主要落到一个 master 上。
第四,不能解决容量分片问题。
主从节点保存的是同一份全量数据。
如果 master 有 100GB 数据,那么 slave 通常也要保存 100GB 数据。
从节点是在保存副本。
所以 Sentinel 解决的是高可用故障转移问题,不是水平扩容问题。
如果数据量继续变大,或者写请求压力继续升高,就需要进一步演化到 Redis Cluster。
十九、从单机到 Cluster:Redis 架构演化主线
Redis 高可用不是一上来就变复杂的,而是被业务问题一步步推出来的。
单机 Redis 解决了缓存性能问题,但有单点风险。
主从复制解决了副本和读扩展问题,但主节点故障后不能自动切换。
Sentinel 解决了自动监控、自动选主和自动故障转移问题,但仍然没有解决数据分片和写入扩展问题。
Redis Cluster 则进一步通过分片机制,把数据分散到多个 master 上,从而解决更大规模的数据容量和写入压力问题。
这条演化路径可以总结成一句话:
单机 Redis 解决性能问题,主从复制解决副本问题,Sentinel 解决故障转移问题,Redis Cluster 进一步解决分片扩容问题。
二十、你对Redis高可用有哪些了解?
更好的回答方式是按架构演化来讲:
最开始单机 Redis 虽然性能高,但存在单点故障。为了解决单点风险和读扩展,可以引入主从复制,让 master 负责写,slave 复制数据并承担读请求。但主从复制默认是异步复制,所以不能保证数据强一致,主节点故障时可能丢失少量未同步的数据;同时读 slave 也可能遇到主从延迟。主从复制还有一个问题:master 挂了以后 slave 不会自动变成 master,所以需要 Sentinel。Sentinel 会监控主从节点,通过主观下线、客观下线、leader 选举、slave 晋升等流程完成自动故障转移。但客户端也必须支持 Sentinel 主节点发现,不能写死 master 地址,否则服务端切换成功,业务也不一定能自动恢复。Sentinel 解决的是故障转移,如果数据量和写压力继续增大,就需要 Redis Cluster。
这个回答的层次会比单纯罗列概念高很多。
因为你讲清楚了:
为什么需要这个架构;它解决了什么问题;它还有什么边界;下一步为什么继续演化。
这才是真正理解 Redis 高可用的表达方式。
总结
Redis 高可用架构的演化,本质上是业务问题不断推动出来的。
单机 Redis 很快,但怕挂。
主从复制增加了数据副本,也可以分担读请求,但默认异步复制,存在数据丢失和主从延迟风险。
Sentinel 解决了主节点故障后的自动发现、自动选主和自动切换问题,但它依然不能解决强一致、写扩展和容量分片问题。
所以,Redis 高可用不是一个单独组件能解决的事情,而是一套组合能力:
主从复制提供副本基础;持久化提供重启恢复能力;Sentinel 提供自动故障转移;客户端 Sentinel 支持提供主节点发现;Redis Cluster 提供更大规模下的数据分片能力。
看完,你能回答出这些问题了吗?
单机为什么不够?主从解决了什么?主从为什么还不够?Sentinel 如何完成故障转移?Sentinel 又解决不了什么?
分享
