今天抽空给大家整理了一份关于RocketMQ的高性能知识点文章总结。希望能对各位读者有所帮助。
关于RockeMQ的基本介绍
简介
RocketMQ是一个纯Java、分布式、队列模型的开源消息中间件,前身是MetaQ,是阿里参考Kafka特点研发的一个队列模型的消息中间件,后开源给apache基金会成为了apache顶级开源项目,具有高性能、高可靠、高实时、分布式特点。
发展背景
-
2011年:业界出现了现在被很多大数据领域所推崇的Kafka消息引擎,阿里巴巴在研究了Kafka的整体机制和架构设计之后,基于Kafka的设计使用Java进行了完全重写并推出了MetaQ 1.0版本,主要是用于解决顺序消息和海量堆积的问题。
-
2012年:阿里巴巴开源其自研的第三代分布式消息中间件——RocketMQ。
-
2016年11月:阿里将RocketMQ捐献给Apache软件基金会,正式成为孵化项目。
-
2017年2月20日:RocketMQ正式发布4.0版本,专家称新版本适用于电商领域,金融领域,大数据领域,兼有物联网领域的编程模型。
-
2022年:RocketMQ正式发布5.0版本,这也是目前最新版本。
RocketMQ的各个特点
-
单机吞吐量:10w/s。
-
可用性:支持双主双从的分布式架构,具备高可用特性。支持使用topic,tag,SQL来对消息进行筛选。底层结构通过多队列来承载消息存储等特性。可靠的FIFO和严格有序的消息队列中间件。支持多种消息传递协议,例如grpc,Mqtt,Jms....
-
源码实现:Java语言。
PageCache和Mmap
RocketMQ这款中间件具有着单机10w+的吞吐量,其底层原因,实际上得从操作系统原理开始和大家讲起。
顺序写入
磁盘的写步骤通常是:CPU发送一个写信号给到磁盘磁头,接着磁头需要进行寻道操作,找到对应的磁道后,定位对应的位置进行数据写入。所以如果数据是随机写入的话,磁头就需要频繁地切换盘道进行数据的写入,整体耗时会有所提升。
顺序写,其实是一种非常常见的提升IO写性能的方式,利用连续的写入地址,从而减少磁头的切换次数,提升性能。
PageCache
为了提升对文件的读写效率,Linux 内核会以页大小(4KB)为单位,将文件划分为多数据块。当用户对文件中的某个数据块进行读写操作时,内核首先会申请一个内存页(称为 页缓存)与文件中的数据块进行绑定。
例如下边这张图,当我们发起一次系统调用的write方法,想要将用户态中的数据写入磁盘的时候,其实是需要发生以下操作的:
首先,将用户地址空间的数据通过CPU拷贝,放入到内核空间中,并且写入一个PageCache里面,然后通过DMA去将PageCache的数据写入到磁盘。
这里面由于有CPU拷贝这样的重操作,所以想要提升吞吐量,必须解决这个问题。而RocketMQ的创作团队,则是通过mmap技术来解决了它。
什么是mmap
mmap系统调用,让用户地址空间,跟文件做映射(实际是指向不存在的物理内存)。将内核态的一段空间地址映射到了用户态中,这样数据只需要写入到用户态的这段虚拟地址中,接着内核空间的DMA会将这段数据写入到磁盘中。这样之后,整体的写入流程就如下图所示:
使用mmap技术之后,可以减少一次的CPU拷贝次数,提升性能。
这里补充一些说明,其实DMA本质上是一块访问独立的芯片。由于每次访问磁盘进行IO操作都会导致CPU大量的空闲时间,而DMA则是用于提升IO操作效率的一个角色,主要用于IO的数据传输,降低CPU等待时间。
Java里面如何使用mmap技术
在Java语言中,其实很早就有提供mmap方面的api了,下边是一段简单的mmap使用案例。
public class MmapUtils {
public File commitLogFile;
public MappedByteBuffer mappedByteBuffer;
public int mappedSize = 0;
public int writePos = 0;
public MmapUtils(String commitLogPath, int mappedSize) {
this.commitLogFile = new File(commitLogPath);
if(!commitLogFile.ex