深入理解RocketMQ是如何做到高性能的

1、RocketMQ的核心Broker​

对rocketmq稍有了解的同学,都知道它主要由4部分组成,Producer、Consumer、Broker、NameServer。

Broker作为Rocket MQ的核心,提供了强大的数据存储能力,可以把亿万级的消息存储在服务器磁盘上。它决定了生产者写入的吞吐量,决定了消息不能丢失,决定了消费者消费消息的吞吐量。

​2、消息写入磁盘文件:CommitLog​

当生产者的消息发送到一个Broker上的时候,它接收到了一条消息,会对这个消息做什么处理?

首先第一步,他会把这个消息直接写入磁盘上的一个日志文件,没错就是磁盘文件,它叫做CommitLog,直接顺序写入这个文件,如下图。

图1 消息顺序写入CommitLog文件

这个CommitLog文件默认大小是1G,如果消息很多的话,可能会创建很多个CommitLog文件。

CommitLog文件的文件名长度为20位,左边补零,剩余为起始偏移量,比如00000000000000000000代表了第一个文件,起始偏移量为0,文件大小为1G=1073741824;当第一个文件写满了,第二个文件为00000000001073741824,起始偏移量为1073741824,以此类推。

图2 CommitLog文件

Broker收到消息后,直接追加到这个文件的末尾。

3、消息的偏移量写入磁盘文件:ConsumeQueue​

我们知道每个Topic可能对应了多个Queue,那么这些Queue在Broker中是如何体现的呢?

其实在Broker中,每个Topic下的每个Queue都会对应一些列的ConsumeQueue文件。

图3 Broker本地存储文件

就是在Broker磁盘上,会有下面这种格式的一些列文件:

~/store/consumequeue/{topic}/{queueId}/{fileName}

{topic}指代的就是某个Topic,{queueId}指代的就是某个MessageQueue。

然后存储在这台Broker机器上的Topic下的一个MessageQueue,他有很多的ConsumeQueue文件,这个ConsumeQueue文件里存储的是一条消息对应在CommitLog文件中的offset​偏移量​。

这点比较重要,ConsumeQueue不存储真实的消息数据,只存消息数据在CommitLog文件中的偏移量。

假设有一个Topic,他有4个Queue,然后分布在两台Broker机器上,每台Broker机器会存储两个Queue。

此时生产者选择对其中一个Queue写入了一条消息,此时消息会发送到Broker上。

然后然后Broker会把这个消息写入CommitLog文件中,同时会把消息的偏移量写入两个ConsumeQueue中,ConsumeQueue0和ConsumeQueue1。它们分别对应着Topic里的Queue0和Queue1。

图4 消息偏移量写入ConsumeQueue文件中

也就是说,Topic下的Queue0和Queue1就放在这个Broker机器上,而它们每个在磁盘上对应了一个ConsumeQueue文件,所以就是Queue0对应着Broker磁盘上的ConsumeQueue0,Queue1对应着磁盘上的ConsumeQueue1。

假设Queue的名字叫做:TopicOrderInfo,Queue0的id是0,Queue1的id是1,那么此时在Broker磁盘上应该有如下两个路径的文件:

~/store/consumequeue/TopicOrderInfo/0/ConsumeQueue0文件

~/store/consumequeue/TopicOrderInfo/1/ConsumeQueue1文件

图5 ConsumeQueue本地磁盘文件

然后,当你的Broker收到一条消息写入了CommitLog之后,其实他同时会将这条消息在CommitLog中的物理位置,也就是一个文件偏移量(offset),写入到这条消息所属的Queue对应的ConsumeQueue文件中去。

ConsumeQueue文件存在的目的就是可以快速定位到消息真实的物理位置,在ConsumeQueue中存储的每条数据不只是消息在CommitLog中的offset偏移量,还包含了消息的长度,以及tag hashcode,一条数据是20个字节,每个ConsumeQueue文件保存30万条数据,所以计算下来每个文件是5.72MB。

需要注意的是每个Topic的每个Queue都对应了Broker机器上的多个ConsumeQueue文件,保存了这个MessageQueue的所有消息在CommitLog文件中的物理位置,也就是offset偏移量。

​4、RocketMQ是如何提升CommitLog写入性能的?​

CommitLog作为存储消息的核心所在,关乎着整个消息队列的吞吐量。那么Broker是如何提升整个过程的性能的呢?

Broker是基于OS操作系统的PageCache和顺序写两个机制,来提升写入CommitLog文件的性能的。

首先Broker是以顺序的方式将消息写入CommitLog磁盘文件的,也就是每次写入就是在文件末尾追加一条数据就可以了,对文件进行顺序写的性能要比对文件随机写的性能提升很多。

另外,消息写入CommitLog文件的时候,并不是直接写入磁盘文件的,而是先进入OS的PageCache内存缓存中,然后再由OS的后台线程选一个时间,异步化的将OS PageCache内存缓冲中的数据刷入底层的磁盘文件。

图6 异步刷盘CommitLog文件

在采用磁盘文件顺序写+OS PageCache写入+OS异步刷盘的策略,基本上可以让消息写入CommitLog的性能接近直接写入内存,所以正是如此,才可以让Broker高吞吐的处理每秒大量的消息写入。

​5、异步刷盘的利弊​

很多时候鱼和熊掌不可兼得,我们充分提升性能的同时,就会牺牲一些高可用性。

如果生产者认为消息写入成功了,但是实际上那条消息此时是在Broker机器上的os cache中的,如果此时Broker直接宕机,那么是不是os cache中的这条数据就会丢失了?

所以异步刷盘的的策略下,可以让消息写入吞吐量非常高,但是可能会有数据丢失的风险。

所以rocketmq提供了同步刷盘,让使用者可选择。如果你使用同步刷盘模式的话,那么生产者发送一条消息出去,broker收到了消息,必须直接强制把这个消息刷入底层的物理磁盘文件中,然后才会返回ack给producer,此时你才知道消息写入成功了。

但是如果你强制每次消息写入都要直接进入磁盘中,必然导致每条消息写入性能急剧下降,导致消息写入吞吐量急剧下降,但是可以保证数据不会丢失。具体如何选择,还需要看你的业务场景。

转载自:https://blog.51cto.com/u_13626762/5022177

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值