Broker架构设计

技术主题

技术原理

一:消息存储的设计理念

1、每个分区存储整个消息数据,尽管每个分区都是有序写入磁盘的,但随着并发写入分区的数量增加,从操作系统的角度来看,写入变成随机
2、由于数据文件分散,很难使用Linux IO Group Commit机制(追的是一次把多个数据文件写入磁盘。例如:批量发送3条数据,分散在3个文件中,做不到一次刷盘)

RocketMQ干脆另辟蹊径,设计一种新的文件存储方式,所有的Topic的所有的消息全部写在同一个文件中,保证绝对的顺序写。

优势:
1)队列轻量化,单个队列数据量非常少
2)对磁盘的访问串行化,完全顺序写,避免磁盘竞争,不会因为队列增加导致IOWAIT增高
如果想要为每个consumer group只查找自己的topic的offset信息,可以为每一个consumer group把他们消费的topic的最后消费到的offset单独存储在一个地方
也就是说,消息在Broker存储的时候,不仅写入commitlog,同时也把在commit log中的最新的offset写入对应的consume queue
消费者在消费消息的时候,先从consume queue读取持久化消息的起始物理位置的偏移量offset,大小size和消息Tag的HashCode值,随后从commit log中进行读取待拉取消费消息的真正实体内容部分。

总结:
1)写虽然完全是顺序写,但是读却变成了完全的随机读(commit log)
2)读一条信息,会先读comsume queue,再读commit log,增加了开销

2物理存储文件分析
文件名
1)checkpoint:文件检查点,存储commitlog、consumequeue、indexfile最后一次刷盘时间或时间戳
2)index:消息索引文件存储目录
3)consumequeue:消息消费队列存储目录
4)commitlog:消息存储目录
5)config:运行时的配置信息,包含主题消息过滤信息,集群消费模式消息消费进度,延迟消息队列拉去进度、消息消费组配置信息、topic配置属性等

(1)commit log
commit log,一个文件集合,每个默认文件1G大小。当第一个文件写满了,第二个文件会以初始偏移量命名。
跟kafka一样,commit log的内容是在消费后不会删除的
a、可以被多个consumer group重复消费,只要修改consumer group,可以从头消费,
b、支持消息回溯,随时可以搜索
(2)consume queue
consume queue:一个Topic可以有多个,每一个文件代表一个逻辑队列,这里存放消息在commit log的偏移值以及大小和Tag属性。
(3)index file
前面我们在使用api方法的时候,看到Message有一个keys参数,用来检索消息的,所以,如果出现了keys,服务端就会创建索引文件,以空格分割的每个关键字都会产生索引

HashMap,哈希索引,key设置为唯一不重复

二:RocketMQ存储关键技术(持久化/刷盘)

RocketMQ消息存储在磁盘上,如何做到这么低的延迟和这么高的吞吐,到底是如何实的?、
介绍Page Cache概念
1)CPU如果要读取或者操作磁盘上的数据,磁盘的数据加载到内存,由硬件的结构和访问速度的差异决定的
2)加载一个固定的单位,叫做Page。x86的linux中一个标准页面大小是4kb,如果提高磁盘的访问速度,或者尽量减少磁盘I/O,可以把访问过的Page在内存中缓存起来。区域是Page Cache。

PageCache本身也会对数据文件进行预读取,对于每个文件的第一个读请求操作,系统在读入所请求页面的同时会读入紧随其后的少数几个页面
虚拟内存分为内核空间和用户空间。PageCache属于内核空间,用户空间访问不了,因此读取数据还需要从内核空间拷贝到用户空间缓冲区
可以看到数据需要从Page Cache再经过一次拷贝程序才能访问得到。这个copy过程降低数据访问的速度。有什么方法能避免从内核空间到用户空间的copy呢?

避免从内核空间到用户空间的copy呢?
这里用到了一种零拷贝的技术
干脆把page Cache的数据在用户空间中做一个地址映射,这样用户进程就可以通过指针操作直接读写Page Cache,不再需要系统调用(read()和内存拷贝)
RocketMQ中具体实现的事使用mmap,无论是commitlog还是comsumerQueue都采用了mmap,kafka用的是sendfile

三:文件清理策略

跟kafka一样,RocketMQ中被消费过的消息是不会被删除的,所以保证了文件的顺序写入,如果不清理的话,文件数量不断增加,会导致磁盘的可用空间越来越少。
首先,主要清理是CommitLog,ConsumeQueue的过期文件

private void cleanFilesPeriodically() {
	this.cleanCommitLogService.run();
	this.cleanConsumeQueueService.run();
}

其次,什么情况下这些文件变成过期文件?默认是超过72个小时的文件

过期的文件什么时候删除呢?
有两种情况:
第一种情况:通过定时任务,每天凌晨4点,删除这些过期的文件

第二种情况:磁盘的空间使用率超过85%,批量清理文件,直到空间充足,超过95%,拒绝消息写入

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZhiguoXue_IT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值