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

ops/2024/12/19 17:23:11/

  主服务器可以进行读写操作,当发生写操作时自动将写操作同步给从服务器,而从服务器一般是只读,并接受主服务器同步过来写操作命令,然后执行这条命令。 通过再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/ops/143236.html

相关文章

解锁CSS新维度:预处理器之LessSass

在现代前端开发中&#xff0c;CSS&#xff08;层叠样式表&#xff09;是用于控制网页外观的主要技术。然而&#xff0c;随着项目的复杂度增加&#xff0c;传统的CSS编写方式逐渐显现出其局限性&#xff0c;如变量复用、嵌套规则、模块化管理等需求难以满足。为此&#xff0c;出…

【错误收集】tomcat资源访问404

在使用tomcat的时候&#xff0c;tomcat 能够正常访问&#xff0c;index.html也能正常访问。报错界面&#xff1a; 但是只有WebServlet的资源无法访问&#xff0c;原因是&#xff1a;servlet的版本太高。 改正后的maven: <?xml version"1.0" encoding"UTF-…

[ClickHouse 运维系列] 数据 TTL 学习笔记整理

一、clickhouse TTL ClickHouse的MergeTree引擎支持数据生命周期管理&#xff0c;即TTL&#xff08;Time To Live&#xff09;。TTL可以通过设置列字段或整张表的过期时间来实现。列字段的TTL会在时间到期时删除该列数据&#xff0c;而表级别的TTL会删除整张表的数据。如果同…

Java——网络编程(中)—TCP通讯(下)

1 双向通讯—创建服务端 (双向通信是指通信双方中&#xff0c;任何一方都可为发送端&#xff0c;任何一方都可为接收端) (1 创建ServerSocket对象&#xff0c;accept()返回socket) (2 双向通讯——>也要创建键盘输入对象) (3 通过与客户端对应的Socket对象获取输入流对象…

MySQL索引事务

1.索引 索引的作用类似书籍目录,可以用于快速定位,检索数据 可以对数据库表的某列或者某几列创建索引 索引针对查询操作引入的优化手段,但生成索引也会占用更多的空间 对于插入/删除/修改频率高的表不适用索引 使用场景 数据量大,经常对这些列进行条件查询 2.查看/创建/…

Jsckson @JsonValue 注解

概述 Jackson 是一个常用的 Java 库&#xff0c;用于将 Java 对象转换为 JSON 表示形式&#xff0c;并可以反向操作。有时&#xff0c;我们需要以自定义的方式序列化 Java 对象。Jackson 的JsonValue 注解通过允许使用单个方法的返回值作为对象的序列化表示来实现这一点。 Jso…

【前端开发】HTML+CSS网页,可以拿来当作业(免费开源)

HTML代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content_lizhongyu"widthdevice-width, initial-scale1.0"><title>小兔鲜儿-新鲜、惠民、快捷<…

如何查询SQL Server数据库服务器的IP地址

如何查询SQL Server数据库服务器的IP地址 作为数据库管理员或开发人员&#xff0c;了解如何查询SQL Server数据库服务器的IP地址是一项重要技能。本文将介绍几种简单而有效的方法&#xff0c;帮助你轻松获取这一信息。无论你是新手还是经验丰富的专业人士&#xff0c;这些方法…