引用: https://www.jianshu.com/p/d06e9bc6c463
RMQ采用顺序写,随机读
的设计理念:
- CommitLog顺序写,可以大大提高写人效率。
- 虽然是随机读,但是利用操作系统的pagecache机制,可以批量地从磁
盘读取,作为cache存到内存中,加速后续的读取速度。
消息存储结构
RocketMQ消息的存储是由ConsumeQueue
和CommitLog
配合完成的:
Commit Log
,消息真正的物理存储文件是CommitLog
,以物理文件的方式存放,所有消息内容全部持久化到这个文件中.Consume Queue
:ConsumeQueue
是消息的逻辑队列,类似数据库的索引文件
,这里存放消息在Commit Log的偏移值以及大小和Tag属性。
如果一个Topic要发送和接收的数据量非常大,需要能支持增加并行处理的机器来提高处理速度,这时候一个Topic可以根据需求设置一个或多个MessageQueue,Topic有了多个MessageQueue后,消息可以并行地向各个
MessageQueue发送,消费者也可以并行地从多个MessageQueue读取消息并消费。
Commit Log
: 文件地址:${user.home}/store/commitlog}${fileName}
.
Consume Queue
:文件地址在${storeRoot}\consumequeue\${topicName}\${queueld}\${fileName}
RMQ发送逻辑
写消息
发送时,Producer不直接与Consume Queue打交道,RMQ所有的消息都会存放在Commit Log中,为了使消息存储不发生混乱,对Commit Log进行写之前就会上锁。
消息持久被锁串行化后,对Commit Log就是顺序写,也就是常说的Append
操作。
RMQ的消息整体是有序的,所消息按顺序将内容持久化在Commit Log中。
Dispatch
Commit Log持久后,会将里面的数据Dispatch到对应的Consume Queue上。
读消息
消费逻辑底层
消费时,Consumer不直接与Commit Log打交道,而是从Consume Queue中去拉取数据.每一个Consume Queue都是顺序读
光拉取Consume Queue是没有数据的,里面只有一个对Commit Log的引用,所以再次拉取Commit Log。
例子
为了简述方便,来个例子:假如集群有一个Broker,Topic为binlog的队列(Consume Queue)数量为4,如下图所示,按顺序发送这5条内容各不相同消息。
Message msg1 = new Message("binlog", "order", "1001", "content 111".getBytes(RemotingHelper.DEFAULT_CHARSET));
Message msg2 = new Message("binlog", "inst", "1002", "content 222".getBytes(RemotingHelper.DEFAULT_CHARSET));
Message msg3 = new Message("binlog", "menu", "1003", "content 333".getBytes(RemotingHelper.DEFAULT_CHARSET));
Message msg4 = new Message("binlog", "menu", "1004", "content 444".getBytes(RemotingHelper.DEFAULT_CHARSET));
Message msg5 = new Message("binlog", "order", "1005", "content 555".getBytes(RemotingHelper.DEFAULT_CHARSET));
写消息
首先,RMQ的消息整体是有序的,所以这5条消息按顺序将内容持久化在Commit Log中。
dispatch
Consume Queue
consume queue record format