参考答案
RocketMQ 采用文件系统进行消息的存储,相对于 ActiveMq 采用关系型数据库进行存储的方式,更加直接、性能更高。
RocketMQ 与 Kafka 在写消息与发送消息上,继续沿用了Kafka 的这两个方面:顺序写、零拷贝。
1 顺序写
操作系统每次从磁盘读写数据时,都要找到数据在磁盘上的地址,再进行读写。如果是机械硬盘,寻址需要的时间往往会比较长。通常,把数据存储在内存上面,少了寻址的过程,性能就会好很多。
但是,Kafka 的数据存储在磁盘上面,依然性能很好,这是为什么呢?
原因是 Kafka 采用的是顺序写,直接追加数据到末尾。
实际上,磁盘顺序写的性能极高,在磁盘个数一定,转数一定的情况下,基本和内存速度一致。因此,磁盘的顺序写这一机制,极大地保证了 Kafka 本身的性能。
2 零拷贝
例如:读取文件,再用 Socket 发送出去的这个过程。
buffer = File.read Socket.send(buffer)
传统方式实现:先读取、再发送。
实际上,会经过以下四次复制:
- 将磁盘文件,读取到操作系统内核缓冲区 Read Buffer
- 将内核缓冲区的数据,复制到应用程序缓冲区 Application Buffer
- 将应用程序缓冲区 Application Buffer 中的数据,复制到socket网络发送缓冲区
- 将 Socket buffer 的数据,复制到网卡,由网卡进行网络传输
传统方式,读取磁盘文件并进行网络发送,经过的四次数据 copy ,操作非常繁琐。
重新思考传统 IO 方式,我们会注意到,在读取磁盘文件后,不需要做其他处理,直接用网络发送出去的这种场景下,第二次和第三次数据的复制过程,不仅没有任何帮助,反而带来了巨大的开销。
使用零拷贝,则直接由内核缓冲区 Read Buffer ,将数据复制到网卡,省去第二步和第三步的复制。
采用零拷贝的方式发送消息,必定会大大减少读取的开销,使得 RocketMQ 读取消息的性能有一个质的提升。
此外,还需要再提一点,零拷贝技术采用了 MappedByteBuffer 内存映射技术,采用这种技术有一些限制,其中有一条就是传输的文件不能超过 2G ,这也就是 RocketMQ 存储消息的文件 CommitLog 的大小规定为 1G 的原因。
总结:
RocketMQ 采用文件系统存储消息,并采用顺序写写入消息,使用零拷贝发送消息,极大得保证了 RocketMQ 的性能。
以上,是消息队列 RocketMQ 面试题【RocketMQ 的存储机制了解吗?】的参考答案。
输出,是最好的学习方法。
欢迎在评论区留下你的问题、笔记或知识点补充~
—end—