26 redis 中 replication/cluster 集群中的主从复制

发布时间:2023年12月19日

前言

我们这里首先来看?redis?这边实现比较复杂的?replication集群模式?

我们这里主要关注的是 redis?这边的主从同步的相关实现

这边相对比较简单,?我们直接基于?cluster集群模式 进行调试

?

?

主从命令同步复制

比如这里 master 是?redis_7002, slave 是?redis_7005

然后?这里是 master?这边直接同步?相关命令到各个 slave?

a19730e124774c85857090955e267bc1.png

?

然后这里是在 server.call:3765 进行命令存储到?backlog, aof, 以及同步发送到?slave?

命令真实执行是在?server.call:3675 的?cmd->proc->proc(c)

418fbbc6622a45fcbacaabe770ce8a0c.png

?

然后?redis_7005 这边拿到命令之后,?开始执行, 这个执行过程就和客户端这边发送执行命令一样?

e696cfc4a7874538a99cdc3dceaf3285.png

?

?

全量同步

整个流程分为两个 part, 一个是请求方,?就是?slave, 一个是提供方,?是?master?

slave 这边连接到?master?之后,?slave 发送?SYNC?命令到?master?

master 通知客户端需要全量同步, 然后?master?这边后台去?dump?内存快照文件

slave 这边等待?master?这边?dump?内存快照文件,?并通过网络传递过来?

master 这边?dump?内存快照文件生成之后,?会向?slave?这边进行传输

slave 这边拿到?master?的?dump?的内存快照信息,?将其持久化到 临时文件,?完成之后重命名为?dump.rdb, 然后清空当前数据库,?然后?加载 dump.rdb?文件进行一个快照的数据恢复?

我们这里?一边一边的看, 先看?slave, 再看?master?

?

slave 的处理

这个是?slave?这边启动的时候?就会进行的一个操作

这里?syncWithMaster 根据?server.repl_state 这边同步的处理了几个?slave?和?master?的交互,?分为了几个不同的阶段?REPL_STATE_CONNECT, REPL_STATE_CONNECTING, REPL_STATE_RECEIVE_PING_REPLY, REPL_STATE_SEND_HANDSHAKE 等等?

比如这里会?发送 ping?给?master, 然后等待?master?这边回复信息?

在发送?masterauth 等相关信息,?REPLCONF 等相关信息?

940a1e1b87924188a50abcc903662b87.png

?

后面和全量同步相关比较重要的流程就是?发送?SYNC?相关命令?

4a39f9fed3e045e2b222f3c318044dc3.png

?

然后?slave?这边会收到?master?这边的?FULLRESYNC?的通知?

34b74496b62949cda7472938880967fa.png

?

然后就是后面?slave?这边创建临时文件,?然后准备接受?master?这边?后台持久化 rdb?文件之后传递给?slave?这边,?之后的处理交给?readSyncBulkPayload

13b038ad45434cd3ad20a771daccc517.png

?

接受服务器这边传输过来的 rdb?文件的相关信息,?持久化到?上面创建的临时文件 repl_transfer_tmpfile

b0c87aeb46884d6aab1a5b22d8bcd4ed.png

?

然后就是 清空 slave?本地数据库,?然后重命名?临时文件 为?dump.rdb

然后加载?dump.rdb 到?slave?本地数据库?

2b7f847234874d599af93f8000cfbfdd.png

?

触发上面?syncWithMaster 的地方,?从上下文是可以看到是?serverCron 注册了一个定时任务,?100ms 跑一次,?跑的任务是?clusterCron 相关,?里面包含了这里的?connectWithMaster

所以节点的上下线?是可以再 100ms 左右感知到的?

6ead85e84fc64625b0fdd0679f2f5bc7.png

?

客户端这边相关日志如下,?基本上是?syncWithMaster + readSyncBulkPayload 这两部分中输出的?

前面两行是 connectWithMaster 中输出的连接?master?的相关日志?

后面的是?slave?这边向?master?发送 PING, master 进行回复?

后面的是?slave?这边发送?SYNC?指令,?询问是否可以增量同步,?master 这边回复?只能全量同步

然后是?slave?这边接收到了?master?的?dump.rdb?的数据信息,?合计210字节,?清空?slave?的数据库,?从?dump.rdb 中加载数据到?slave?的数据库,?最终同步成功?

e6e4e511e17a4d33b9c4d079075d44da.png

?

?

master 的处理

需要全量同步的有几个场景?

场景1?是?slave 未传递同步偏移,?或者偏移传递错误?

场景2?是?master 和?slave?两边的?replyid 对不上?

场景3?是?slave 这边传递的偏移不在?master?这边数据同步的偏移区间内, 偏移错误?或者 落后的太多

c5c9b8775a3444bd9eec5f6bde5487f7.png

?

然后就是?master?这边处理全量同步的大头了?

场景1?如果是已经在进行?dump 内存快照文件,?则等待即可?

场景2?如果是已经在?dump?内存快照,?并且通过?tcp 直接传输数据,?则只能等待操作完成?

场景3?master 可以?dump?内存快照,?或者直接通过 tcp?传输数据,?

af85abbcfcfa45ceb8e0ea54936075f4.png

?

处理如下,?通过?startBgsaveForReplication 进行逻辑上的分发?

是?dump?内存快照文件,?还是?dump内存快照直接通过 tcp?传输数据?

52f259ff5fdc4f738f35bd2887180487.png

?

然后这里就是?fork?出子进程,?让子进程?来 dump?内存快照,?并保存到目标文件?

b8228fd2a58f4d5eaf6e17f268540803.png

?

然后 master?这边有定时任务在定时检查?子进程是否完成, 周期为?1秒?

如果完成了,?则向?slave?这边传输?dump?的内存快照的数据?

917c4dbcf0904cc08b352d0337f836ea.png

?

master 这边日志如下?

slave 这边发送过来了?PSYNC 的请求?

然后?master?这边判断?replyid,?replyid2 匹配不上,?然后开始进行?全量同步?

然后?master?开始进行 dump?内存快照,?fork 子进程?来生成 dump.rdb

master dump 内存快照生成完成之后,?发送数据到?slave, 之后记录?成功日志

da60fc2fde1b4f83b00c8c124b7f8a1e.png

?

?

基于?backlog 的增量同步

master 这边添加增量命令到?backlog

命令到 server.call:3765 的时候,?会将命令添加到?backlog 队列?

其中存储的数据就是?具体的执行命令,?存储在了一个数据中, 比如这里的?“set name4 jerry17”, 会将其存储为?一个长度为3的数组,?元素分别为?[“set”, “name4”, “jerry17”]

ba04a1534ab046718c620d9d3b0cad42.png

?

具体的复制命令到 backlog?中的相关处理如下,?可以简单理解为一个?memcpy 进去,?然后更新?索引 repl_backlog_idx

a3044b1a017d43da8de3032f1f1d5aca.png

?

?

slave 这边长时间和?master?失联,?重新连接之后发送?PSYNC?增量同步请求

clusterCron 为定时任务,?定时扫描集群的状态,?如果失联了,?则重新建立连接?

同样是在?syncWithMaster 的代码中, 这里传入了?replyid 和?offset?到?master?

0c02133909a24ac9949c51dcf4be9040.png

?

?

master 这边获取增量的命令响应给客户端

比如这里传输了?134 字节的命令数据到客户端, 我们?再来看一下 详细的命令信息

b3fae4214f3e40d9bb2df8f977400e62.png

?

从响应的字符串信息中可以看到,?传输了?“select 0”, “set name4 jerry18”, “set name4 jerry19”, “set name4 jerry20” 四条命令,?其中?“select 0” 是?redis?自己增加的,?然后?其他的几个命令是 客户端这边交互产生的

d264df34188742058d2ec667e97c961a.png

?

?

slave 这边收到命令之后执行

客户端这边接收到这一批次的命令之后,?依次进行执行?“select 0”, “set name4 jerry18”, “set name4 jerry19”, “set name4 jerry20” 进而实现了增量的同步?

f02dc9a1337142dbb429264788559fde.png

?

?

?

?

?

文章来源:https://blog.csdn.net/u011039332/article/details/133395052
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。