初识Redis · 主从复制(下)
目录
前言:
数据同步
全量复制
部分复制
实时复制
前言:
前文我们已经介绍过了主从复制的基本概念,即分布式系统中存在多个Redis节点,一个是充当为主节点,其他的为从节点,并且从节点也是可以成为主节点,不过这个从节点是没有办法更改数据的。而主从模式解决的问题是单点问题,当我们连接上主节点之后,我们通过info replication是可以查看对应的连接信息的。
我们拿一份来看看:
我们上一篇简单带过后面四行,这是积压缓冲区的相关内容,然后还有什么replid runid offset我们也只是简单的提及了一下,这些字段都是我们在同步数据的时候要用到的,并且我们最后引入了从节点连接上主节点之后的流程,流程为:保存主节点的信息->tcp连接->ping->验证权限->同步数据集->命令持续复制。
那么我们今天的主题就是介绍主从复制的核心机制:如何同步数据。
废话不多说,直接进入主题吧。
数据同步
首先数据同步的时候分为了三种模式,分别是全量复制,部分复制以及实时复制,其中什么时候需要全量复制什么时候使用部分复制都是需要根据实际情况来定的。
全量复制
replid:
对于复制数据来说,如果是让我们自己来手动复制,那这个点来说就比较挫了,所以Redis提供了psync命令,通过psync命令来自动实现数据的同步:
而当我们在命令行中敲下了psync命令之后,我们会发现后面的两个提示符分别是replicationid offset,所以我们现在就应该思考,这两个东西是用来干什么的了。
对于replicationid来说,我们分别在主节点和从节点查看的话:
我们发现所有的replid都是一样的,也就是说这个id是用来区分数据的来源,因为目前的拓扑结构是6379的从节点是6380,6380的从节点是6381,所有的数据同步都来源于6379这个节点,所以我们不妨大胆猜测replid就是用来指定数据来源的。
得出结论:
在 Redis 的复制链路中,
replid
是用于标识主节点身份的唯一标识符。在链式复制结构中,只要最终数据来源是同一个主节点,所有下游节点保存的replid
就会一致。这也正是 Redis 能够在网络闪断或断线重连时判断能否进行部分同步的关键依据。
那么我们不止发现有一个replid,我们发现有两个replid,一般来说第二个replid是用不上的,但是如果主节点挂了,发生了更改,那么replid2就会用来记录对应的已经挂的主节点的replid,当恢复的时候,就会通过replid去重新匹配已经挂了的主节点的数据。
所以replid2主要是用来提高容错性的。
当然了,重新连接的过程是需要人工干预的,但是有意思的是哨兵机制是可以很完美的完成这个工作的。
offset:
在 Redis 的复制系统中,主节点会维护一个递增的整数值,称为 复制偏移量(replication offset),简称 offset。它表示的是主节点已经向从节点发送了多少字节的数据(以字节为单位,不是命令数量)。
当主节点写了多条命令,offset达到了10200的时候,从节点的offset如果是10000,就代表还有200字节的数据没有复制完成。
对于主节点来说,offset的作用表示写入进度,全局唯一的值,持续递增,对于从节点来说,它表示的是复制进度,用于请求主节点的数据。
而对于数据来说,replid和offset就相当于描述了一个数据集合,如果两个机器的replid和offset是完全一样的,也就代表了这两台机器上的数据是完全一样的了。
当从节点发送psync给主节点的时候,主节点返回的1代表的是全量复制,2代表的是部分复制,3代表的是出错,这里的出错就有多种原因了,比如版本不一致,比如网络抖动问题,比如rdb文件出错(后面要考)。
当我们的offset设置为了-1的时候代表的就是全量复制,当我们的offset设置为了具体的一个正数,那么执行的就是部分复制了,那么如果整数的设置是超过了主节点的offset的话,首先主节点会拒绝数据同步要求,然后回退执行全量复制。
那么什么时候执行全量复制呢?
当从节点第一次连接到了主节点的时候或者主节点不方便进行部分复制的时候,就会进行全量复制,是的,你没听错,数据同步实际上还是要根据主节点的实际情况确定的。
无硬盘模式
对于全量复制来说,主从节点之间也是支持无硬盘模式的,即主节点生成的rdb文件不直接保存到硬盘中了,直接就通过tcp网络传输把数据发送给了从节点。
这个操作能够为节点省下一系列的读写硬盘操作,不过如果数据量大了,网络传输消耗的资源还是比较大的,毕竟网络传输的资源可没有办法省略。
全量复制的一般流程为:
1)从节点发送 psync 命令给主节点进⾏数据同步,由于是第⼀次进⾏复制,从节点没有主节点的运⾏ ID 和复制偏移量,所以发送 psync ? -1。2)主节点根据命令,解析出要进行全量复制,回复 +FULLRESYNC 响应。3)从节点接收主节点的运⾏信息进⾏保存。4)主节点执行 bgsave 进⾏ RDB ⽂件的持久化。5)从节点发送 RDB ⽂件给从节点,从节点保存 RDB 数据到本地硬盘。6)主节点将从生成 RDB 到接收完成期间执⾏的写命令,写⼊缓冲区中,等从节点保存完 RDB ⽂件后,主节点再将缓冲区内的数据补发给从节点,补发的数据仍然按照 rdb 的⼆进制格式追加写⼊到收到的 rdb ⽂件中. 保持主从⼀致性。7)从节点清空⾃⾝原有旧数据。8)从节点加载 RDB ⽂件得到与主节点⼀致的数据。9)如果从节点加载 RDB 完成之后,并且开启了 AOF 持久化功能,它会进⾏ bgrewrite 操作,得到最近的 AOF文件。
部分复制
这是部分复制的一个简单流程图。
首先,什么时候进行部分复制呢?
当从节点已经从主节点同步过了数据或者是发生了网络抖动,导致主节点突然下线了,重新连接的时候从节点就要同步主节点下线的时候收到的命令了。
步骤 | 操作角色 | 操作内容 | 说明 |
---|---|---|---|
1 | 从节点 | 向主节点发送 PSYNC <replid> <offset> 请求 | 包含从节点记录的主节点 replid 和最新的 offset |
2 | 主节点 | 检查 replid 是否匹配 | 对比当前或旧的 replid2 ,判断是否是自己 |
3 | 主节点 | 检查 offset 是否仍在 backlog 中 | 判断是否有足够的历史数据可供部分同步 |
4 | 主节点 | 条件成立:发送 backlog 中 offset 之后的数据 | 主节点开始增量推送命令流 |
5 | 从节点 | 接收并应用增量数据 | offset 会随着数据同步不断递增 |
6 | 同步完成 | 主从状态更新为 ONLINE | 说明部分复制成功,无需全量复制 |
这是它的一般流程,我们主要是要注意replid是否正确,如果replid不正确的话,那么就会进行全量复制,并且在这里,主节点因为突然下线而没有发送给从节点的命令就会放在一个缓冲区里面。
这个缓冲区叫做积压缓冲区,我们刚才info replication看到的就是积压缓冲区的相关描述,对于积压缓冲区来说,它实际上是一个环形队列,也就是说它存在数据覆盖的可能性,如果数据覆盖了,那么也就没有办法部分复制了,就会全量复制了。
实时复制
这个就非常简单了,主节点会和从节点建立TCP长连接,通过网络服务发送对应的命令。
Redis 的实时复制指的是主节点在执行写操作时,会将这些写命令通过异步方式实时发送给所有从节点。从节点收到命令后,会立即按顺序执行这些命令,从而保持与主节点数据一致。整个过程是非阻塞的,主节点不会因为等待从节点响应而停顿服务。
这种复制机制保证了主从之间数据同步的“近实时性”,即使在高并发场景下,也能保持较低的延迟。通过 INFO replication
命令可以查看从节点的延迟情况(lag 字段),一般 lag 值越小代表同步越及时。
实时复制是 Redis 实现高可用、读写分离和快速主备切换的重要基础,结构简单,但在实际应用中非常高效稳定。
我们现在要注意一个问题,因为我们只是简单更改了一下配置文件对应的端口号,对于aof文件的生成位置是没有更改的,那么三个服务器共用一个aof文件是不应该的,这个问题会导致我们的服务器没有办法启动。
主要是因为aof文件的权限问题,服务器加载的时候肯定是通过读写的方式打开aof文件的,所以权限不对,自然就启动不了,所以我们需要有意的更改一下对应的权限。
感谢阅读!