往RocketMq发送消息的底层原理

u=4190245608,2148235661&fm=11&gp=0.jpeg

1:为什么创建Topic的时候需要指定MessageQueue的数量

在我们给RocketMq发送消息的时候,首先就是要创建Topic,在创建Topic的时候需要指定一个很关键的参数,就是MeeageQueue, 简单的说就是要指定你这个Topic对应了多少个队列,下图中一个Topic就对应着4个MessageQueue

WeChat018b5acfcb3b2cd66b9ec29c519e2ed0.png
我们知道每个Topic中的数据都是分布式存储的,也就是说Topic中有一部分数据在Broker1上,有一部分数据在Broker2上

WeChat15ea43acb339f3cd571f2bd84c444a6a.png
但是我们如何决定将哪些数据放在对应的Broker上呢??所以在这里RocketMq就引入了MessageQueue概念,也就是数据分片机制

假设你现在有1万条数据,然后有二个Broker,4个MessageQueue,每个Broker有二个MessageQueue,这时候大致可以认为每个MessageQueue中有2500条数据,当然这个不是绝对的哈。
那么我们的数据是放到MessageQueue中了,那MessageQueue放在哪呢?? 当然是Broker上

WeChat26c1da863be66a2200921b3a36526900.png
这时候不同的数据都是存储在不同的Broker上的。这也是为什么RocketMq能实现海量数据存储的原理

2:生产者将消息写到哪个MessageQueue中

当我们要发送消息的时候,肯定要从NameServer路由中心去拿到Topic对应的有哪些Broker,拿到Broker也就可以拿到该Topic对应的所有的MessageQueue。这时候只需要根据不同的分法策略将消息发送到不同的MessageQueue就可以了

WeChat1e8def1167c94f0362f7160d59ec8eff.png

3:如果某个Broker发生故障了怎么办

如果某个Broker发生了故障,那么基于Dledger和Raft协议就会从多个Slave中进行选举新的Master,这个时候这个Broker是处于不可用的状态,如果这时候我们还往这个Broker发送消息那肯定是发送不成功的

WeChat37e8a3b736a392fc75675ca846517404.png
这时候我们可以打开生产者的一个开关,就是sendLatencyFaultEnable,一旦打开这个开关,就会有一个自动容错机制,就是当访问这个Broker的时候超出多少时间还没成功,那么就会隔一段时间不去访问这个Broker,等过一段时间,该Broker节点的主从切换成功之后,就又可以继续访问了

4:Broker是如何持久化数据的

当我们发送一条消息到RocketMq的时候,并不会马上被消费者消息,Broker会首先将该消息写入到一个CommotLog的磁盘文件中,CommitLog是磁盘中的一系列文件,当接收到一条消息之后,就会将这条消息顺序写入到CommitLog文件中,当这个文件大小达到1GB的时候,就会新创建一个CommitLog文件,继续写入消息。

可是我们之前说消息是发送到MessageQueue中的,在这里并没有体现出对MessageQueue的持久化。其实每一个MessageQueue都会对应着一个ConsumeQueue文件,这个ConsumeQueue对应的文件格式如下

$HOME/store/consumequeue/{topic}/{queueId}/{fileName}

我们知道每个Topic都会对应的Broker上的一些MessageQueue

    {topic}: 就是对应着哪个topic

    {queueId}: 就是就是代表某个Topic下的某个MessageQueue

    {fileName}: 就是文件名称了
复制代码

这样说吧,当我们发送一条消息到Broker之后,就会将该消息顺序写入CommitLog这个文件当中。

WeChat2dc9ee5f66780e1c7988311725f5a249.png

这时候这个Broker中有二个MessageQueue,分别是MessageQueue0,MessageQueue1,他们分别对应的ConsumeQueue0 , ConsumeQueue1

WeChat70c9fe446373274a3537854176f49476.png

假设现在Topic是order_topic,那么MessageQueue0和MessageQueue1对应的二个ConsumeQueue对应的文件格式如下:

$HOME/store/consumerqueue/order_topic/messagequeue0/consumequeue0磁盘文件

$HOME/store/consumequeue/order_topic/messagequeue1/consumequeue1磁盘文件

也就是说,当有消息发送到这二个MessageQueue之后,就会将消息写入到CommitLog文件当中,同时也会将这条消息在CommitLog文件中的偏移量和长度还有hashcode等信息存储到对应的ConsumeQueue文件中

WeChatb440e14897772a0406423199a43b0046.png
也就是说ConsumerQueue中存储的是消息的地址引用

WeChat5a1218e64c5eb8f58375454046fd35bd.png

5:如何提升CommitLog的写入性能

RocketMq会将消息写入到CommitLog这个磁盘文件当中,那么如何能够让写入的性能与写入内存的性能一样的??

RocketMq采用了 磁盘顺序写入+ OS PageCache + 异步刷盘机制来实现的

我们知道磁盘顺序写入的性能是比随机写入的性能好的,我们只需要在文件的末尾追加消息就行

RocketMq收到消息并不会直接将消息写入到底层的磁盘文件当中,而是会先写入到OS PageCache的缓存中,然后等待OS的后端线程定时的去执行刷盘操作

6:异步刷盘会有什么问题

现在我们知道RocketMq会将消息写入到OS PageCache的缓存中,然后让OS线程异步的去刷盘,也就是说有些数据还是在缓存中,并没有真正写入到底层磁盘中,如果这时候机器挂了,那么这些在缓存中的数据也是会丢失的。

所以这时候就有了同步刷盘机制。 也就是说RocketMq收到一条消息之后,会同步将这条消息写入到底层磁盘文件当中,然后在返回响应给客户端,这时候除非你硬盘坏了,一般情况下是不会丢失数据的,但是同步刷盘也会导致吞吐量降低,

异步刷盘:吞吐量高,性能好,存在丢失数据的风险
同步刷盘:吞吐量降低,性能较低,保证数据不丢失
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享