Redis 高可用 - 主从复制详解
本文讲解主从复制,也叫主从架构、读写分离。
主从复制
在你的 Redis 服务器只有一个“单枪匹马”时,会遇到几个大问题:
- 数据备份在哪里? - 服务器硬盘坏了,数据就全没了。
- 服务器宕机了怎么办? - 整个服务就瘫痪了,用户访问不了。
- 读的压力太大,CPU 累垮了怎么办? - 所有读写都压在一台机器上。
主从复制就是来解决这些问题的!它像这样安排工作:
| 角色 | 职责 | 比喻 |
|---|---|---|
| 主库 | 写数据,并同步给从库 | 原始笔记本,所有新记录都写这里 |
| 从库 | 读数据,并同步主库的数据 | 笔记本的复印件,供别人查阅 |
主从复制:主库写,从库读,分摊单 redis 节点的压力。

主从复制的作用主要包括:
- 数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。
- 故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余。
- 负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务(即写Redis数据时应用连接主节点,读Redis数据时应用连接从节点),分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。
- 高可用基石:除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用的基础。
主从复制原理
全量复制和增量复制。
全量复制
首先确立主从关系
例如,现在有实例 1(ip:172.16.19.3)和实例 2(ip:172.16.19.5),我们在实例 2 上执行以下这个命令后,实例 2 就变成了实例 1 的从库,并从实例 1 上复制数据:
▼bash复制代码replicaof 172.16.19.3 6379
全量复制的原理
你可以先看一下下面这张图,有个整体感知,接下来我再具体介绍。

- 打招呼,建立连接:从库对主库说:“你好,我要同步数据!”(发送
**PSYNC ? -1**命令)。 - 主库打包全部数据:主库收到后,会说:“好,我准备把所有数据都给你!”(响应
**FULLRESYNC**)。然后主库会在后台执行一个**BGSAVE**命令,生成一个当前内存数据的快照文件(RDB 文件)。这就像把笔记本当前所有页面快速拍了一张照片。 - 发送数据 + 追补增量:
-
- 主库把快照(RDB 文件)发给从库。
- 从库收到后,先把自己脑子里的旧数据清空,然后加载这张照片,瞬间和主库同步了。
- 关键点:在拍照和传输照片的这段时间里,主库可没闲着,它还在接收新的写命令!这些新命令没法放进照片里,怎么办?主库会把它们临时记在一个叫
**replication buffer**的缓冲区里。 - 照片发完后,主库会把缓冲区里积压的这些新命令,再一股脑儿发给从库。从库执行完这些命令,就和主库完全同步了。
第三个阶段同步的是主库在发送数据给从库的过程中,客户端持续像redis执行命令,这些命令也要在全量同步中传递过去,作为一个保存点。
增量复制
在 Redis 2.8 版本引入了增量复制。
- 为什么会设计增量复制?
现在从库和主库数据一致了。那之后主库来了新的写命令,难道每次都全量复制一遍吗?那也太蠢了!
同步数据过程中,网络抖了一下,断开了怎么办?
重连后,从库会对主库说:“我刚才掉线了,我记得我同步到哪个位置了(比如第 1000 条命令),请从那里继续给我吧。”
- 原理
主库怎么知道“第 1000 条之后”的命令是什么呢?靠一个叫 **repl_backlog_buffer** 的环形缓冲区。
**repl_backlog_buffer**:主库上的一个环形队列,像一段循环磁带,记录着最近一段时间内的写命令。**replication buffer**:主库为每个从库分配的客户端缓冲区,用于实际发送数据。

更深入理解
我们通过几个问题来深入理解主从复制。
主库如果关了持久化(RDB/AOF),自动重启后,从库数据会丢失吗?
会!而且非常危险!
想象一下:
- 主库(没开持久化)重启,内存空了。
- 从库们很忠诚,发现主库“空了”,为了和主库保持一致,也把自己清空了。
- 数据瞬间蒸发!
所以,生产环境强烈建议主库一定要开启持久化!
为什么还会有从库的从库的设计?
有时候,主库压力太大,带很多从库也累。这时可以让一个从库当“二把手”,再带几个从库。
▼bash复制代码主库 -> 从库A -> 从库B -> 从库C
这样,主库只需要把数据同步给从库A,由A去同步给B和C,减轻了主库的负担。

为什么用 RDB 而不用 AOF 做全量复制?
简单说:快、小、省事!RDB 是二进制压缩数据,传输快,加载也快。AOF 是文本命令,文件大,一条条执行慢得要死。全量复制讲究的就是一个“快”字!
为什么还有无磁盘复制模式?
无磁盘复制,也叫盘内复制或磁盘less复制,是指主从复制过程中,主库不再通过 RDB 文件这个中间介质,而是直接将内存中的数据序列化后,通过网络发送给从库, 整个过程磁盘不参与。
这种方式优点是很快,纯内存操作,可以全程不用 RDB ,缺点也明显,数据丢失再也找不回。
适用于:
- 极致性能需求:在对数据丢失不敏感,但对同步速度要求极高的场景。比如,一个大型集群在做扩容,需要快速添加新节点时,用无盘复制可以大大缩短新节点上线的时间。
- 临时从库:创建一些临时的、用于数据分析的从库,这些从库即使丢了数据也没关系。
读写分离及其中的问题
读写分离是一种架构模式,将数据库的写操作和读操作路由到不同的节点。在 Redis 主从架构中,主库处理写,从库处理读。
这种模式面临三大核心挑战:
- 主从复制延迟
定义:主库的数据变更异步同步到从库,存在一个时间窗口。在这个窗口内,主从数据是不一致的。
原因:网络传输延迟、从库执行命令速度慢、主库繁忙来不及发送等。
影响:用户可能读到旧数据,导致业务逻辑错误(如刚下单后查不到订单)。
- 从库数据不一致
定义:在存在多个从库的情况下,由于网络抖动或各从库的负载不同,导致不同从库在同一时刻的数据可能存在差异。
影响:用户的多次请求可能路由到不同从库,得到不同的结果,体验极差,甚至引发业务混乱。
- 主从切换的复杂性
定义:当主库故障时,系统需要自动或手动地将一个从库提升为新的主库,这个过程称为故障转移。
核心挑战:
- 故障检测:如何快速、准确地判断主库真的挂了?
- 选主:在多个从库中,如何选择一个数据最完整、最合适的作为新主库?(这通常需要哨兵 Sentinel 或 集群 Cluster 的介入)
- 通知机制:如何让其他从库和所有客户端知道新的主库是谁,并去连接它?
如何缓解这些问题?
- 针对延迟:优化网络,使用更快的机器,监控复制延迟,在关键业务上强制读主库。
- 针对不一致:尽量让一个用户的请求固定路由到同一个从库,或使用一致性哈希等策略。
- 针对切换:引入成熟的高可用组件,如 Redis Sentinel(自动监控、通知、故障转移)或 Redis Cluster(分片+高可用)。
