深入探究 Redis 集群:主从复制实现原理

embedded/2024/12/20 0:34:34/

  主服务器可以进行读写操作,当发生写操作时自动将写操作同步给从服务器,而从服务器一般是只读,并接受主服务器同步过来写操作命令,然后执行这条命令。 通过再B服务器上执行replicaof <服务器 A 的 IP 地址> <服务器 A 的 Redis 端口号>命令,A服务器会变成B服务器的主服务。

1.主从服务器的第一次同步--全量

  主从服务器间的第一次同步的过程可分为三个阶段:

  1. 第一阶段是建立链接、协商同步;
  2. 第二阶段是主服务器同步数据给从服务器;
  3. 第三阶段是主服务器发送新写操作命令给从服务器。  主从数据同步过程中产生的写命令;

第一阶段:建立链接、协商同步--建立的连接属于长链接,之后的命令同步都是通过该链接进行

  执行了 replicaof 命令后,从服务器就会给主服务器发送 psync 命令,表示要进行数据同步。psync 命令包含两个参数,分别是主服务器的 runID 和复制进度 offset。

  • runID,每个 Redis 服务器在启动时都会自动生产一个随机的 ID 来唯一标识自己。当从服务器和主服务器第一次同步时,因为不知道主服务器的 run ID,所以将其设置为 "?"。

  • offset,表示复制的进度,第一次同步时,其值为 -1。

  主服务器收到 psync 命令后,会用 FULLRESYNC 作为响应命令返回给对方。并且这个响应命令会带上两个参数:主服务器的 runID 和主服务器目前的复制进度 offset。从服务器收到响应后,会记录这两个值。FULLRESYNC 响应命令的意图是采用全量复制的方式,也就是主服务器会把所有的数据都同步给从服务器。所以,第一阶段的工作时为了全量复制做准备。

第二阶段:主服务器同步数据给从服务器

   接着,主服务器会执行bgsave命令来生成RDB文件(默认为该方式,也可以是AOF文件,但是第一次全量的的时候最好是rdb,二进制节省传输带宽,执行快),然后把文件发送给从服务器。从服务器收到RDB文件后,会先清空当前的数据,然后载入 RDB 文件。这里有一点要注意,主服务器生成 RDB 这个过程是不会阻塞主线程的,因为 bgsave 命令是产生了一个子进程来做生成 RDB 文件的工作,是异步工作的,这样 Redis 依然可以正常处理命令。但是,这期间的写操作命令并没有记录到刚刚生成的 RDB 文件中,这时主从服务器间的数据就不一致了。

  那么为了保证主从服务器的数据一致性,主服务器在下面这三个时间间隙中将收到的写操作命令,写入到 replication buffer {所有同步到从服务器的命令都会经过该缓冲区}缓冲区里:

  • 主服务器生成 RDB 文件期间;

  • 主服务器发送 RDB 文件给从服务器期间;

  • 「从服务器」加载 RDB 文件期间;

第三阶段:主服务器发送新写操作命令给从服务器

  在主服务器生成的 RDB 文件发送完,从服务器收到 RDB 文件后,丢弃所有旧数据,将 RDB 数据载入到内存。完成 RDB 的载入后,会回复一个确认消息给主服务器。接着,主服务器将 replication buffer 缓冲区里所记录的写操作命令发送给从服务器,从服务器执行来自主服务器 replication buffer 缓冲区里发来的命令,这时主从服务器的数据就一致了。

2.主从服务器第一次同步完成后,之后的写命令如何同步

   主从服务器在完成第一次同步后,就会基于长连接进行命令传播。具体流程如下:

  • 接收命令:当主节点接收到一个写命令时,首先会将该命令写入 Replication Buffer(实时数据)。这是因为 Replication Buffer 主要用于缓存当前的写操作,以便能够迅速将这些命令发送给连接的从节点。

  • 发送命令:主节点会尝试立即将 Replication Buffer 中的命令发送给其所有活跃的从节点。如果从节点连接正常,命令会被迅速传递。

  如果再整个架构中,系统一切都正常,那么主从同步就可以按照上面的流程正常运转下去,可是,网络总是不按套路出牌的嘛,说延迟就延迟,说断开就断开。如果主从服务器间的网络连接断开了,那么就无法进行命令传播了,这时从服务器的数据就没办法和主服务器保持一致了,客户端就可能从「从服务器」读到旧的数据。那么redis是如何处理的呢?依靠的就是增量复制。

3.增量复制

  在Redis 2.8之前,如果主从服务器在命令同步时出现了网络断开又恢复的情况,从服务器就会和主服务器重新进行一次全量复制,很明显这样的开销太大了,必须要改进一波。所以,从Redis 2.8开始,网络断开又恢复后,主从服务器会采用增量复制的方式继续同步,也就是只会把网络断开期间主服务器接收到的写操作命令,同步给从服务器。这里就离不开一个关键的缓存池:repl_backlog_buffer。

1.什么是repl_backlog_buffer

  Repl Backlog Buffer 是用来处理从节点与主节点之间的网络延迟和临时断开的情况。它会缓存主节点的命令,以便在从节点重新连接后能够获取这些命令并进行同步。具体来说,Repl Backlog Buffer 可以存储一定数量的写命令,以便在从节点恢复连接后,能够将这些命令发送给从节点,确保数据的一致性。

  其是一个「环形」缓冲区,如果写满会直接覆盖起始位置数据,跟mysql中的redo log双文件类似。其有几个指标比较重要:replication offset,标记上面那个缓冲区的同步进度,主从服务器都有各自的偏移量,主服务器使用 master_repl_offset 来记录自己「写」到的位置,从服务器使用 slave_repl_offset 来记录自己「读」到的位置。

2.repl_backlog_buffer和Replication Buffer的区别

  • 实时性:Replication Buffer 专注于存储最新的写命令。这意味着它只会包含在主节点当前的运行周期内接受的写操作,而不会包含历史操作或在从节点断开连接期间的命令

  • 缓冲区的生命周期:当一个新的写命令到达主节点时,该命令会被写入 Replication Buffer。如果从节点连接正常,主节点会立即将这些命令发送到从节点,Replication Buffer 中的命令会被及时消费。

  • 存储范围:Replication Buffer 的内容是瞬时的,代表了当前正在进行的写操作。而 Repl Backlog Buffer 则存储的是过去一段时间内的写操作,以便从节点在重新连接后获取这些丢失的命令。

  • 目的不同:Replication Buffer 主要是为了提高写操作的实时性和效率,确保主节点能迅速响应写请求。而 Repl Backlog Buffer 则用于处理网络波动或从节点断连的情况,确保从节点在恢复连接后能够同步所有遗漏的写操作。

3.repl_backlog_buffer如何实现增量复制

  • 接收命令:当主节点接收到一个写命令时,首先会将该命令写入 Replication Buffer(实时数据)。这是因为 Replication Buffer 主要用于缓存当前的写操作,以便能够迅速将这些命令发送给连接的从节点。

  • 发送命令:主节点会尝试立即将 Replication Buffer 中的命令发送给其所有活跃的从节点。如果从节点连接正常,命令会被迅速传递。

  • 写入 Repl Backlog Buffer:同时,主节点也会将相同的写命令写入 Repl Backlog Buffer历史数据)。这是为了在从节点因网络波动或其他原因暂时断开连接时,能够在其重新连接后补发这些命令,确保数据的一致性。

  上面的流程即是一个写命令的正常同步流程,此时发生了网络中断,1分钟以后网络恢复,那么这1分钟内发生的写命令已经同步到主节点的Repl Backlog Buffer中,那么如何同步到从节点呢?

  • 当从服务器重新连上主服务器时,从服务器会通过 psync 命令将自己的复制偏移量 slave_repl_offset 发送给主服务器

  • 主服务器根据自己的 master_repl_offset 和 slave_repl_offset 之间的差距,然后来决定对从服务器执行哪种同步操作:(1)如果判断出从服务器要读取的数据还在 repl_backlog_buffer 缓冲区里,那么主服务器将采用增量同步的方式;(2)如果判断出从服务器要读取的数据已经不存在 repl_backlog_buffer 缓冲区里,那么主服务器将采用全量同步的方式

  •  当主服务器在 repl_backlog_buffer 中找到主从服务器差异(增量)的数据后,就会将增量的数据直接发送到从服务器。  无需再经过replication buffer缓存

  所以再主从复制的架构中,为了保证断网后能够进行增量同步,我们需要适当增加repl_backlog_buffer 缓存池的大小。尽可能的大一些,减少出现从服务器要读取的数据被覆盖的概率,从而使得主服务器采用增量同步的方式。

4.repl_backlog_buffer 缓冲区具体要调整到多大呢

  估算公式为 second* write_size_per_second, 当然,为了应对一些突发的情况,可以将 repl_backlog_buffer 的大小设置为此基础上的 2 倍。

  • second 为从服务器断线后重新连接上主服务器所需的平均 时间(以秒计算)。

  • write_size_per_second 则是主服务器平均每秒产生的写命令数据量大小。

 

 


http://www.ppmy.cn/embedded/147146.html

相关文章

【容器】k8s学习笔记基础部分(三万字超详细)

概念 应用部署方式演变 在部署应用程序的方式上&#xff0c;主要经历了三个时代&#xff1a; 传统部署&#xff1a;互联网早期&#xff0c;会直接将应用程序部署在物理机上 优点&#xff1a;简单&#xff0c;不需要其它技术的参与 缺点&#xff1a;不能为应用程序定义资源使…

Luma 视频生成 API 对接说明

Luma 视频生成 API 对接说明 随着 AI 的应用变广&#xff0c;各类 AI 程序已逐渐普及。AI 已逐渐深入到人们的工作生活方方面面。而 AI 涉及的行业也越来越多&#xff0c;从最初的写作&#xff0c;到医疗教育&#xff0c;再到现在的视频。 Luma 是一个专业高质量的视频生成平…

【论文阅读:半监督人头姿态方法SemiUHPE】

【论文阅读&#xff1a;Semi-Supervised Unconstrained Head Pose Estimation in the Wild】 论文总结方法分析使用的数据集最后的指标头部定向强增强方法 论文 “Semi-Supervised Unconstrained Head Pose Estimation in the Wild” 论文总结 标题: Semi-Supervised Unconst…

《C 语言携手 PaddlePaddle C++ API:开启深度学习开发新征程》

在深度学习领域&#xff0c;PaddlePaddle 作为一款强大的深度学习框架&#xff0c;为开发者提供了丰富的功能和高效的计算能力。而 C 语言&#xff0c;凭借其高效性和广泛的应用场景&#xff0c;与 PaddlePaddle 的 C API 相结合&#xff0c;能够为深度学习开发带来独特的优势。…

Leetcode打卡:形成目标字符串需要的最少字符串数II

执行结果&#xff1a;通过 题目&#xff1a;3292 形成目标字符串需要的最少字符串数II 给你一个字符串数组 words 和一个字符串 target。 如果字符串 x 是 words 中 任意 字符串的 前缀 &#xff0c;则认为 x 是一个 有效 字符串。 现计划通过 连接 有效字符串形成 targ…

环境变革下 B2B 销售的转型与创新:开源 AI 智能名片与 S2B2C 商城小程序的助力

摘要&#xff1a;本文探讨了在信息科技与互联网迅猛发展所引发的环境改变背景下&#xff0c;B2B 销售工作面临的挑战与机遇。深入分析了传统销售模式的局限性以及新环境对销售人员素质和能力的要求&#xff0c;提出从提供“信息”向提供“业务价值”转变的必要性。同时&#xf…

python学opencv|读取图像(十三)BGR图像和HSV图像互相转换深入

【1】引言 前序学习过程中&#xff0c;我们偶然发现&#xff1a;如果原始图像是png格式&#xff0c;将其从BGR转向HSV&#xff0c;再从HSV转回BGR后&#xff0c;图像的效果要好于JPG格式。 文章链接为&#xff1a; python学opencv|读取图像&#xff08;十二&#xff09;BGR图…

车载通信架构 --- 一个以太网帧包含多个DoIP帧?

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 所谓鸡汤,要么蛊惑你认命,要么怂恿你拼命,但都是回避问题的根源,以现象替代逻辑,以情绪代替思考,把消极接受现实的懦弱,伪装成乐观面对不幸的…