rocketmq python消息堆积_RocketMQ消息存储和查询原理

前言

RocketMQ 作为一款优秀的分布式消息中间件,可以为业务方提供高性能低延迟的稳定可靠的消息服务。其核心优势是可靠的消费存储、消息发送的高性能和低延迟、强大的消息堆积能力和消息处理能力。

从存储方式来看,主要有几个方面:文件系统

分布式KV存储

关系型数据库

从效率上来讲,文件系统高于KV存储,KV存储又高于关系型数据库。因为直接操作文件系统肯定是最快的,那么业界主流的消息队列中间件,如RocketMQ 、RabbitMQ 、kafka 都是采用文件系统的方式来存储消息。

今天,我们就从它的存储文件入手,来探索一下 RocketMQ 消息存储的机制。

CommitLog

CommitLog,消息存储文件,所有主题的消息都存储在 CommitLog文件中。

我们的业务系统向 RocketMQ 发送一条消息,不管在中间经历了多么复杂的流程,最终这条消息会被持久化到CommitLog文件。

我们知道,一台Broker服务器只有一个CommitLog文件(组),RocketMQ会将所有主题的消息存储在同一个文件中,这个文件中就存储着一条条Message,每条Message都会按照顺序写入。

2822302e7f8315cc797044ee06e8b0df.png

也许有时候,你会希望看看这个 CommitLog 文件中,存储的内容到底长什么样子?

1、消息发送

当然,我们需要先往 CommitLog 文件中写入一些内容,所以先来看一个消息发送的例子。public static void main(String[] args) throws Exception{

MQProducer producer = getProducer();

for (int i = 0;i<10;i++){

Message message = new Message();

message.setTopic("topic"+i);

message.setBody(("清幽之地的博客").getBytes());

SendResult sendResult = producer.send(message);

}

producer.shutdown();

}

我们向10个不同的主题中发送消息,如果只有一台Broker机器,它们会保存到同一个CommitLog文件中。此时,这个文件的位置处于C:/Users/shiqizhen/store/commitlog/00000000000000000000。

2、读取文件内容

这个文件我们不能直接打开,因为它是一个二进制文件,所以我们需要通过程序来读取它的字节数组。public static ByteBuffer read(String path)throws Exception{

File file = new File(path);

FileInputStream fin = new FileInputStream(file);

byte[] bytes = new byte[(int)file.length()];

fin.read(bytes);

ByteBuffer buffer = ByteBuffer.wrap(bytes);

return buffer;

}

如上代码,可以通过传入文件的路径,读取该文件所有的内容。为了方便下一步操作,我们把读取到的字节数组转换为java.nio.ByteBuffer对象。

3、解析

在解析之前,我们需要弄明白两件事:消息的格式,即一条消息包含哪些字段;

每个字段所占的字节大小。

在上面的图中,我们已经看到了消息的格式,包含了19个字段。关于字节大小,有的是 4 字节,有的是 8 字节,我们不再一一赘述,直接看代码。/**

* commitlog 文件解析

* @param byteBuffer

* @return

* @throws Exception

*/

public static MessageExt decodeCommitLog(ByteBuffer byteBuffer)throws Exception{

MessageExt msgExt = new MessageExt();

// 1 TOTALSIZE

int storeSize = byteBuffer.getInt();

msgExt.setStoreSize(storeSize);

if (storeSize<=0){

return null;

}

// 2 MAGICCODE

byteBuffer.getInt();

// 3 BODYCRC

int bodyCRC = byteBuffer.getInt();

msgExt.setBodyCRC(bodyCRC);

// 4 QUEUEID

int queueId = byteBuffer.getInt();

msgExt.setQueueId(queueId);

// 5 FLAG

int flag = byteBuffer.getInt();

msgExt.setFlag(flag);

// 6 QUEUEOFFSET

long queueOffset = byteBuffer.getLong();

msgExt.setQueueOffset(queueOffset);

// 7 PHYSICALOFFSET

long physicOffset = byteBuffer.getLong();

msgExt.setCommitLogOffset(physicOffset);

// 8 SYSFLAG

int sysFlag = byteBuffer.getInt();

msgExt.setSysFlag(sysFlag);

// 9 BORNTIMESTAMP

long bornTimeStamp = byteBuffer.getLong();

msgExt.setBornTimestamp(bornTimeStamp);

// 10 BORNHOST

int bornhostIPLength = (sysFlag & MessageSysFlag.BORNHOST_V6_FLAG) == 0 ? 4 : 16;

byte[] bornHost = new byte[bornhostIPLength];

byteBuffer.get(bornHost, 0, bornhostIPLength);

int port = byteBuffer.getInt();

msgExt.setBornHost(new InetSocketAddress(InetAddress.getByAddress(bornHost), port));

// 11 STORETIMESTAMP

long storeTimestamp = byteBuffer.getLong();

msgExt.setStoreTimestamp(storeTimestamp);

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值