RocketMQ核心知识原理

RocketMQ使用场景

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

RocketMQ架构

  • 架构图

    • 技术架构

RocketMQ核心知识原理_第1张图片

  • 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核心知识原理_第2张图片

  • 架构部署

RocketMQ核心知识原理_第3张图片

- **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建立连接通道,开始消费消息
  • 角色介绍

    • 消息模型(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核心消息存储原理

  • 消息存储

    RocketMQ核心知识原理_第4张图片

  • 息存储整体架构

    • 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()等操作

RocketMQ核心知识原理_第5张图片

  • PageCache

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

- 当内核发起一个读请求时, 先会检查请求的数据是否缓存到了page cache中
  - 如果有,那么直接从内存中读取,不需要访问磁盘, 此即 cache hit(缓存命中)
  - 如果没有, 就必须从磁盘中读取数据, 然后内核将读取的数据再缓存到cache中, 如此
    后续的读请求就可以命中缓存了
- page可以只缓存一个文件的部分内容, 而不需要把整个文件都缓存进来
  • 写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的时候,有两种写磁
盘方式,分布式同步刷盘和异步刷盘。

  • 同步刷盘

RocketMQ核心知识原理_第6张图片

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

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

RocketMQ核心知识原理_第7张图片

你可能感兴趣的:(Java服务端,java-rocketmq,rocketmq,java)