一文吃透Redis主从复制的原理

news2024/9/30 13:33:06

1. 引言

之前我们聊过 Redis 的数据结构底层原理和持久化机制,这期我们来聊 Redis 的高可用主题。

时光穿梭机:

  • Redis持久化都说不明白?那今天先到这吧~
  • Redis数据结构的底层原理

众所周知,一个数据库系统想要实现高可用,主要从以下两个方面来考虑:

  1. 保证数据安全不丢失
  2. 系统可以正常提供服务

而 Redis 作为一个提供高效缓存服务的数据库,也不例外。

上期我们提到的 Redis 持久化策略,其实就是为了减少服务宕机后数据丢失,以及快速恢复数据,也算是支持高可用的一种实现。

除此之外,Redis 还提供了其它几种方式来保证系统高可用,业务中最常用的莫过于主从同步(也称作主从复制)、Sentinel 哨兵机制以及 Cluster 集群。

同时,这也是面试中出现频率最高的几个主题,这期我们先来讲讲 Redis 的主从复制。

2. 主从复制简介

Redis 同时支持主从复制和读写分离:一个 Redis 实例作为主节点 Master,负责写操作。其它实例(可能有 1 或多个)作为从节点 Slave,负责复制主节点的数据。

2.1 架构组件

图片

主节点Master

数据更新:Master 负责处理所有的写操作,包括写入、更新和删除等。

数据同步:写操作在 Master 上执行,然后 Master 将写操作的结果同步到所有从节点 Slave 上。

从节点Slave

数据读取:Slave 负责处理读操作,例如获取数据、查询等。

数据同步:Slave 从 Master 复制数据,并在本地保存一份与主节点相同的数据副本。

2.2 为什么要读写分离

1)防止并发

从上图我们可以看出,数据是由主节点向从节点单向复制的,如果主、从节点都可以写入数据的话,那么数据的一致性如何保证呢?

有聪明的小伙伴可能已经想到了,那就是加锁!

但是主、从节点分布在不同的服务器上,数据跨节点同步时又会出现分布式一致性的问题。而在高频并发的场景下,解决加锁后往往又会带来其它的分布式问题,例如写入效率低、吞吐量大幅下降等。

而对于 Redis 这样一个高效缓存数据库来说,性能降低是难以忍受的,所以加锁不是一个优秀的方案。

那如果不加锁,使用最终一致性方式呢?

这样 Redis 在主、从库读到的数据又可能会不一致,带来业务上的挑战,用户也是难以接受的。

业务为用户服务,技术为业务服务。

所以,为了权衡数据的并发问题和用户体验,我们只允许在主节点上写入数据,从节点上读取数据。

不理解分布式一致性的同学可以看我之前的这篇文章:深入浅出:分布式、CAP和BASE理论

2)易于扩展

我们都知道,大部分使用 Redis 的业务都是读多写少的。所以,我们可以根据业务量的规模来确定挂载几个从节点 Slave,当缓存数据增大时,我们可以很方便的扩展从节点的数量,实现弹性扩展。

同时,读写分离还可以实现数据备份和负载均衡,从而提高可靠性和性能。

3)高可用保障

不仅如此,Redis 还可以手动切换主从节点,来做故障隔离和恢复。这样,无论主节点或者从节点宕机,其他节点依然可以保证服务的正常运行。

3. 主从复制实现

3.1 开启主从复制

要开启主从复制,我们需要用到 replicaof 命令。

当我们确定好主节点的 IP 地址和端口号,在从库执行 replicaof <masterIP> <masterPort> 这个命令,就可以开启主从复制。

注意,在 Redis5.0 之前,该命令为 slaveof

开启主从复制后,应用层采用读写分离,所有的写操作在主节点进行,所有读操作在从节点进行。

主从节点会保持数据的最终一致性:主库更新数据后,会同步给从库。

3.2 主从复制过程

那主从库同步什么时候开始和结束呢?

是一次性传输还是分批次写入?Redis 主从节点在同步过程中网络中断了,没传输完成的怎么办?

带着这些疑问我们来分析下,首先,Redis 第一次数据同步时分 3 个阶段。

图片

1)建立连接,请求数据同步

主从节点建立连接,从库请求数据同步。

从服务器从 replicaof 配置项中获取主节点的 IP 和 Port,然后进行连接。

连接成功后,从服务器会向主服务器发送 PSYNC 命令,表示要进行同步。同时,命令中包含 runID 和 offset 两个关键字段。

  • runID:每个 Redis 实例的唯一标识,当主从复制进行时,该值为 Redis 主节点实例的ID。由于首次同步时还不知道主库的实例ID,所以该值第一次为 ?
  • offset:从库数据同步的偏移量,当第一次复制时,该值为 -1,表示全量复制

主服务器收到 PSYNC 命令后,会创建一个专门用于复制的后台线程(replication thread),然后记录从节点的 offset 参数并开始进行 RDB 同步。

2)RDB 同步

主库生成 RDB 文件,同步给从库。

当从服务器连接到主服务器后,主服务器会将自己的数据发送给从服务器,这个过程叫做全量复制。主服务器会执行 bgsave 命令,然后 fork 出一个子进程来遍历自己的数据集并生成一个 RDB 文件,将这个文件发送给从服务器。

在这期间,为了保证 Redis 的高性能,主节点的主进程不会被阻塞,依旧对外提供服务并接收数据写入缓冲区中。

从服务器接收到 RDB 文件后,会清空自身数据,然后加载这个文件,将自己的数据集替换成主服务器的数据集。

3)命令同步

在第一次同步过程中,由于是全量同步,所以用时可能比较长,这期间主库依旧会写入新数据。

但是,在数据同步一开始就生成的 RDB 文件中显然是没有这部分新增数据的,所以第一次数据同步后需要再发送一次这部分新增数据。

这样,主服务器需要在发送完 RDB 文件后,将期间的写操作重新发送给从服务器,以保证从服务器的数据集与主服务器保持一致。

3.3 增量同步

1)命令传播

在完成全量复制后,主从服务器之间会保持一个 TCP 连接,主服务器会将自己的写操作发送给从服务器,从服务器执行这些写操作,从而保持数据一致性,这个过程也称为基于长连接的命令传播(command propagation)。

增量复制的数据是异步复制的,但通过记录写操作,主从服务器之间的数据最终会达到一致状态。

2)网络断开后数据同步

命令传播的过程中,由于网络抖动或故障导致连接断开,此时主节点上新的写命令将无法同步到从库。

即便是抖动瞬间又恢复网络连接,但 TCP 连接已经断开,所以数据需要重新同步。

从 Redis 2.8 开始,从库已支持增量同步,只会把断开的时候没有发生的写命令,同步给从库。

图片

详细过程如下:

  1. 网络恢复后,从库携带之前主库返回的 runid,还有复制的偏移量 offset 发送 psync runid offset 命令给主库,请求数据同步;
  2. 主库收到命令后,核查 runid 和 offset,确认没问题将响应 continue 命令;
  3. 主库发送网络断开期间的写命令,从库接收命令并执行。

这时,有细心的小伙伴可能要问了,网络断开后,主库怎么知道哪些数据是新写入的呢?

这是个好问题,接下来我们详细说明一下。

3)增量复制的关键

Master 在执行写操作时,会将这些命令记录在 repl_backlog_buffer (复制积压缓冲区)里面,并使用 master_repl_offset 记录写入的位置偏移量。

而从库在执行同步的写命令后,也会用 slave_repl_offset 记录写入的位置偏移量。正常情况下,从库会和主库的偏移量保持一致。

但是,当网络断开后,主库继续写入,而从库没有收到新的同步命令,所以偏移量就停止了。所以,master_repl_offset 会大于 slave_repl_offset。

注意:主从库实现增量复制时,都是在 repl_backlog_buffer 缓冲区上进行。

网络断开前后,主从库的同步图如下:

图片

repl_backlog_buffer 复制积压缓冲区是一个环形缓冲区,如果缓冲区慢了(比如超过 1024),则会从头覆盖掉前面的内容。

所以,当网络恢复以后,主节点只需将 master_repl_offset 和 slave_repl_offset 之间的内容同步给从库即可(图中 256~512 这部分数据)。

需要注意的是,主库的积压缓冲区默认为 1M,如果从库网络断开太久,缓冲区之前的内容已经被覆盖,这时主从的数据复制就只能采取全量同步了。

所以我们需要根据业务量和实际情况来设置 repl_backlog_buffer 的值。

4. 小结

面让架构易于扩展,另一方面防止单体故障:当主库挂了,可以立即拉起从库,不至于让业务停滞太久。

而首次主从复制包括建立连接,RDB 同步和命令同步三个阶段。

为了保证同步的效率,除了第一次需要全量同步以外,例如当主从节点断连后,则只需要增量同步,这是由主从库的复制偏移量以及主库的 repl_backlog_buffer 复制积压缓冲区来控制的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1180934.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

GNU链接脚本详解

0. 前言 每一个链接都是由链接脚本控制的&#xff0c;链接脚本是用链接命令语言编写的脚本。链接都会用到一个链接脚本&#xff0c;如果你没有指定自己的脚本&#xff0c;就会使用默认的链接脚本。可以用 "--verbose" 命令行选项显示默认的连接脚本。指定命令行参数…

Unreal Engine 学习笔记 (2)—— 走跑切换

1.创建并编辑混合空间 鼠标右击内容浏览器选中动画选中混合空间1D选择对应的骨骼重命名为1D双击1D的图标&#xff0c;进入混合空间的编辑界面鼠标点开水平坐标标签设置名称为Speed设置最大轴值为600拖放对应动画到采样点中 2.创建动画蓝图 鼠标右击内容浏览器选中动画选中动…

【NLP】特征提取: 广泛指南和 3 个操作教程 [Python、CNN、BERT]

什么是机器学习中的特征提取&#xff1f; 特征提取是数据分析和机器学习中的基本概念&#xff0c;是将原始数据转换为更适合分析或建模的格式过程中的关键步骤。特征&#xff0c;也称为变量或属性&#xff0c;是我们用来进行预测、对对象进行分类或从数据中获取见解的数据点的…

国自然中标越来越难,怎样才能赢在起跑线上?

众所周知&#xff0c;国自然在学术界的地位和影响力不容小觑。“国自然在手&#xff0c;天下我有”&#xff0c;对于科研人来说&#xff0c;成功申报国自然&#xff0c;有助于职称评审、职业升迁&#xff0c;同时&#xff0c;获得不菲的科研经费。据了解&#xff0c;有些高校还…

MCU常见通信总线串讲(一)—— UART和USART

&#x1f64c;秋名山码民的主页 &#x1f602;oi退役选手&#xff0c;Java、大数据、单片机、IoT均有所涉猎&#xff0c;热爱技术&#xff0c;技术无罪 &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; 获取源码&#xff0c;添加WX 目录 前言一…

第七章 图【数据结构与算法】【精致版】

第七章 图【数据结构与算法】【精致版】 前言版权第七章 图7.1 应用实例7.2图的基本概念7.3图的存储结构7.3.1邻接矩阵**1-邻接矩阵.c****2-邻接矩阵plus.c** 7.3.2 邻接表**3-邻接表.c** **4-邻接表plus.c** 7.3.3 十字链表7.3.4多重链表 7.4图的遍历7.4.1深度优先搜索遍历**5…

每天一点python——day62

为了方便复制&#xff0c;我在下面附带了一个python文件。 C:\Users\Admin>python Python 3.9.13 (main, Aug 25 2022, 23:51:50) [MSC v.1916 64 bit (AMD64)] :: Anaconda, Inc. on win32Warning: This Python interpreter is in a conda environment, but the environmen…

【蓝桥杯选拔赛真题13】C++最短距离 青少年组蓝桥杯C++选拔赛真题 STEMA比赛真题解析

C/C++最短距离 第十二届青少组蓝桥杯C++选拔赛真题 一、题目要求 1、编程实现 有一个居民小区的楼房全是一样的,并且按矩阵样式排列。其楼房的编号为 1,2,3……,当排满一行时,从下一行相邻的楼往反方向排号。 例如:小区为 3 行 6 列,矩阵排列方式: 要求:已知小区…

python 之列表的常用方法

文章目录 1. **append()** 方法2. **extend()** 方法3. **insert()** 方法4. **pop()** 方法5. **remove()** 方法6. **clear()** 方法7. **index()** 方法8. **count()** 方法9. **reverse()** 方法10. **sort()** 方法 当操作 Python 列表时&#xff0c;常用的方法如下。以下…

Python学习笔记--模块简介

一、Python 模块简介 在开发过程中&#xff0c;随着程序代码越写越多&#xff0c;在一个文件里代码就会越来越长&#xff0c;越来越不容易维护。 后面我们学习了函数&#xff0c;知道函数是实现一项或多项功能的一段程序&#xff0c;这样就更方便我们重复使用代码。 紧接着&…

解析半导体测试系统及半导体的测试方法步骤

半导体如今在集成电路、通信系统、照明等领域被广泛应用&#xff0c;是一种非常重要的材料。在半导体行业中&#xff0c;半导体测试是特别关键的环节&#xff0c;以保证半导体器件及产品符合规定和设计要求&#xff0c;确保其质量和性能。 随着现代电子技术的发展&#xff0c;半…

移远EC600U-CN开发板 day02

1.QuecPythonLVGL显示图片 由于官方提供的显示图片函数使用失败&#xff0c;为了能在屏幕上显示图片&#xff0c;通过对出厂脚本的分析&#xff0c;成功使用LVGL显示图片 (1)代码 import lvgl as lv from tp import gt9xx from machine import LCD from machine import Pin …

别让噪声偷走你的听力

欢声笑语&#xff0c;音乐悠扬&#xff0c;燕语莺声&#xff0c;流水潺潺&#xff0c;和亲友畅所欲言…… 这些愉悦的声音让我们每天的生活更充实&#xff0c;他们也是美好记忆的重要组成部分。听力对于我们的身体健康、情感幸福和整体生活质量起着巨大的作用。 因此保护听力健…

华为fusionInsigtht集群es连接工具

华为fusionInsight为用户提供海量数据的管理及分析功能&#xff0c;快速从结构化和非结构化的海量数据中挖掘您所需要的价值数据。开源组件结构复杂&#xff0c;安装、配置、管理过程费时费力&#xff0c;使用华为FusionInsight Manager将为您提供企业级的集群的统一管理平台,在…

大数据管理平台有什么用?如何利用大数据管理平台优化企业运营?

在数字化时代&#xff0c;大数据管理平台已经成为了企业和组织不可或缺的工具。它不仅可以帮助企业跟踪和解决报修问题&#xff0c;还为数据分析提供了丰富的信息。通过合理利用大数据管理平台进行数据分析&#xff0c;企业可以更好地了解其运营情况&#xff0c;优化设备维修和…

攻防世界题目练习——Web引导模式(四)(持续更新)

题目目录 1. shrine2. very_easy_sql 1. shrine 打开网页题目内容如下&#xff1a; 是一段代码&#xff0c;我们把它还原一下&#xff1a; import flask import osapp flask.Flask(__name__) app.config[FLAG] os.environ.pop(FLAG) #这里应该是将config配置里的FLAG字段设…

Time series analysis of InSAR data: Methods and trends(NASA,2015)

文章目录 ISPRS J PHOTOGRAMMIntroductionPhase unwrapping相位解缠算法综述 Time series analysis of InSAR dataPersistent Scatterer Interferometry (PSI)--持久散射体☆☆☆☆PSInSAR && SBAS-InSAR☆☆☆☆PS-InSARSBAS-InSARDS-InSAR&#xff08;分布式散射体干…

金秋云创季——ECS爆品省钱攻略

阿里云双十一推出优惠活动——“金秋云创季”&#xff0c;其中&#xff0c;云服务ECS下的经济型e实例&#xff0c;低至99元/1年&#xff0c;新老用户都可购买&#xff0c;续费不涨价&#xff1b;轻量应用服务器&#xff0c;2核2G 低至87元1年……官方满减优惠享受折上折。惊喜不…

微服务架构——笔记(4)

微服务架构——笔记&#xff08;4&#xff09; 基于分布式的微服务架构 本次笔记为 此次项目的记录&#xff0c;便于整理思路&#xff0c;仅供参考&#xff0c;笔者也将会让程序更加完善 内容包括&#xff1a;8001集群构建&#xff0c;负载均衡&#xff0c;服务发现&#xff0…

day51

前端框架Booststrap 该框架已经帮我们写了很多页面样式&#xff0c;如果需要使用&#xff0c;只需要下载对应文件直接cv即可 在使用Booststrap的时候&#xff0c;所有发页面样式只需要通过修改class属性来调节即可 什么是Booststrap Bootstrap是一个开源的前端框架&#xff…