根据资料显示RocketMQ每秒能处理10W量级数据,而Kafka能处理17W量级数据。
- 这两者差别主要再使用的零拷贝技术不一样。
再什么情况下零拷贝技术诞生了
为了防止消息队列中的消息因为各种意外情况丢失,要对消息进行持久化处理,将其存储在磁盘当中。在传统的I/O工作方式中发送消息要经历多次的状态改变和消息拷贝。
从图中可以看到有四次数据拷贝,两次系统调用(),四次状态的切换。对于一个消息的发送需要这么多次拷贝一样的数据。
DMA技术:
之前这些拷贝都需要CPU全程参与,导致再数据传输期间CPU无法完成其他任务。那么如果再大量传输数据时,那么CPU就不用干其他事情了,就一直干着拷贝数据的活,那不完犊子了。所以就有了DMA技术(直接内存访问技术),它允许磁盘等外部硬件设备直接与主内存进行数据交换,而无需中央处理器(CPU)的干预。减低了CPU的负担,此时只需要CPU在 DMA 传输开始之前,设置好 DMA 控制器。这通常涉及到指定源地址、目标地址以及要传输的数据量。后面就由DMA自己控制拷贝就好了。
零拷贝技术实现方式:
1、mmap技术
mmap是操作系统提供的一个内核方法,可以将内核缓冲区映射到用户空间,这样子就可以直接通过操作用户空间映射的部分直接操作内核缓冲区中的消息。就无需将内核缓冲区的数据拷贝到用户缓冲区后再将其拷贝到Socket缓冲区。
映射:页表指向同一块内核地址。
但这个过程还是需要三次的拷贝、四次的状态的切换和两次的系统调用。
2、sendfile技术
sendfile也是内核提供的一个方法,从名字就可以看出它的作用就是发送文件。从发生方法调用开始,由用户态转化为内核态,并将磁盘内的数据拷贝到内核缓冲区,然后直接将内核缓冲区中的数据拷贝到网卡当中,进行消息发送。当然这个直接将内核缓冲区数据直接拷贝到网卡的过程要是 网卡支持SG-DMA技术。
这样子只需要进行一次系统调用、两次拷贝和两次状态转换。
而Kafka使用的就是sendfile(),RocketMQ使用的就是mmap()技术。
为什么RocketMQ不也使用sendfile()技术呢?
sendfile()方法成功时返回已传输的字节数。
int sendfile(int out_fd, in_fd, off_t* offset, int count);
//out_fd:被拷贝文件描述符
//in_fd:拷贝目的文件描述符
//offset: 被拷贝文件偏移量
//count:被拷贝数据长度
mmap()方法返回的是一个指向映射区域的指针。
void * mmap(void*addr,int length,prot,flags,fd,off_t offset);
mmap返回的值可以让应用层获取到消息内容,可以进行一些逻辑处理,但sendfile返回的只是已经传输的字节数,具体发送了什么内容,内容层无法得知。而RocketMQ的一些功能需要具体了解到发送了什么消息才能实现(二次投递)。而Kafka主要追求吞吐量,也就不需要这些独特的功能,所以选择sendfile()文件,以达到更高的吞吐量。
所以不同消息队列都有自己的特征,并不是说Kafka的架构就比RocketMQ比好,而是他们各自的选择。