消息的存储

commitlog 目录与文件

image.png

commitlog目录中存放着很多的mappedFile文件,当前Broker中所有的消息都是落盘到这些mappedFile文件中的,mappedFile文件大小为1G,文件名有20位十进制数据构成,表示当前文件的第一条消息的起始位偏移量。
需要注意的是,一个broker中仅仅包含一个commitlog目录,所有的mappedFile文件都是存放到该目录中的,即无论当前Broker中存放者多少topic的消息,这些消息都是被顺序写入到mappedFile文件中的,也就是说,这些消息在broker中存放时并没有按照topic进行分类存放。

消息单元

image.png

mappedFile文件内容由一个个消息单元构成,每个消息单元中包含消息总长度,消息的物理位置,消息体内容,消息体长度,消息主题,主题长度,消息生产者,消息发送时间戳,消息所在队列的ID,消息在queue中存储的偏移量queueoffset等近20余项消息相关属性。

consumequeue(消费队列)

consumequeue 中存放的是消息的索引


image.png

为了提高效率,会为每个topic在/store/consumequeue中创建一个目录,目录名称为topic名称,在该topic目录下,会再为每个topic的queue建立一个目录,目录名为queueID,每个目录中存放着若干consumequeue文件,consumequeue文件是commitlog的索引文件,可以根据consumequeue定位到具体的消息。
consumequeue文件名也是有20位数字组成,表示当前文件的第一个索引条目的启始位移偏移量,与mappedFile文件名不同的是,其后续文件名是固定的,因为consumequeue文件大小是固定不变的。

对文件的读写

image.png

消息写入

一条消息进入到Broker后经历以下几个过程才最终被持久化

  • Broker根据queueId,获取到该消息对应索引条目要在consumequeue目录中的写入偏移量,即QueueOffset
  • 将queueId,queueOffset等数据,与消息一起分装为消息单元
  • 将消息单元写入commitlog
  • 同时形成消息索引条目
  • 将消息索引条目发送到相应的consumequeue

消息拉取

当consumer来拉取消息的时候,会经历以下几个步骤:

  • consumer获取到其要消费消息所在的queue的消费偏移量offset(消费进度),计算出其要消费消息的offset
    注释:消费offset即消费的进度,consumer对某个Queue的消费offset,即消费到了该queue的第几条消息;消息offset就是消费offset + 1
  • consumer向broker发送拉取请求,其中会包含要拉取消息的queue,消息offset及消息tag
  • broker 计算在该consumequeue中的queueOffset
  • 从该queueOffset出开始向后查找第一个指定tag的索引目录
  • 解析该索引条目的前8个字节,即可定位到该消息在commitlog和commitlog offset
  • 从对应的commitlog offset中读取消息单元,并发送给consumer

消息的消费

消费者从Broker中获取消息的方式有两种,pull拉取方式和push推动方式。消费者组对于消息消费的模式又分为两种:集群消费和广播消费。


image.png

注意:广播模式下,相同的consumer group的每个consumer实例都会接收到同一个topic的全量消息,即每条消息都会发送到Consumer Group中的每个Consumer
集群模式下,相同的Consumer group的每个Consumer实例平均分摊同一个topic的消息,即每条消息只会发送到Consumer group中的某个Consumer


image.png

消费进度保存

  • 广播模式:消费进度保存在consumer端,因为广播模式下consumer group中每个consumer都会消费所有的消息,但他们的消费进度是不同,所以consumer各自保存各自的消费进度。
  • 集群模式:消费进度是保存在broker中,consumer group中的所有consumer共同消费同一个topic中消息,同一个消息只会被消费一次,消费进度会参与到消费的负载均衡中,固消费进度是需要共享的。

Rebalance 机制(提升消息的并行消费能力)

Rebalance 指的是,将一个topic下所有的queue在同一个consumer group中的多个consumer间进行重新分配的过程。


image.png
  • Rebalance 限制:
    由于一个队列最多分配给一个消费者,因此当某个消费者组下的消费者实例数量大于队列数量时,多余的消费者实例将分配不到任何队列
  • Rebalance 危害
    1. 消费暂停
      在只有一个consumer的时候,其负责消费所有的队列,在新增一个consumer后会触发Rebalance 发生,此时原consumer就需要暂停部分队列的消费,等到这些队列分配给新的consumer后,这些暂停的消费队列才能继续被消费
    2. 消费重复
      consumer在消费新分配给自己的队列时候,必须接着之前consumer提交的消费进度的offset继续消费,然而默认情况下,offset是异步提交的,这个异步性导致提交到broker的offset与consumer实际消费的消息并不一致,这个不一致的差值可能会重复消费消息。
    3. 消费突刺
      由于Rebalance 可能导致重复消费,如果需要重复消费的消息太多,后者因为Rebalance 暂停时间过长导致积压了部分消息,那么可能导致在Rebalance 结束后瞬间需要消费很多消息。
  • Rebalance 产生的原因:
    消费者所订阅的queue数量发生变化,或者消费者组中消费者的数量发生变化。

Queue分配算法:

  • 一个topic中的queue只能由consumer group中的一个consumer进行消费,而一个consumer可以同时消费多个queue中的消息。那么queue与consumer间的配对关系是如何确定的,即queue要分配给那个consumer进行消费,也是有算法策略的。常见的有四种策略,这些策略是通过在创建consumer的时的构造器传进去的。
  • 平均分配策略


    image.png

    该算法是根据avg = QueueCount/ConsumerCount的计算结果进行分配,如果能够整除,则按照顺序将AVG个queue逐个分配给consumer;如果不能整除,则将多余的queue按照consumer顺序逐个分配

  • 环形平均策略


    image.png

    环形平均算法策略是指,根据消费者顺序,一次在由queue队列组成的环形图中逐个分配。

  • 一致性hash策略(分配不均)


    image.png

    该算法会将consumer的hash值作为node节点存放到hash环上,然后将queue的hash值也放到hash换上,通过顺时针方向,距离queue最近的那个consumer就是该queue要分配的consumer

  • 同机房策略


    image.png

    该算法会根据queue的部署机房位置和consumer的位置,过滤出当前consumer相同机房的queue,然后按照平均分配策略或环形平均策略对同机房queue进行分配,如果没有同机房queue,则按照平均分配侧策略或者环形侧策略对所有queue进行分配。

重试队列

当rocketmq对消息的消费出现异常时候,会将发生异常消息的offset提交到broker中的重试队列,系统在发生消息消费异常时会为当前topic@group创建一个重试队列,该队列以%RETRY%开始,到达重试时间的时候重新消费。

你可能感兴趣的:(消息的存储)