路上,小胖问我:Redis 主从复制原理是怎样的?

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: 路上,小胖问我:Redis 主从复制原理是怎样的?

00 前言


我负责我司的报表系统,小胖是我小弟。随着业务量的增加,单实例顶不住,我就搭建了多个 Redis 实例,实现主从模式。


好学的小胖就问我啊,远哥,多实例之间的数据是怎么保持同步的呀?你教教我好不好嘛~


我拿起手中 82 年的开水抿了一口,跟小胖说:你先看这篇文章,学会了操作,我再给你讲讲原理吧。


https://juejin.cn/post/6844903650175746056#heading-0


老规矩,还是先上脑图:(PS:文末有我准备的大厂面试题


640.png


01 主从复制


Redis 的高可靠主要由两点保证,一是数据尽量少丢失,二是服务尽量少中断。持久化保证了第一点;而第二点则由 Redis 集群保证,Redis 的做法就是多实例保持数据同步。


1.1 读写分离


Redis 提供了主从库模式,以保证数据副本的一致,主从库之间采用的是读写分离的方式。


  1. 读操作:主库、从库都可以接收;


  1. 写操作:首先到主库执行,然后,主库将写操作同步给从库。


640.png


为什么要读写分离呢?


看看上图,如果所有库都可以写,那将会发生一个 key 在不同实例就有不同的值。比如上图对应的键 k1 在不同实例就有不同的 v1、v2、v3 值,这是绝对不能接受的。


有人说,,可以加锁呀


但是这会涉及到加锁、实例间协商是否完成修改等一堆操作,带来巨额的开销,Redis 以快著称,这也是不能接受的。


那咋办呀?读写分离咯


主从库模式采用读写分离,所有数据修改只会在主库进行。主库有最新数据,会同步给从库,这样,主从库的数据就是一致的。


问题就在同步了,主从库之间是怎么同步的呢?一起来探讨下


1.2 全量复制


当我们启动多个 Redis 实例的时候,它们相互之间就通过 replicaof(Redis 5.0 之前使用 slaveof)命令形成主库和从库的关系,之后会按照三个阶段完成数据的第一次同步。


比如现在有实例 1(127.0.0.1)和实例 2(127.0.0.2),在实例 2 执行 replicaof 后,实例 2 就变成实例 1 的从库啦。


replicaof  127.0.0.2  6379


建立关系之后,Redis 会进行第一次全量复制。过程如下:


640.png


第一步,主从库建立连接、协商同步的过程,主要是为全量复制做准备。


从库给主库发送 psync 命令,表示要进行数据同步,主库根据这个命令的参数来启动复制。psync 命令包含了主库的 runID 和复制进度 offset 两个参数


  • runID,是每个 Redis 实例启动时都会自动生成的一个随机 ID,用来唯一标记这个实例。当从库和主库第一次复制时,因为不知道主库的 runID,所以将 runID 设为 “?”。
  • offset,此时设为 -1,表示第一次复制。主库收到 psync 命令后,会用 FULLRESYNC 响应命令带上两个参数:主库 runID 和主库目前的复制进度 offset,返回给从库


FULLRESYNC 响应表示第一次复制采用的全量复制,也就是说,主库会把当前所有的数据都复制给从库。


第二步,主库执行 bgsave 命令,生成 RDB 文件,发送给从库。从库收到后,先清空自己的数据(避免主从不一致),在本地完成数据加载。


主库在将数据同步给从库的过程中,仍然可以正常接收请求。但是,这些请求中的写操作并没有记录到刚刚生成的 RDB 文件中。


为了保证主从一致性,主库会在内存中用 replication buffer 记录 RDB 文件生成后收到的所有写操作。


第三步,主库会把 replication buffer 中的修改操作发给从库,从库再重新执行这些操作。如此,主从就实现了同步。


1.3 主从级联分散压力


以上还有个问题:如果直接跟主库建立关系的从库非常多,那么主库会 fork 很多线程去生成 RDB 和 发送 RDB 文件,这将会造成主库阻塞。那咋办?


主从级联的模式就来了:选一个资源较多的实例作为级联的从库,作为叶子节点的从库执行以下命令将所选从库作为主库,这样就形成了级联关系。


replicaof  所选从库的IP 6379


640.png


如上图,主库就跟两个实例做主从关系,从库又跟另外的从库建立主从关系,类似于树结构。如此,主库便可减少压力。


就上图来说,主库原来要跟 4 个从库建立主从关系;加了级联之后,只需要建立两个主从关系,剩下的由某一个从库去承担。这颇有点父养子,子又养子的意思。


这个过程也称为基于长连接的命令传播,可以避免频繁建立连接的开销。


1.4 增量复制


细想一下,上面的主从复制还有问题:如果主从之间的网络断开了咋办?


其实 Redis 2.8 之前,主从断开了,做的是全量复制。但这种方式开销太大,已被淘汰。2.8 之后的 Redis 采用的是增量复制


增量复制依赖一个环形缓冲区 repl_backlog_buffer(只要有从库存在,就会有这个缓存区),主从断连后,主库会把断连期间的写操作命令,写入 repl_backlog_buffer 缓冲区。repl_backlog_buffer 是一个环形缓冲区,主库会记录自己写到的位置,从库则会记录自己已经读到的位置


640.png


如上图所示,还没断连时,主从指向同一个位置;主库写,从库读,一直往前走。突然,断连了,从库没法写、主库继续读


恢复连接后,从库发送 psync {runID}{offset} 告诉主库,自己上次读到哪。主库通过 offset 在 repl_backlog_buffer 中找到从库断开的位置,主从之间的偏移量就是增量复制需要同步的内容。比如上图的 put d e 和 put d f 两个操作。


把这部分增量数据复制到 repl_buffer 中,主库再发送给从库读入。


基于此增量复制的整个流程是这样的:


640.png


你可能也发现了?repl_backlog_buffer 是环形缓存区,如果从库断开时间太久,就有可能导致从库还未读取的操作被主库新写的操作覆盖了,这会导致主从库间的数据不一致。这该咋办呀?


连接恢复后,主库根据从库上次读到的 offset 位置判断是否被覆盖?如果是, 从库连上主库后也只能乖乖地进行一次全量同步


为了避免全量同步,可以通过参数 repl_backlog_size 设置 repl_backlog_buffer 的大小,把它弄大点。


计算公式是:缓冲空间大小 = 主库写入命令速度 * 操作大小 - 主从库间网络传输命令速度 * 操作大小


repl_backlog_size = 缓冲空间大小 * 2


这样一来,发生全量同步的概率就小了很多了。


02 总结


本文主要讲了 Redis 的主从模式为什么要读写分离?Redis 全量复制的流程以及原理;从库很多时,如何降低主库复制的压力?如果主从断开了,Redis 是怎么进行数据同步的?希望你看完能有所收获。


好啦,以上就是狗哥关于 Redis 主从复制的总结。感谢各技术社区大佬们的付出,尤其是极客时间,真的牛逼。如果说我看得更远,那是因为我站在你们的肩膀上。希望这篇文章对你有帮助,我们下篇文章见~

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
2月前
|
存储 缓存 NoSQL
蚂蚁金服P7私藏的Redis原理与实践内部笔记
Redis 是完全开源免费的,是一个高性能的key-value类型的内存数据库。整个数据库统统加载在内存当中进行操作,定期通过异步操作把数据库数据flush到硬盘上进行保存。因为是纯内存操作,Redis的性能非常出色,每秒可以处理超过 10万次读写操作,是已知性能最快的Key-Value DB。
58 1
|
3月前
|
NoSQL Java 测试技术
字节二面:Spring Boot Redis 可重入分布式锁实现原理?
字节二面:Spring Boot Redis 可重入分布式锁实现原理?
155 1
|
1月前
|
存储 缓存 Java
【Spring原理高级进阶】有Redis为啥不用?深入剖析 Spring Cache:缓存的工作原理、缓存注解的使用方法与最佳实践
【Spring原理高级进阶】有Redis为啥不用?深入剖析 Spring Cache:缓存的工作原理、缓存注解的使用方法与最佳实践
|
5天前
|
运维 NoSQL 算法
Java开发-深入理解Redis Cluster的工作原理
综上所述,Redis Cluster通过数据分片、节点发现、主从复制、数据迁移、故障检测和客户端路由等机制,实现了一个分布式的、高可用的Redis解决方案。它允许数据分布在多个节点上,提供了自动故障转移和读写分离的功能,适用于需要大规模、高性能、高可用性的应用场景。
15 0
|
18天前
|
存储 NoSQL Redis
作者推荐 |【Redis技术进阶之路】「原理系列开篇」揭秘高效存储模型与数据结构底层实现(SDS)(三)
作者推荐 |【Redis技术进阶之路】「原理系列开篇」揭秘高效存储模型与数据结构底层实现(SDS)
18 0
|
20天前
|
NoSQL 关系型数据库 MySQL
LAMP+Redis详解(一)——基本原理
LAMP+Redis详解(一)——基本原理
13 1
|
1月前
|
NoSQL Redis
[Redis]——主从同步原理(全量同步、增量同步)
[Redis]——主从同步原理(全量同步、增量同步)
|
1月前
|
存储 监控 NoSQL
Redis 架构深入:主从复制、哨兵到集群
大家好,我是小康,今天我们来聊下 Redis 的几种架构模式,包括主从复制、哨兵和集群模式。
Redis 架构深入:主从复制、哨兵到集群
|
1月前
|
消息中间件 存储 缓存
【Redis实战】有MQ为啥不用?用Redis作消息队列!?Redis作消息队列使用方法及底层原理高级进阶
【Redis实战】有MQ为啥不用?用Redis作消息队列!?Redis作消息队列使用方法及底层原理高级进阶
|
1月前
|
负载均衡 NoSQL 容灾