1、何时存储消息
producer发送到mq中,然后Comsumer去消费,mq为了保证工作效率,所有的消息肯定是在内存中去中转的,那么就有个问题,一断电,内存中的消息就丢失了,肯定得有个方式需要把消息存到硬盘中.
- MQ收到消息之后会给producer一个响应,然后给消息存到硬盘里面
- MQ给消息推送给consumer之后也会等待consumer给MQ的响应,MQ收到了consumer的成功消费的响应,那么MQ肯定是不会再推这个消息了 ,肯定得有个标记,去标记这个队列里面的消息消费情况
- MQ会定期删除一些过期的消息,如果不删除的话,消息会越积越多.肯定是得定期删除保存消息的文件.
配置文件删除策略
在conf的broker.properties 文件上修改
#删除文件时间点,默认凌晨 4点
deleteWhen=04
#文件保留时间,默认 48 小时
fileReservedTime=120
2、消息存储介质
如果让你设计一个消息存储的功能,很多人可能会想到用redis或者MySQL去存储,但是这些工具都有个特点,就是对数据存盘做了索引,但是索引的建立和维护都有开销的.所以我们的MQ都采用更直接的方式,直接用文件来存储.
RocketMQ采用的是类似于Kafka的文件存储机制,即直接用磁盘文件来保存消息,而不需要借助MySQL这一类索引工具。
可能有些人会角色用文件存储,这样肯定性能是很慢的,其实MQ对文件也进行了优化,就是用了顺序写机制
顺序写机制就是会提前在磁盘申请出一片地方,所有的文件一个一个的往上面写就行了,
而一般的文件写是随机写的,我们的磁盘有些地方有文件,有些地方没文件,操作系统在写文件的时候要找一片地方,找一个扇区,找的过程就是随机写,所以随机写的效率是很低的.
2.1磁盘保存文件慢吗?
磁盘如果使用得当,磁盘的速度完全可以匹配上网络 的数据传输速度。目前的高性能磁盘,顺序写速度
可以达到600MB/s, 超过了一般网卡的传输速度。但是磁盘随机写的速度只有大概100KB/s,和顺序写
的性能相差6000倍!因为有如此巨大的速度差别,好的消息队列系统会比普通的消息队列系统速度快多
个数量级。RocketMQ的消息用顺序写,保证了消息存储的速度。
2.2零拷贝技术加速文件读写
Linux操作系统分为【用户态】和【内核态】,文件操作、网络操作需要涉及这两种形态的切换,免不
了进行数据复制。
一台服务器 把本机磁盘文件的内容发送到客户端,一般分为两个步骤:
1)read;读取本地文件内容;
2)write;将读取的内容通过网络发送出去。
这两个看似简单的操作,实际进行了4 次数据复制,分别是:
- 从磁盘复制数据到内核态内存;
- 从内核态内存复 制到用户态内存;
- 然后从用户态 内存复制到网络驱动的内核态内存;
- 最后是从网络驱动的内核态内存复 制到网卡中进行传输。
而通过使用mmap的方式,可以省去向用户态的内存复制,提高速度。这种机制在Java中是通过NIO包
中的MappedByteBuffer实现的。RocketMQ充分利用了上述特性,也就是所谓的“零拷贝”技术,提高
消息存盘和网络发送的速度。
零拷贝用两种技术
关于零拷贝,JAVA的NIO中提供了两种实现方式,mmap和sendfile,其中mmap适合比较小的文件,而sendfile适合传递比较大的文件。
mmap的缺点就是文件不能太大,如果文件太大就不行.MappedByteBuffer使用的是mmap技术
这里需要注意的是,采用MappedByteBuffer这种内存映射的方式有几个限制,其中之一是一次只能映射1.5~2G 的文件至用户态的虚拟内存,
而RocketMQ为了适应mmap,每个CommitLog日志的设计的时候都是固定一个G的大小.