• RocketMQ核心知识原理


    RocketMQ使用场景

    • 应用解耦
    • 流量削峰
    • 数据分发

    RocketMQ架构

    • 架构图

      • 技术架构

    在这里插入图片描述

    • RocketMQ架构上主要分为四部分

      • Producer:消息发布的角色,支持分布式集群方式部署。Producer通过MQ的负载均衡模块选择相应的Broker集群队列进行消息投递,投递的过程支持快速失败并且低延迟。

      • Consumer:消息消费的角色,支持分布式集群方式部署。支持以push推,pull拉两种模式对消息进行消费。同时也支持集群方式和广播方式的消费,它提供实时消息订阅机制,可以满足大多数用户的需求

      • NameServer:NameServer是一个非常简单的Topic路由注册中心,其角色类似Dubbo中的zookeeper,支持Broker的动态注册与发现。主要包括两个功能:Broker管理,NameServer接受Broker集群的注册信息并且保存下来作为路由信息的基本数据。然后提供心跳检测机制,检查Broker是否还存活;路由信息管理,每个NameServer将保存关于Broker集群的整个路由信息和用于客户端查询的队列信息。然后Producer和Conumser通过NameServer就可以知道整个Broker集群的路由信息,从而进行消息的投递和消费。NameServer通常也是集群的方式部署,各实例间相互不进行信息通讯。Broker是向每一台NameServer注册自己的路由信息,所以每一个NameServer实例上面都保存一份完整的路由信息。当某个NameServer因某种原因下线了,Broker仍然可以向其它NameServer同步其路由信息,Producer和Consumer仍然可以动态感知Broker的路由的信息

      • BrokerServer:Broker主要负责消息的存储、投递和查询以及服务高可用保证,为了实现这些功能,Broker包含了以下几个重要子模块。

        1. Remoting Module:整个Broker的实体,负责处理来自Client端的请求。

        2. Client Manager:负责管理客户端(Producer/Consumer)和维护Consumer的Topic订阅信息。

        3. Store Service:提供方便简单的API接口处理消息存储到物理硬盘和查询功能。

        4. HA Service:高可用服务,提供Master Broker 和 Slave Broker之间的数据同步功能。

        5. Index Service:根据特定的Message key对投递到Broker的消息进行索引服务,以提供消息的快速查询。

        在这里插入图片描述

    • 架构部署

    在这里插入图片描述

    - **RocketMQ 网络部署特点**
      - NameServer是一个几乎无状态节点,可集群部署,节点之间无任何信息同步
      - Broker部署相对复杂,Broker分为Master与Slave,一个Master可以对应多个Slave,但是一个Slave只能对应一个Master,Master与Slave 的对应关系通过指定相同的BrokerName,不同的BrokerId 来定义,BrokerId为0表示Master,非0表示Slave。Master也可以部署多个。每个Broker与NameServer集群中的所有节点建立长连接,定时注册Topic信息到所有NameServer。 注意:当前RocketMQ版本在部署架构上支持一Master多Slave,但只有BrokerId=1的从服务器才会参与消息的读负载
      - Producer与NameServer集群中的其中一个节点(随机选择)建立长连接,定期从NameServer获取Topic路由信息,并向提供Topic 服务的Master建立长连接,且定时向Master发送心跳。Producer完全无状态,可集群部署
      - Consumer与NameServer集群中的其中一个节点(随机选择)建立长连接,定期从NameServer获取Topic路由信息,并向提供Topic服务的Master、Slave建立长连接,且定时向Master、Slave发送心跳。Consumer既可以从Master订阅消息,也可以从Slave订阅消息,消费者在向Master拉取消息时,Master服务器会根据拉取偏移量与最大偏移量的距离(判断是否读老消息,产生读I/O),以及从服务器是否可读等因素建议下一次是从Master还是Slave拉取
    - **集群工作流程**
      - 启动NameServer,NameServer起来后监听端口,等待Broker、Producer、Consumer连上来,相当于一个路由控制中心
      - Broker启动,跟所有的NameServer保持长连接,定时发送心跳包。心跳包中包含当前Broker信息(IP+端口等)以及存储所有Topic信息。注册成功后,NameServer集群中就有Topic跟Broker的映射关系
      - 收发消息前,先创建Topic,创建Topic时需要指定该Topic要存储在哪些Broker上,也可以在发送消息时自动创建Topic
      - Producer发送消息,启动时先跟NameServer集群中的其中一台建立长连接,并从NameServer中获取当前发送的Topic存在哪些Broker上,轮询从队列列表中选择一个队列,然后与队列所在的Broker建立长连接从而向Broker发消息
      - Consumer跟Producer类似,跟其中一台NameServer建立长连接,获取当前订阅Topic存在哪些Broker上,然后直接跟Broker建立连接通道,开始消费消息
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 角色介绍

      • 消息模型(Message Model)
        • RocketMQ主要由 Producer、Broker、Consumer 三部分组成,其中Producer 负责生产消息,Consumer 负责消费消息,Broker 负责存储消息。Broker 在实际部署过程中对应一台服务器,每个 Broker 可以存储多个Topic的消息,每个Topic的消息也可以分片存储于不同的 Broker。Message Queue 用于存储消息的物理地址,每个Topic中的消息地址存储于多个 Message Queue 中。ConsumerGroup 由多个Consumer 实例构成
      • 消息生产者(Producer)
        • 负责生产消息,一般由业务系统负责生产消息。一个消息生产者会把业务应用系统里产生的消息发送到broker服务器。RocketMQ提供多种发送方式,同步发送、异步发送、顺序发送、单向发送。同步和异步方式均需要Broker返回确认信息,单向发送不需要
      • 消息消费者(Consumer)
        • 负责消费消息,一般是后台系统负责异步消费。一个消息消费者会从Broker服务器拉取消息、并将其提供给应用程序。从用户应用的角度而言提供了两种消费形式:拉取式消费、推动式消费
      • 主题(Topic)
        • 表示一类消息的集合,每个主题包含若干条消息,每条消息只能属于一个主题,是RocketMQ进行消息订阅的基本单位
      • 代理服务器(Broker Server)
        • 消息中转角色,负责存储消息、转发消息。代理服务器在RocketMQ系统中负责接收从生产者发送来的消息并存储、同时为消费者的拉取请求作准备。代理服务器也存储消息相关的元数据,包括消费者组、消费进度偏移和主题和队列消息等
      • 名字服务(Name Server)
        • 名称服务充当路由消息的提供者。生产者或消费者能够通过名字服务查找各主题相应的Broker IP列表。多个Namesrv实例组成集群,但相互独立,没有信息交换
      • 拉取式消费(Pull Consumer)
        • Consumer消费的一种类型,应用通常主动调用Consumer的拉消息方法从Broker服务器拉消息、主动权由应用控制。一旦获取了批量消息,应用就会启动消费过程
      • 推动式消费(Push Consumer)
        • Consumer消费的一种类型,该模式下Broker收到数据后会主动推送给消费端,该消费模式一般实时性较高
      • 生产者组(Producer Group)
        • 同一类Producer的集合,这类Producer发送同一类消息且发送逻辑一致。如果发送的是事务消息且原始生产者在发送之后崩溃,则Broker服务器会联系同一生产者组的其他生产者实例以提交或回溯消费
      • 消费者组(Consumer Group)
        • 同一类Consumer的集合,这类Consumer通常消费同一类消息且消费逻辑一致。消费者组使得在消息消费方面,实现负载均衡和容错的目标变得非常容易。要注意的是,消费者组的消费者实例必须订阅完全相同的Topic。RocketMQ 支持两种消息模式:集群消费(Clustering)和广播消费(Broadcasting)
      • 集群消费(Clustering)
        • 集群消费模式下,相同Consumer Group的每个Consumer实例平均分摊消息
      • 广播消费(Broadcasting)
        • 广播消费模式下,相同Consumer Group的每个Consumer实例都接收全量的消息
      • 普通顺序消息(Normal Ordered Message)
        • 普通顺序消费模式下,消费者通过同一个消息队列( Topic 分区,称作 Message Queue) 收到的消息是有顺序的,不同消息队列收到的消息则可能是无顺序的
      • 严格顺序消息(Strictly Ordered Message)
        • 严格顺序消息模式下,消费者收到的所有消息均是有顺序的
      • 消息(Message)
        • 消息系统所传输信息的物理载体,生产和消费数据的最小单位,每条消息必须属于一个主题。RocketMQ中每个消息拥有唯一的Message ID,且可以携带具有业务标识的Key。系统提供了通过Message ID和Key查询消息的功能
      • 标签(Tag)
        • 为消息设置的标志,用于同一主题下区分不同类型的消息。来自同一业务单元的消息,可以根据不同业务目的在同一主题下设置不同标签。标签能够有效地保持代码的清晰度和连贯性,并优化RocketMQ提供的查询系统。消费者可以根据Tag实现对不同子主题的不同消费逻辑,实现更好的扩展性

    RocketMQ核心消息存储原理

    • 消息存储

      在这里插入图片描述

    • 息存储整体架构

      • CommitLog

        • CommitLog:消息主体以及元数据的存储主体,存储Producer端写入的消息主体内容,消息内容不是定长的。单个文件大小默认1G, 文件名长度为20位,左边补零,剩余为起始偏移量,比如00000000000000000000代表了第一个文件,起始偏移量为0,文件大小为1G=1073741824;当第一个文件写满了,第二个文件为00000000001073741824,起始偏移量为1073741824,以此类推。消息主要是顺序写入日志文件,当文件满了,写入下一个文件;注意每次文件会先申请1G得存储生成文件,借助磁盘的优势顺序写提高性能,保证了消息顺序存储的速度。文件大小一般需要限制在1.5~2G以下),采用Mmap的方式其读/写的效率和性能都非常高,
      • ConsumeQueue

        • ConsumeQueue:消息消费队列,引入的目的主要是提高消息消费的性能,由于RocketMQ是基于主题topic的订阅模式,消息消费是针对主题进行的,如果要遍历commitlog文件中根据topic检索消息是非常低效的。Consumer即可根据ConsumeQueue来查找待消费的消息。其中,ConsumeQueue(逻辑消费队列)作为消费消息的索引,保存了指定Topic下的队列消息在CommitLog中的起始物理偏移量offset,消息大小size和消息Tag的HashCode值。consumequeue文件可以看成是基于topic的commitlog索引文件,故consumequeue文件夹的组织方式如下:topic/queue/file三层组织结构,具体存储路径为:$HOME/store/consumequeue/{topic}/{queueId}/{fileName}。同样consumequeue文件采取定长设计,每一个条目共20个字节,分别为8字节的commitlog物理偏移量、4字节的消息长度、8字节tag hashcode,单个文件由30W个条目组成,可以像数组一样随机访问每一个条目,每个ConsumeQueue文件大小约5.72M;
      • IndexFile

        • IndexFile:IndexFile(索引文件)提供了一种可以通过key或时间区间来查询消息的方法。Index文件的存储位置是:$HOME \store\index${fileName},文件名fileName是以创建时的时间戳命名的,固定的单个IndexFile文件大小约为400M,一个IndexFile可以保存 2000W个索引,IndexFile的底层存储设计为在文件系统中实现HashMap结构,故rocketmq的索引文件其底层实现为hash索引
        • RocketMQ采用的是混合型的存储结构,即为Broker单个实例下所有的队列共用一个日志数据文件(即为CommitLog)来存储。RocketMQ的混合型存储结构(多个Topic的消息实体内容都存储于一个CommitLog中)针对Producer和Consumer分别采用了数据和索引部分相分离的存储结构,Producer发送消息至Broker端,然后Broker端使用同步或者异步的方式对消息刷盘持久化,保存至CommitLog中。只要消息被刷盘持久化至磁盘文件CommitLog中,那么Producer发送的消息就不会丢失。正因为如此,Consumer也就肯定有机会去消费这条消息。当无法拉取到消息后,可以等下一次消息拉取,同时服务端也支持长轮询模式,如果一个消息拉取请求未拉取到消息,Broker允许等待30s的时间,只要这段时间内有新消息到达,将直接返回给消费端。这里,RocketMQ的具体做法是,使用Broker端的后台服务线程—ReputMessageService不停地分发请求并异步构建ConsumeQueue(逻辑消费队列)和IndexFile(索引文件)数据。
      • 过期文件删除机制

        CommitLog、ConsumerQueue文件是基于内存映射机制并在启动的时候回加
        载CommitLog、ConsumerQueue目录下的所有文件,为了避免内存与磁盘的浪费,不可能将消息永
        久存储在消息服务器上,所以要引入一种机制来删除已过期的文件。RocketMQ顺序写CommitLog、
        ConsumerQueue文件,所有写操作全部落在最后一个CommitLog或者ConsumerQueue文件上,之前
        的文件在下一个文件创建后将不会再被更新。RocketMQ清除过期文件的方法时:如果当前文件在在一
        定时间间隔内没有再次被消费,则认为是过期文件,可以被删除,RocketMQ不会关注这个文件上的消
        息是否全部被消费。默认每个文件的过期时间为72小时,通过在Broker配置文件中设置
        fileReservedTime来改变过期时间,单位为小时。

    • 页缓存与内存映射

      • 零拷贝(mmap)

        • mmap将一个文件或者其它对象映射进内存。
          它本身提供了不同于一般对普通文件的访问方式,进程可以像读写内存一样对普通文件的操作。
          而Posix或System V的共享内存IPC则纯粹用于共享目的,当然mmap()实现共享内存也是其主要应用之一

          mmap将一个文件或者其它对象映射进内存。
          文件被映射到多个页上,如果文件的大小不是所有页的大小之和,最后一个页不被使用的空间将会清
          零。mmap在用户空间映射调用系统中作用很大,mmap()系统调用使得进程之间通过映射同一个普通文件实现共享内存

          普通文件被映射到进程地址空间后,进程可以像访问普通内存(ByteByffer)一样对文件进行访问,通
          过put和get进行访问不必再调用read(),write()等操作

    在这里插入图片描述

    • PageCache

      • 由内存中的物理page组成,其内容对应磁盘上的block
      • page cache的大小是动态变化的
      • backing store: cache缓存的存储设备
      • 一个page通常包含多个block, 而block不一定是连续的
    • 读Cache

    - 当内核发起一个读请求时, 先会检查请求的数据是否缓存到了page cache中
      - 如果有,那么直接从内存中读取,不需要访问磁盘, 此即 cache hit(缓存命中)
      - 如果没有, 就必须从磁盘中读取数据, 然后内核将读取的数据再缓存到cache中, 如此
        后续的读请求就可以命中缓存了
    - page可以只缓存一个文件的部分内容, 而不需要把整个文件都缓存进来
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 写Cache

      • 当内核发起一个写请求时, 也是直接往cache中写入, 后备存储中的内容不会直接更新
      • 内核会将被写入的page标记为dirty, 并将其加入到dirty list中
      • 内核会周期性地将dirty list中的page写回到磁盘上, 从而使磁盘上的数据和内存中缓存的数据
        一致
    • cache回收

      • Page cache的另一个重要工作是释放page, 从而释放内存空间
      • cache回收的任务是选择合适的page释放
        • 如果page是dirty的, 需要将page写回到磁盘中再释放
    • cache和buffer的区别

    • Cache:缓存区,是高速缓存,是位于CPU和主内存之间的容量较小但速度很快的存储器,因
      为CPU的速度远远高于主内存的速度,CPU从内存中读取数据需等待很长的时间,而 Cache
      保存着CPU刚用过的数据或循环使用的部分数据,这时从Cache中读取数据会更快,减少了
      CPU等待的时间,提高了系统的性能

      • Cache并不是缓存文件的,而是缓存块的(块是I/O读写最小的单元);Cache一般会用在I/O请求上,
        如果多个进程要访问某个文件,可以把此文件读入Cache中,这样下一个进程获取CPU控制权并访问此
        文件直接从Cache读取,提高系统性能
    • Buffer:缓冲区,用于存储速度不同步的设备或优先级不同的设备之间传输数据;通过buffer
      可以减少进程间通信需要等待的时间,当存储速度快的设备与存储速度慢的设备进行通信时,
      存储慢的数据先把数据存放到buffer,达到一定程度存储快的设备再读取buffer的数据,在此
      期间存储快的设备CPU可以干其他的事情。

      • Buffer:一般是用在写入磁盘的,例如:某个进程要求多个字段被读入,当所有要求的字段被读入
        之前已经读入的字段会先放到buffer中
    • HeapByteBuffer和DirectByteBuffer

      • HeapByteBuffer,是在jvm堆上面一个buffer,底层的本质是一个数组,用类封装维护了很多的
        索引(limit/position/capacity等)
      • DirectByteBuffer,底层的数据是维护在操作系统的内存中,而不是jvm里,DirectByteBuffer里维
        护了一个引用address指向数据,进而操作数据
      • HeapByteBuffer优点:内容维护在jvm里,把内容写进buffer里速度快;更容易回收

    RocketMQ同步异步复制

    • 同步复制
      • 同步复制方式是等Master和Slave均写 成功后才反馈给客户端写成功状态;
        在同步复制方式下,如果Master出故障,Slave上有全部的备份数据,容易恢复,但是同步复制会
        增大数据写入延迟,降低系统吞吐量。
    • 异步复制
      • 异步复制方式是只要Master写成功 即可反馈给客户端写成功状态。
        在异步复制方式下,系统拥有较低的延迟和较高的吞吐量,但是如果Master出了故障,有些数据因
        为没有被写 入Slave,有可能会丢失;
    • 实际应用中要结合业务场景,合理设置刷盘方式和主从复制方式, 尤其是SYNC_FLUSH方式,由于
      频繁地触发磁盘写动作,会明显降低性能。通常情况下,应该把Master和Save配置成ASYNC_FLUSH的
      刷盘 方式,主从之间配置成SYNC_MASTER的复制方式,这样即使有一台机器出故障,仍然能保证数据
      不丢,是个不错的选择。

    RocketMQ高可用机制

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3SkDWHRR-1660545962393)(img\image-20220815113429434-166053447090311.png)]

    • RocketMQ分布式集群是通过Master和Slave的配合达到高可用性的。
    • Master和Slave的区别
      • 在Broker的配置文件中,参数brokerId的值为0表明这个Broker是Master
      • 大于0表明这个Broker是Slave
      • brokerRole参数也说明这个Broker是Master还是Slave。
        (SYNC_MASTER/ASYNC_MASTER/SALVE)
      • Master角色的Broker支持读和写,Slave角色的Broker仅支持读
      • Consumer可以连接Master角色的Broker,也可以连接Slave角色的Broker来读取消息
    • 消息消费高可用
      • 在Consumer的配置文件中,并不需要设置是从Master读还是从Slave 读,当Master不可用或者繁
        忙的时候,Consumer会被自动切换到从Slave 读。
        有了自动切换Consumer这种机制,当一个Master角色的机器出现故障后,Consumer仍然可以从
        Slave读取消息,不影响Consumer程序。
        这就达到了消费端的高可用性
    • 消息发送高可用
      • 在创建Topic的时候,把Topic的多个Message Queue创建在多个Broker组上(相同Broker名称,
        不同brokerId的机器组成一个Broker组),这样既可以在性能方面具有扩展性,也可以降低主节点故障
        对整体上带来的影响,而且当一个Broker组的Master不可用后,其他组的Master仍然可用,Producer
        仍然可以发送消息的。

    RocketMQ刷盘机制

    RocketMQ 的所有消息都是持久化的,先写入系统 PageCache,然后刷盘,可以保证内存与磁盘
    都有一份数据, 访问时,直接从内存读取。消息在通过Producer写入RocketMQ的时候,有两种写磁
    盘方式,分布式同步刷盘和异步刷盘。

    • 同步刷盘

    在这里插入图片描述

    • 同步刷盘与异步刷盘的唯一区别是异步刷盘写完 PageCache直接返回,而同步刷盘需要等待刷盘
      完成才返回, 同步刷盘流程如下

      • 写入 PageCache后,线程等待,通知刷盘线程刷盘
      • 刷盘线程刷盘后,唤醒前端等待线程,可能是一批线程
      • 前端等待线程向用户返回成功
    • 异步刷盘

    在这里插入图片描述

  • 相关阅读:
    Arrays.asList()你真的知道怎么用吗?
    一个看似Circular view path的问题, 其实不是这个问题的问题
    3.Linux传统性能检测工具——vmstat
    分类预测 | MATLAB实现基于BiLSTM-AdaBoost双向长短期记忆网络结合AdaBoost多输入分类预测
    云原生安全系列2:关于镜像安全必须知道的事儿
    【Linux_TODO】
    JUC-线程池
    Web 性能测试
    Windows 11 中打印时提示打印机不兼容,都来是“+”惹的祸
    队列和栈两种数据结构的区别和Python实现
  • 原文地址:https://blog.csdn.net/qq_32168087/article/details/126346647