19 Broker持久化存储消息的原理
Posted 鮀城小帅
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了19 Broker持久化存储消息的原理相关的知识,希望对你有一定的参考价值。
1. Broker的重要性
Broker数据存储实际上才是MQ最核心的环节,它决定了生产者消息写入的吞吐量,决定了消息不能丢失,决定了消费者获取消息的吞吐量。
生产者发送到Broker的消息不可能都放在内存里,一旦机器宕机、重启,就会有消息丢失的问题。所以RocketMQ的Broker是需要将消息持久化到磁盘文件的。
2.Broker持久化消息到磁盘的原理
消息写入磁盘CommitLog文件
生产者发送的消息会直接写入磁盘上的日志文件 CommitLog。
CommitLog包含有很多磁盘文件,每个文件限定最多1GB,Broker收到消息之后就直接追加写入这个文件的末尾。如果一个CommitLog写满了1GB,就会创建一个新的CommitLog文件。
MessageQueue与offset偏移位置
在Broker中,对Topic下的每个MessageQueue会有一系列的ConsumeQueue文件,这些文件落在磁盘上。
ConsumeQueue文件的路径格式:$HOME/store/consumequeue/{topic}/{queueId}/{fileName}.
在上面的ConsumeQueue格式中,{topic}指的是某个Topic,{queueId}指的是某个MessageQueue。而在{fileName}这个文件中,它存储的就是一条消息对应在CommitLog文件中的offset偏移量。(一条消息的内容记录在CommitLog中,这条消息在CommitLog的哪个位置也就是偏移量offset记录在ConsumeQueue文件中)
场景说明:
上图中,Topic下有MessageQueue0和MessageQueue1两个在Broker上,他们分别对应Broker所在机器的磁盘上的ConsumeQueue0和ConsumeQueue1。
假设此时Topic为“TopicOrderPaySuccess”,那么Broker磁盘下的两个路径的文件为:
$HOME/store/consumequeue/TopicOrderPaySuccess/MessageQueue0/ConsumeQueue0磁盘文件
$HOME/store/consumequeue/TopicOrderPaySuccess/MessageQueue1/ConsumeQueue1磁盘文件
如果这时Broker收到一条消息写入了CommitLog之后,它同时会将这条消息在CommitLog中的物理位置,也就是一个文件偏移量,就是一个offset,写入到这条消息所属的MessageQueue对应的ConsumeQueue文件中去。
ConsumeQueue
在ConsumeQueue中存储的每条数据不只是消息在CommitLog中的offset偏移量,还包含了消息的长度,以及tag hashcode,一条数据是20个字节,每个ConsumeQueue文件保存30万条数据,大概每个文件是5.72MB。
3.消息写入CommitLog文件的底层原理
写入CommitLog的高性能
在RocketMQ中,消息写入磁盘CommitLog文件的性能近乎内存写性能。
PageCache和顺序写
Broker是基于OS操作系统的PageCache和顺序写两个机制,来提升写入CommitLog文件的性能的。
首先Broker是以顺序的方式将消息写入CommitLot磁盘文件的,也就是每次写入就是在文件末尾追加一条数据就可以了,对文件进行顺序写的性能要比文件随机写的性能提升很多。
另外,数据写入CommitLog文件的时候,其实不是直接写入底层的物理磁盘文件的,而是先进入OS的PageCache内存缓存中,然后后续由OS的后台线程选一个时间,异步化的将OS PageCache内存缓冲中的数据刷入底层的磁盘文件。
总结:整个优化采用的是 磁盘文件顺序写+OS PageCache写入+OS异步刷盘的策略。
4.异步刷盘与同步刷盘
异步刷盘
上述的模式就是异步刷盘模式,生产者把消息发送个Broker,Broker将消息写入OS PageCache中,就直接返回ACK给生产者了。
存在的弊端:如果生产者认为消息写入成功了,但是实际上那条消息此时是在Broker机器上的os cache中的,如果此时Broker宕机,必然导致这里的数据丢失,而Producer还以为数据已经写入成功了,这就有问题了。
总结:在异步刷盘的策略下,可以让消息写入吞吐量非常高。但是可能会有数据丢失的风险。
同步刷盘
同步刷盘模式下,生产者发送一条消息出去,broker收到了消息,必须直接强制把这个消息刷入底层的物理磁盘文件中,然后才会返回ack给producer,此时生产者才知道消息写入成功了。
如果brokerr还没有来得及把数据同步刷入磁盘,然后他自己挂了,那么此时对producer来说会感知到消息发送失败了,然后你只要不停地重试发送就可以了,直到有slave broker切换成 master broker重新让你可以写入消息,此时可以保证数据是不会丢失的。
同步刷屏的优缺点:如果强制每次消息写入都要直接进入磁盘中,必然导致每条消息写入性能急剧下降,导致消息写入吞吐量急剧下降,但是可以保证数据不会丢失。
5.应用场景
异步刷盘:日志场景,允许部分数据丢失,需要高吞吐
同步刷盘:订单场景,不需要高吞吐,需要保证数据不丢失
补偿机制:库存系统,库存明细可以采用异步刷盘,即使极端情况下数据丢失,也可以通过日志做数据的补偿。
小结:
生产者将消息发给Broker,Broker将消息写入CommitLog,每个CommitLog最多为1G,写完后,重新建一个。
每个Topic可以配置多个MessageQueue,每个MessageQueue都对应一系列的ConsumeQueue文件,ConsumeQueue文件中记录的是CommitLog消息的offset偏移量。通过ConsumeQueue中记录的offset偏移量定位到CommitLog中的消息。
Broker有2中刷盘策略:同步刷盘和异步刷盘。
同步刷盘是指broker收到消息后,必须强制将消息刷入磁盘,才返回ack给producer;异步刷盘是指broker收到消息后,将消息写入OS PageCache后就返回ack给producer。
同步刷盘消息写入性能低,但是可以保证消息不丢失;异步刷盘消息写入吞吐量高,但是消息可能会丢失。
CommitLog采用磁盘顺序写+OS PageCache写入+异步刷盘的方式达到近似内存的写入性能。
以上是关于19 Broker持久化存储消息的原理的主要内容,如果未能解决你的问题,请参考以下文章