提到主从复制,我们可能立马会联想到 MySQL 的主从复制。

MySQL 主从复制是 MySQL 高可用机制之一,数据可以从数据库服务器主节点复制到一个或多个从节点。

这篇文章,我们聊聊 RocketMQ 的主从复制,希望你读完之后,能够理解主从复制的精髓。

1 同步与异步

在 RocketMQ 的集群模式中,Broker 分为 Master 与 Slave,一个 Master 可以对应多个 Slave,但是一个 Slave 只能对应一个 Master。

每个 Broker 与 Name Server 集群中的所有节点建立长连接,定时注册 Topic 信息到所有 Name Server。

Master 节点负责接收客户端的写入请求,并将消息持久化到磁盘上。而 Slave 节点则负责从 Master 节点复制消息数据,并保持与 Master 节点的同步。

  • 同步复制

生产者发送消息后,Master 接收到存储消息请求,将消息数据同步给 Slave 后,才将存储结果返回给生产者。同步复制模式下,发送消息会有一定延迟,系统吞吐量也会降低。

  • 异步复制

生产者发送消息后,Master 接收到存储消息请求,将消息存储后,直接将存储结果返回给生产者。 Master 和 Slave 再通过异步的方式同步数据,这种复制模式具有较小的延迟,可以实现比较高的吞吐量。

若 Master 出现故障,有些数据可能未写入 Slave ,未同步的数据可能丢失。

复制流程分为两个部分:元数据复制消息数据复制

  • 主从服务器同步主题,消费者进度,延迟消费进度,消费者配置数据
  • 主从服务器同步消息数据

2 元数据复制

Slave Broker 定时任务每隔 10 秒会同步元数据,包括主题消费进度延迟消费进度消费者配置

同步主题时, Slave Broker 向 Master Broker 发送 RPC 请求,返回数据后,首先加入本地缓存里,然后持久化到本地。

3 消息数据复制

下图是 Master 和 Slave 消息数据同步的流程图。

1、Master 启动后监听指定端口;

Master 启动后创建 AcceptSocketService 服务 , 用来创建客户端到服务端的 TCP 链接。

RocketMQ 抽象了链接对象 HAConnection , HAConnection 会启动两个线程,分别用于读服务和写服务:

  • 读服务:处理 Slave 发送的请求
  • 写服务:用于向 Slave 传输数据

2、Slave 启动后,尝试连接 Master ,建立 TCP 连接;

HAClient 是客户端 Slave 的核心类 ,负责和 Master 创建连接和数据交互。

客户端在启动后,首先尝试连接 Master , 查询当前消息存储中最大的物理偏移量 ,并存储在变量 currentReportedOffset 里。

3、Slave 判定拉取间隔是否大于 5 秒,则向 Master 汇报已拉取消息偏移量;

上报进度的数据格式是一个 Long 类型的 Offset , 8个字节 , 非常简洁 。

发送到 Socket 缓冲区后 , 修改最后一次的写时间 lastWriteTimestamp 。

4、Master 解析请求偏移量,从消息文件中检索该偏移量后的所有消息;

当 Slave 上报数据到 Master 时,触发 SelectionKey.OP_READ 事件,Master 将请求交由 ReadSocketService 服务处理:

当 Slave Broker 传递了自身 commitlog 的 maxPhyOffset 时,Master 会马上中断 selector.select(1000) ,执行 processReadEvent 方法。

processReadEvent 方法的核心逻辑是设置 Slave 的当前进度 offset ,然后通知复制线程当前的复制进度。

写服务 WriteSocketService 从消息文件中检索该偏移量后的所有消息,并将消息数据发送给 Slave。

5、Slave 接收到数据,将消息数据 append 到消息文件 commitlog 里 。

首先 HAClient 类中调用 dispatchReadRequest 方法 , 解析出消息数据 ;

然后将消息数据 append 到本地的消息存储。

4 同步的实现

从数据复制流程图,我们发觉数据复制本身就是一个异步执行的,但是同步是如何实现的呢?

Master Broker 接收到写入消息的请求后 ,调用 Commitlog 的 aysncPutMessage 方法写入消息。

这段代码中,当 commitLog 执行完 appendMessage 后, 需要执行刷盘任务同步复制两个任务。

但这两个任务并不是同步执行,而是异步的方式,使用了 CompletableFuture 这个异步神器

当 HAConnection 读服务接收到 Slave 的进度反馈,发现消息数据复制成功,则唤醒 future 。

最后 Broker 组装响应命令 ,并将响应命令返回给客户端。

5 总结

1、主从复制包含元数据复制和消息数据复制两个部分;

2、元数据复制

​ Slave Broker 定时任务每隔 10 秒向 Master Broker 发送 RPC 请求,将元数据同步到缓存后,然后持久化到磁盘里;

3、消息数据复制

  • Master 启动监听指定端口
  • Slave 启动 HaClient 服务,和 Master 创建 TCP 链接
  • Slave 向 Master 上报存储进度
  • Master 接收进度,消息文件中检索该偏移量后的所有消息,并传输给 Slave
  • Slave 接收到数据后,将消息数据 append 到本地的消息存储。

4、同步的实现

​ 当 commitLog 执行完 appendMessage 后, 需要执行刷盘任务同步复制两个任务,这里用到了 CompletableFuture 这个异步神器。

​ 当 HAConnection 读服务接收到 Slave 的进度反馈,发现消息数据复制成功,则唤醒 future 。最后 Broker 组装响应命令 ,并将响应命令 返回给客户端 。


如果我的文章对你有所帮助,还请帮忙点赞、在看、转发一下,你的支持会激励我输出更高质量的文章,非常感谢!

聊聊 RocketMQ 主从复制的更多相关文章

  1. 通过源码分析RocketMQ主从复制原理

    作者:京东物流 宫丙来 一.主从复制概述 RocketMQ Broker的主从复制主要包括两部分内容:CommitLog的消息复制和Broker元数据的复制. CommitLog的消息复制是发生在消息 ...

  2. 聊聊rocketmq的ConsumeMode.CONCURRENTLY

    序 本文主要研究一下rocketmq的ConsumeMode.CONCURRENTLY ConsumeMode.CONCURRENTLY rocketmq-spring-boot-2.0.4-sour ...

  3. 聊聊rocketmq的sendBatchMessage

    序 本文主要研究一下rocketmq的sendBatchMessage SendMessageRequestHeader rocketmq-all-4.6.0-source-release/commo ...

  4. 聊聊MySQL主从复制的几种复制方式

    目录 异步复制 多线程复制 增强半同步复制 异步复制 MySQL的复制默认是异步的,主从复制至少需要两个MYSQL服务,这些MySQL服务可以分布在不同的服务器上,也可以在同一台服务器上. MySQL ...

  5. 聊聊MySQL常用的4种主从复制架构

    目录 一主多从复制架构 多级复制架构 双主(Dual Master)复制架构 多源(Multi-Source)复制架构 如何优化主从延迟问题? 复制的4中常见架构有一主多从复制架构.多级复制架构.双主 ...

  6. 消息队列面试题、RabbitMQ面试题、Kafka面试题、RocketMQ面试题 (史上最全、持续更新、吐血推荐)

    文章很长,建议收藏起来,慢慢读! 疯狂创客圈为小伙伴奉上以下珍贵的学习资源: 疯狂创客圈 经典图书 : <Netty Zookeeper Redis 高并发实战> 面试必备 + 大厂必备 ...

  7. 读完 RocketMQ 源码,我学会了如何优雅的创建线程

    RocketMQ 是一款开源的分布式消息系统,基于高可用分布式集群技术,提供低延时.高可靠的消息发布与订阅服务. 这篇文章,笔者整理了 RocketMQ 源码中创建线程的几点技巧,希望大家读完之后,能 ...

  8. 【Java进阶面试系列之一】哥们,你们的系统架构中为什么要引入消息中间件?

    转: [Java进阶面试系列之一]哥们,你们的系统架构中为什么要引入消息中间件? **这篇文章开始,我们把消息中间件这块高频的面试题给大家说一下,也会涵盖一些MQ中间件常见的技术问题. 这里大家可以关 ...

  9. RabbitMQ 常见问题

    RabbitMQ 常见问题 昔我往矣,杨柳依依.今我来思,雨雪霏霏. 1.什么是RabbitMQ?  RabbitMQ是一款开源的.Erlang编写的消息中间件:最大的特点就是消费并不需要确保提供方存 ...

  10. 聊聊redis的主从复制吧

    聊聊基础概念 主从复制与主从替换 主从复制不同于主从替换,主从复制是正常情况下主节点同步数据到从节点:主从替换是主节点挂了之后,把从节点替换为主节点: 从节点存在的意义:备份主节点数据+负载均衡(对外 ...

随机推荐

  1. Atcoder Regular Contest 093 C - Bichrome Spanning Tree

    给定一张图,对图上边黑白染色,使得同时选择了两种颜色边的最小生成树边权和为X,求染色方案数. 先求出图的\(mst\)大小,然后分三类讨论: 1.\(X<mst\) 无解 2.\(X==mst\ ...

  2. day93:flask:Cookie&Session&请求钩子&捕获错误&上下文&Flask-Script

    目录 1.HTTP的会话控制 2.Cookie 3.Session 4.请求钩子 5.捕获错误 6.上下文:context 7.Flask-Script 1.HTTP的会话控制 1.什么是会话控制? ...

  3. 【vue3-element-admin 】基于 Vue3 + Vite4 + TypeScript + Element-Plus 从0到1搭建后台管理系统(前后端开源@有来开源组织)

    vue3-element-admin 是基于 vue-element-admin 升级的 Vue3 + Element Plus 版本的后台管理前端解决方案,技术栈为 Vue3 + Vite4 + T ...

  4. RateLimiter使用

    1.maven依赖 <dependency> <groupId>com.google.guava</groupId> <artifactId>guava ...

  5. ES6 新增的一些特性

    还有symbol和set,map, bind,call,apply 1. let关键字 (1)基本用法:let关键字用来声明变量,它的用法类似于var,都是用来声明变量. (2)块级作用域:let声明 ...

  6. 2021-09-28:合并区间。以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回一个不重叠

    2021-09-28:合并区间.以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] .请你合并所有重叠的区间,并返回一个不重叠 ...

  7. WSGI介绍

  8. Value '0000-00-00 00:00:00' can not be represented as java.sql.Timestamp; nested exception is java.sql.SQLException: Value '0000-00-00 00:00:00' can not be represented as java.sql.Timestamp

    好久没记录了,最近一直在忙着工作以及码前后端 记录下这种大多数人都会碰到但是又不一定找得到问题的错误 1 Value '0000-00-00 00:00:00' can not be represen ...

  9. linux中使用jenkins自动部署前端工程

    1.去年在自己的服务器上安装了jenkins,说用来自己研究一下jenkins自动化部署前端项目,jenkins安装好了,可是一直没管,最近终于研究了一下使用jenkins自动化部署,以此记录下来. ...

  10. 「学习笔记」模运算与 BSGS 算法

    取模 取模符号:\(x \bmod y\),表示 \(x\) 除以 \(y\) 得到的余数. 例如, \[5 \bmod 3 = 2\\ 7 \bmod 4 = 3\\ 3 \bmod 3 = 0\\ ...