RocketMQ高性能核心原理与源码架构剖析

RocketMQ高性能核心原理与源码架构剖析

读、写队列

  • 采用读写分离的方式,RocketMQ在创建Topic的时候会单独设置读队列和写队列,写队列负责写入以及同步数据到读队列,读队列会记录消费者的offset,负责消息拉取,通过MessageQueue的路由策略进行队列读、写指向
    • 如果写队列大于读队列,就会有一部分写队列无法同步到读队列,这样会造成数据丢失(消息存入了但是读取不到)
    • 如果写队列小于读队列,就会有一部分读队列无消息写入,造成消费者空转,耗费性能
  • 综述
    • 写队列 > 读队列,会造成消息丢失
    • 写队列 < 读队列,会造成消费者空转,耗费性能
    • 如果当Topic的MessageQueue进行缩减时,可以适当调整读写队列的数量
      • 先缩减写队列,待空出来的读队列上的消息消费完之后再去缩减读队列

消息持久化

  • RocketMQ采用顺序写磁盘来保证消息存储的速度以及mmap零拷贝技术来保证文件传输速度,文件存储结构采用稀疏索引方式(类似Kafka)

  • 存储文件主要分为3部分

    • CommitLog
      • 存储消息的所有实体
        • 消息都会被写入到CommitLog文件中,CommitLog由多个文件组成,没过文件固定1G,以首条消息的offset作为文件名
          • 对于生产者发送过来的消息都会依次存储到CommitLog文件中,相对于Kafka还需要寻找分区文件才能写入,减少了查找目标文件的时间,所以Kafka不适合过多Topic的场景
    • ComsumerQueue
      • 存储消息在CommitLog的索引
        • 一个MessageQueue对应一个文件,记录当前MessageQueue被消费者组消费到哪个CommitLog
          • 消费者可以通过ComsumerQueue文件中的消息索引定位需要的消息记录
    • IndexFile
      • 为了消息查询提供一种通过key或时间区间来查询消息的方法,这样不影响发送与消费消息的主流程
        • IndexFile文件主要是辅助消息检索,消费者可以通过ComsumerQueue文件中的消息索引定位需要的消息记录,但是如果要按照消息ID或者消息Key来检索文件,可以通过IndexFile文件来检索
          • IndexFile文件名为一串时间戳可以辅助检索时间区间
          • IndexFile结构与hash表类似,固定数量的槽位,每个槽位对应一条索引链(链表),槽位的值对应最新的索引号
  • 何时存储消息

    • MQ收到一条消息后,会向生产者进行反馈后再进行消息存储,当MQ推送消息给消费者时,会等待消费者反馈后再进行消息标记为已消费,如果消息者一直不反馈就会不断重发,当达到一定次数就会跳过该消息,并且MQ会定期清理一些过期的消息
      • 不管是生产端还是消费端都需要进行ACK之后才能进行持久化

过期文件删除

  • 消息既然需要持久化也需要对应的过期删除机制
  • 如何判断过期文件
    • RocketMQ中CommitLog文件和ComsumerQueue文件都是以偏移量命名,对于非当前写的文件如果超过了一定的保留时间会被认定为过期文件,随时都可以删除,所以对于RocketMQ的消息堆积也是有一定时间的,从而也会由于消息未消费导致消息丢失
  • 何时删除过期文件
    • RocketMQ中默认凌晨4点执行定时任务进行文件扫描,触发过期文件删除操作,如果磁盘空间不充足也会触发,所以官方建议Broker的磁盘空间不能少于4G

数据刷盘机制

image.png

  • 同步刷盘
    • 边写边存盘
      • 消息写入操作系统的页缓存后通知刷盘线程进行刷盘,刷盘成功之后唤醒等待的线程以及消息写成功的状态,保证了数据一定刷盘成功,吞吐量较小
  • 异步刷盘
    • 先写后续再刷盘
      • 消息可能只是写入操作系统的页缓存,就返回写入成功,但是会等待积累到一定程度去进行刷盘,保证了响应速度,但是容易丢数据

消息主从复制

  • Broker如果以主从集群架构进行部署,一个master会有多个slave,master会将数据同步到slave

  • 同步复制

    • master和slave的数据都写入成功之后才进行反馈,如果master故障,slave仍有数据备份,方便数据恢复,但是可能因为数据写入延迟降低了吞吐量
  • 异步复制

    • 保证master写入成功就进行反馈,再通过异步同步数据到slave,如果master出现故障会导致slave无法同步数据导致数据丢失

负载均衡

生产端负载均衡

image.png

  • 生产端在发送消息时,默认会轮询目标Topic下的所有MessageQueue,并采用递增取模的方式往不同的MessageQueue上法消息,来达到让消息平摊到不同的MessageQueue上,而由于MessageQueue分布在不同的Broker上,所以消息也会存在于不同的Broker上
  • 同时生产端在发消息时可以指定一个选择器(MessageQueueSelector)来保证消息的局部有序

消费端负载均衡

  • 消费端是以MessageQueue为单位进行负载均衡的,分为集群模式和广播模式
    • 集群模式
      • 在集群模式下,一条被订阅的消息在每个消费组只能被一个消费者消费,RocketMQ采用主动拉取的方式来消费消息,在拉取前需要指定MessageQueue,当消费端节点数量有变化时,都会触发一次负载均衡,会将MessageQueue数量以指定的分配算法摊到每个消费端节点
        • 同机房分配(AllocateMachineRoomNearby)
          • 将同机房的Consumer和Broker优先分配在一起,可以定制化规则
        • MessageQueue平均分配(AllocateMessageQueueAveragely)
          • 将所有MessageQueue平均分给每一个消费者
        • 不分配(AllocateMessageQueueByConfig
          • 直接指定一个MessageQueue列表,类似于广播模式,直接指定所有队列
        • 逻辑机房分配(AllocateMessageQueueByMachineRoom)
          • 按逻辑机房的概念进行分配,可以定制化规则
        • hash分配(AllocateMessageQueueConsistentHash)
          • 一致性哈希策略只需要指定一个虚拟节点数,是用的一个哈希环的算法,虚拟节点是为了让Hash数据在换上分布更为均匀
    • 广播模式
      • 在广播模式下,一条被订阅的消息会发送给所有消费者,广播模式实现的关键是将消费者消费的偏移量保存在消费端而不是Broker进行维护

消息重试

  • 首先对于广播模式下不存在消息重试机制,对于普通的消息,当消费失败之后可以进行消息重试

  • 如何让消息进行重试

    • 可以通过三种配置
      • 返回Action.ReconsumeLater(推荐)
      • 返回null
      • 抛出异常
    • 如果希望消费失败之后不充实,可以直接返回Action.CommitMessage
  • 重试消息如何处理

    • 每个消费者都会维护一个重试队列,重试的消息会被安排进去(“%RETRY%”+ConsumeGroup),默认允许重试16次,当达到阈值会被安排进入到死信队列(%DLQ%+ConsumGroup)
    • 死信队列
      • 当一条消息消费失败自动重试一定次数之后,RocketMQ不会立刻丢弃而是安排到死信队列中
      • 特征
        • 一个死信队列对应一个ConsumGroup,而不是对应某个消费者实例
        • 如果一个ConsumeGroup没有产生死信,RocketMQ就不会为其创建相应的死信队列
        • 一个死信队列包含了这个ConsumeGroup里的所有死信消息,而不区分该消息属于哪个Topic
        • 死信队列中的消息不会再被消费者正常消费
        • 死信队列的有效期跟正常消息相同

消息幂等

  • 在MQ系统中,对于消息幂等有三种实现语义
    • at most once 最多⼀次:每条消息最多只会被消费⼀次
      • 可以⽤异步发送、sendOneWay等⽅式就可以保证
    • at least once ⾄少⼀次:每条消息⾄少会被消费⼀次
      • 可以⽤同步发送、事务消息等很多⽅式能够保证
    • exactly once 刚刚好⼀次:每条消息都只会确定的消费⼀次
      • RocketMQ只能保证at least once,保证不了exactly once
        • 云上版本支持
  • 消息幂等的必要性
    • 出现重复的情况
      • 发送时消息重复
        • 当⼀条消息已被成功发送到服务端并完成持久化,此时出现了⽹络闪断或者客户端宕机,导致服务端对客户端
          应答失败, 如果此时⽣产者意识到消息发送失败并尝试再次发送消息,消费者后续会收到两条内容相同并且消息ID也相同的消息
      • 投递时消息重复
        • 消息消费的场景下,消息已投递到消费者并完成业务处理,当客户端给服务端反馈应答的时候⽹络闪断,为
          了保证消息⾄少被消费⼀次,Broker端将在⽹络恢复后再次尝试投递之前已被处理过的消息,消费者后续会收到两条内容相同并且消息ID也相同的消息
      • 负载均衡时消息重复(不限于⽹络抖动、Broker 重启以及订阅⽅应⽤重启)
        • 当 Broke端 或客户端重启、扩容或缩容时,会触发Rebalance,此时消费者可能会收到重复消息
    • 处理方式
      • 在RocketMQ中,是⽆法保证每个消息只被投递⼀次的,所以要在业务上⾃⾏来保证消息消费的幂等性,RocketMQ的每条消息都有⼀个唯⼀的MessageId,这个参数在多次投递的过程中是不会改变的,所以业务上可以⽤这个MessageId来作为判断幂等的关键依据,但是最好使用分布式ID来避免出现冲突

源码关注重点

  • NameServer的启动过程

    • 在RocketMQ集群中,实际进行消息存储、推送等核⼼功能点的是Broker,⽽NameServer的作⽤,其实和微服务中的注册中⼼⾮常类似,他只是提供了Broker端的服务注册与发现功能
  • Broker服务启动过程

    • Broker是整个RocketMQ的业务核⼼《所有消息存储、转发这些重要的业务都是Broker进⾏处理
  • Netty服务注册框架

    • Netty的所有远程通信功能都由remoting模块实现
    • 在RocketMQ中,涉及到的远程服务⾮常多,在RocketMQ中,NameServer主要是RPC的服务端RemotingServer,Broker对于客户端来说,是RPC的服务端RemotingServer,⽽对于NameServer来说,⼜是RPC的客户端
    • RocketMQ基于Netty保持客户端与服务端的⻓连接Channel,只要Channel是稳定的,那么即可以从客户端发请求到服务端,同样服务端也可以发请求到客户端
  • Broker⼼跳注册管理

    • Broker会在启动时向所有NameServer注册⾃⼰的服务信息,并且会定时往NameServer发送⼼跳信,⽽NameServer会维护Broker的路由列表,并对路由表进⾏实时更新
  • Producer发送消息过程

    • Producer有两种
      • 普通发送者(DefaultMQProducer)
        • 只负责发送消息,发送完消息,就可以停⽌了
      • 事务消息发送者(TransactionMQProducer)
        • ⽀持事务消息机制,需要在事务消息过程中提供事务状态确认的服务,这就要求事务消息发送者虽然是⼀个客户端,但是也要完成整个事务消息的确认机制后才能退出
  • Consumer拉取消息过程

    • 消费者也是有两种,推模式消费者和拉模式消费者
    • 消费者组之间有集群模式和⼴播模式两种消费模式
    • 消费者端的负载均衡
    • 消费者端消息的有序性
      • MessageListenerConcurrently
      • MessageListenerOrderly
  • 延迟消息机制

    • 延迟消息的核⼼使⽤⽅法就是在Message中设定⼀个MessageDelayLevel参数,对应18个延迟级别。然后Broker中会创建⼀个默认的Schedule_Topic主题,这个主题下有18个队列,对应18个延迟级别,消息发过来之 后,会先把消息存⼊Schedule_Topic主题中对应的队列,然后等延迟时间到了,再转发到⽬标队列,推送给消费者进⾏消费
  • ⻓轮询机制

    • RocketMQ对消息消费者提供了Push推模式和Pull拉模式两种消费模式,但是这两种消费模式的本质其实都是Pull拉模式,Push模式可以认为是⼀种定时的Pull机制
    • 当使⽤Push模式时,RocketMQ实现了⼀种⻓轮询机制(long polling)
      • 当Broker接收到Consumer的Pull请求时,判断如果没有对应的消息,不⽤直接给Consumer响应,⽽是就将这个Pull请求给缓存起来
      • 当Producer发送消息过来时,增加⼀个步骤去检查是否有对应的已缓存的Pull请求,如果有,就及时将请求从缓存中拉取出来,并将消息通知给Consumer

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/406620.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

7-liunx服务器规范

目录 概况liunx日志liunx系统日志syslog函数openlog 可以改变syslog默认输出方式 &#xff0c;进一步结构化 用户信息进程间的关系会话ps命令查看进程关系 系统资源限制改变工作目录和根目录服务器程序后台话 概况 liunx服务器上有很多细节需要注意 &#xff0c;这些细节很重要…

openGauss学习笔记-228 openGauss性能调优-系统调优-LLVM使用建议

文章目录 openGauss学习笔记-228 openGauss性能调优-系统调优-LLVM使用建议 openGauss学习笔记-228 openGauss性能调优-系统调优-LLVM使用建议 目前LLVM在数据库内核侧已默认打开&#xff0c;用户可结合上述的分析进行配置&#xff0c;总体建议如下&#xff1a; 设置合理的wor…

谷歌seo推广有什么方式?

首先是网站优化&#xff0c;这是所有SEO工作的基础&#xff0c;这不仅仅意味着关键词的优化&#xff0c;还包括提升网站的加载速度、确保良好的移动设备适配性、以及加强网站的安全性&#xff0c;一个技术性能优异的网站&#xff0c;能够为用户提供更佳的体验&#xff0c;从而受…

【IDEA】安装Jrebel实现热部署

前言 devtool虽然也可以实现热部署 但是新增完方法和修改完参数后 热部署不生效 需要重启 而Jrebel却不用 功能也比devtool强大 但是收费 这里教大家怎么使用 插件下载 激活Jrebel

通俗易懂地理解稀疏性

今天我想与大家探讨的是一个数学和工程学中的重要概念——稀疏性。这个概念可能听起来很抽象&#xff0c;但它实际上贯穿于我们生活中的许多方面。那么&#xff0c;稀疏性到底是什么呢&#xff1f;简单来说&#xff0c;在数学和信号处理领域&#xff0c;一个信号被称为稀疏&…

2024年最值得尝试的创业项目,利用信息差,普通人下班也能做

大家好&#xff0c;我是电商花花。 到了2024年&#xff0c;人们依然在寻找长期可靠的副业项目&#xff0c;但我建议暂时停一下&#xff0c;因为抖音小店这个轻松暴利的副业项目还在等着我们呢。 抖音小店无货源创业项目作为一个轻资产创业项目&#xff0c;操作简单&#xff0…

基于springboot+vue的信息化在线教学平台(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

018—pandas 生成笛卡尔积排列组合合并多列字符串数据

思路&#xff1a; 本需求需要将给定的几列数据&#xff0c;生成一个排列组合形式的数据列&#xff0c;利用到 Pandas 多层索引生成的笛卡尔积的方法。 二、使用步骤 1.引入库 代码如下&#xff08;示例&#xff09;&#xff1a; import pandas as pd2.读入数据 代码如下&…

每日一学—由面试题“Redis 是否为单线程”引发的思考

文章目录 &#x1f4cb; 前言&#x1f330; 举个例子&#x1f3af; 什么是 Redis&#xff08;知识点补充&#xff09;&#x1f3af; Redis 中的多线程&#x1f3af; I/O 多线程&#x1f3af; Redis 中的多进程&#x1f4dd; 结论&#x1f3af;书籍推荐&#x1f525;参与方式 &a…

【Ubuntu】解决Ubuntu 22.04开机显示器颜色(高对比度/反色)异常的问题

使用Ubuntu 22.04时强制关机了一下&#xff08;make -j16把电脑搞崩了&#xff09;&#xff0c;开机后系统显示的颜色异常&#xff0c;类似高对比度或反色&#xff0c;如下图。看着很难受&#xff0c;字体也没办法辨认。还好之前遇到过类似的问题&#xff0c;应该是一个配置文件…

政府采购网有哪些回款方式

政府采购网的回款方式多种多样&#xff0c;具体取决于采购项目的性质、规模以及采购单位与供应商之间的约定。以下是一些常见的政府采购网回款方式&#xff1a; 线上支付&#xff1a;随着电子商务的发展&#xff0c;越来越多的政府采购项目采用线上支付方式。这种方式方便快捷&…

TLS握手证书链的校验

看一遍忘一遍&#xff0c;还是自己写一遍&#xff0c;看看这次能记多久。 在TLS握手过程中&#xff0c;通过证书校验认证服务端的身份和交换加密秘钥&#xff0c;握手完成之后后续就可以进行加密数据传输。 在浏览器地址栏上点击锁的图标&#xff0c;能打开查看证书的详细信息…

猫毛过敏却想养猫时?如何缓解猫毛过敏?宠物空气净化器推荐

作为一个新养猫的主人&#xff0c;一开始并没有发现对猫咪过敏。直到养了半年才意识到这个问题&#xff0c;而此时我已经和猫咪有了深厚的感情。我不想放弃我的猫咪&#xff0c;但是留着它的话&#xff0c;我经常会因为流眼泪、打喷嚏、眼睛发红等过敏症状而影响日常生活&#…

位运算03 不用加号的加法[C++]

图源&#xff1a;文心一言 上机题目练习整理&#xff0c;位运算&#xff0c;供小伙伴们参考~&#x1f95d;&#x1f95d; 网页版目录在页面的右上角↗~&#x1f95d;&#x1f95d; 第1版&#xff1a;在力扣新手村刷题的记录~&#x1f9e9;&#x1f9e9; 编辑&#xff1a;梅…

go 1.18 不同目录package引用问题

go 1.18开始使用module了 不同的package在vs code中引用的话 需要先开启 是Go1.11版本之后 推出的版本管理工具 有点类似java的 maven工具 可以引入依赖使用 go env -w GO111MODULEon 先把这个打开 然后在创建的vs code工作目录下 执行 module gomdoule module 模块名 会生…

(六)激光线扫描-三维重建

本篇文章是《激光线扫描-三维重建》系列的最后一篇。 1. 基础理论 1.1 光平面 在之前光平面标定的文章中,已经提到过了,是指 激光发射器投射出一条线,形成的一个扇形区域平面就是光平面。 三维空间中平面的公式是: A X + B Y + C Z + D = 0 A X+B Y+C Z+D=0

解决RabbitMQ管理页面异常/不正确的问题

正确的页面&#xff1a;有Channels、Exchanges等 异常/不正确的页面&#xff1a; 问题原因 我的RabbitMQ是用docker安装的&#xff0c;应该不会是安装的环境有问题。 而且MQ的服务确实是启动了&#xff0c;后端能正常使用&#xff0c;并且管理界面的登录页面也是能正常登录的&…

流程图:理解、创建与优化的视觉工具

流程图&#xff1a;理解、创建与优化的视觉工具 引言 在日常生活和工作中&#xff0c;我们经常遇到需要描述一系列步骤或过程的情况。这些步骤可能是制作一杯咖啡、完成一个项目&#xff0c;或者是解决一个复杂的数学问题。流程图&#xff0c;作为一种强大的视觉工具&#xf…

数据同步MySQL -> Elasticsearch

大家好我是苏麟,今天聊聊数据同步 . 数据同步 一般情况下&#xff0c;如果做查询搜索功能&#xff0c;使用 ES 来模糊搜索&#xff0c;但是数据是存放在数据库 MySQL 里的&#xff0c;所以说我们需要把 MySQL 中的数据和 ES 进行同步&#xff0c;保证数据一致(以 MySQL 为主)…

在 Jupyter Notebook 中查看所使用的 Python 版本和 Python 解释器路径

&#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ 我们在做 Python 开发时&#xff0c;有时在我们的服务器上可能安装了多个 Python 版本。 使用 conda info --envs 可以列出所有的 conda 环境。当在 Linux 服务器上使用 which python 命令时&#xff0…