Redis 高可用 - 主从复制详解

本文讲解主从复制,也叫主从架构、读写分离。

主从复制

在你的 Redis 服务器只有一个“单枪匹马”时,会遇到几个大问题:

  1. 数据备份在哪里? - 服务器硬盘坏了,数据就全没了。
  2. 服务器宕机了怎么办? - 整个服务就瘫痪了,用户访问不了。
  3. 读的压力太大,CPU 累垮了怎么办? - 所有读写都压在一台机器上。

主从复制就是来解决这些问题的!它像这样安排工作:

角色职责比喻
主库数据,并同步给从库原始笔记本,所有新记录都写这里
从库数据,并同步主库的数据笔记本的复印件,供别人查阅

主从复制:主库写,从库读,分摊单 redis 节点的压力。

img

主从复制的作用主要包括:

  • 数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。
  • 故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余。
  • 负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务(即写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

全量复制的原理

你可以先看一下下面这张图,有个整体感知,接下来我再具体介绍。

img

  1. 打招呼,建立连接:从库对主库说:“你好,我要同步数据!”(发送 **PSYNC ? -1** 命令)。
  2. 主库打包全部数据:主库收到后,会说:“好,我准备把所有数据都给你!”(响应 **FULLRESYNC**)。然后主库会在后台执行一个 **BGSAVE** 命令,生成一个当前内存数据的快照文件(RDB 文件)。这就像把笔记本当前所有页面快速拍了一张照片。
  3. 发送数据 + 追补增量
    • 主库把快照(RDB 文件)发给从库。
    • 从库收到后,先把自己脑子里的旧数据清空,然后加载这张照片,瞬间和主库同步了。
    • 关键点:在拍照和传输照片的这段时间里,主库可没闲着,它还在接收新的写命令!这些新命令没法放进照片里,怎么办?主库会把它们临时记在一个叫 **replication buffer** 的缓冲区里
    • 照片发完后,主库会把缓冲区里积压的这些新命令,再一股脑儿发给从库。从库执行完这些命令,就和主库完全同步了。

第三个阶段同步的是主库在发送数据给从库的过程中,客户端持续像redis执行命令,这些命令也要在全量同步中传递过去,作为一个保存点。

增量复制

在 Redis 2.8 版本引入了增量复制。

  • 为什么会设计增量复制

现在从库和主库数据一致了。那之后主库来了新的写命令,难道每次都全量复制一遍吗?那也太蠢了!

同步数据过程中,网络抖了一下,断开了怎么办?

重连后,从库会对主库说:“我刚才掉线了,我记得我同步到哪个位置了(比如第 1000 条命令),请从那里继续给我吧。”

  • 原理

主库怎么知道“第 1000 条之后”的命令是什么呢?靠一个叫 **repl_backlog_buffer** 的环形缓冲区。

  • **repl_backlog_buffer**:主库上的一个环形队列,像一段循环磁带,记录着最近一段时间内的写命令。
  • **replication buffer**:主库为每个从库分配的客户端缓冲区,用于实际发送数据。

img

更深入理解

我们通过几个问题来深入理解主从复制。

主库如果关了持久化(RDB/AOF),自动重启后,从库数据会丢失吗?

会!而且非常危险!

想象一下:

  1. 主库(没开持久化)重启,内存空了。
  2. 从库们很忠诚,发现主库“空了”,为了和主库保持一致,也把自己清空了
  3. 数据瞬间蒸发!

所以,生产环境强烈建议主库一定要开启持久化!

为什么还会有从库的从库的设计?

有时候,主库压力太大,带很多从库也累。这时可以让一个从库当“二把手”,再带几个从库。

bash
复制代码
主库 -> 从库A -> 从库B -> 从库C

这样,主库只需要把数据同步给从库A,由A去同步给B和C,减轻了主库的负担。

img

为什么用 RDB 而不用 AOF 做全量复制?

简单说:快、小、省事!RDB 是二进制压缩数据,传输快,加载也快。AOF 是文本命令,文件大,一条条执行慢得要死。全量复制讲究的就是一个“快”字!

为什么还有无磁盘复制模式?

无磁盘复制,也叫盘内复制磁盘less复制,是指主从复制过程中,主库不再通过 RDB 文件这个中间介质,而是直接将内存中的数据序列化后,通过网络发送给从库, 整个过程磁盘不参与。

这种方式优点是很快,纯内存操作,可以全程不用 RDB ,缺点也明显,数据丢失再也找不回。

适用于:

  • 极致性能需求:在对数据丢失不敏感,但对同步速度要求极高的场景。比如,一个大型集群在做扩容,需要快速添加新节点时,用无盘复制可以大大缩短新节点上线的时间。
  • 临时从库:创建一些临时的、用于数据分析的从库,这些从库即使丢了数据也没关系。

读写分离及其中的问题

读写分离是一种架构模式,将数据库的写操作读操作路由到不同的节点。在 Redis 主从架构中,主库处理写,从库处理读

这种模式面临三大核心挑战:

  1. 主从复制延迟

定义:主库的数据变更异步同步到从库,存在一个时间窗口。在这个窗口内,主从数据是不一致的。

原因:网络传输延迟、从库执行命令速度慢、主库繁忙来不及发送等。

影响:用户可能读到旧数据,导致业务逻辑错误(如刚下单后查不到订单)。

  1. 从库数据不一致

定义:在存在多个从库的情况下,由于网络抖动或各从库的负载不同,导致不同从库在同一时刻的数据可能存在差异。

影响:用户的多次请求可能路由到不同从库,得到不同的结果,体验极差,甚至引发业务混乱。

  1. 主从切换的复杂性

定义:当主库故障时,系统需要自动或手动地将一个从库提升为新的主库,这个过程称为故障转移。

核心挑战:

  • 故障检测:如何快速、准确地判断主库真的挂了?
  • 选主:在多个从库中,如何选择一个数据最完整、最合适的作为新主库?(这通常需要哨兵 Sentinel 或 集群 Cluster 的介入)
  • 通知机制:如何让其他从库和所有客户端知道新的主库是谁,并去连接它?

如何缓解这些问题?

  • 针对延迟:优化网络,使用更快的机器,监控复制延迟,在关键业务上强制读主库。
  • 针对不一致:尽量让一个用户的请求固定路由到同一个从库,或使用一致性哈希等策略。
  • 针对切换:引入成熟的高可用组件,如 Redis Sentinel(自动监控、通知、故障转移)或 Redis Cluster(分片+高可用)。
0个评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
下载 APP