Kafka凭啥这么快
kakfa是什么?Kafka的架构原理和应用场景是什么?
RocketMQ是什么?为什么RocketMQ性能不如Kafka?
RocketMQ 和 Kafka 怎么选?
零拷贝是什么?
mmap是什么?
sendfile是什么?
RocketMQ为什么不使用sendfile?
1. Kafka 为何没有被 RocketMQ 替代?
RocketMQ 相比于 Kafka, 简化了架构, 丰富了功能, 却依旧没能取代 Kafka, 那么 RocketMQ 一定有不如 Kafka 的地方
性能 & 吞吐量
- RocketMQ: 1w/s Proc
- Kafka: 17w/s Proc
2. 零拷贝是什么?
我们知道消息队列的消息为了防止进程崩溃后,一般不会放内存里,而是放磁盘上。
消息发送过程
操作系统分为内核空间和用户空间,程序处于用户空间,而磁盘属于硬件;
操作系统本质上是程序和硬件设备的一个中间层程序,程序需要通过操作系统去调用硬件能力。
+-------------+
| Program | +---------+
+-------------+ | Program |
+-+---------+-+
+-------------+ ------>| User Space |
| |------/ +-------------+
| OS |
| |------\ +---------------+
+-------------+ ------>| Kernel Space |
+---------------+
+-------------+
| Hardware |
+-------------+
如果用户想要将数据从磁盘发送到网络,那么就会发生下面这几件事
+-----------------------------+
| |
User | read() write() |
Space | user buffer |
| ^ \ |
+---------/-------\-----------+
socket | / \ |
+-------/-----------\---------+
| / \ |
Kernal | / v |
Space |kernal buffer socket buffer|
| ^ \ |
+--/---------------------\----+
/ v
disk NIC
- 程序发起系统调用 read() 将磁盘数据从设备拷贝到内核空间的缓冲区
- 从内核空间的缓冲区拷贝到用户空间
- 程序在发起系统调用 write() 将数据从用户空间拷贝到 socket 的发送缓冲区
- 再从 socket 的发送缓冲区拷贝到网卡
- 最终数据会会经过网络到达消费者
整个过程本机内发生了两次系统调用: read()/write()
对应四次用户空间到内核空间切换: read 调用/返回, write 调用/返回
以及四次数据拷贝
优化
零拷贝技术常见的方案有两种,分别是 mmap 和 sendfile
mmap
mmap 是操作系统内核提供的一个方法,以将内核空间的缓冲区映射到用户空间
+-----------------------------+
| |
User |mmap() write() |
Space | user buffer |
| ^ |
+---------/-------------------+
socket | map |
+-------/---------------------+
| / |
Kernal | v socket |
Space |kernal buffer <------>buffer |
| ^ | |
+--/----------------------|---+
/ v
disk NIC
- 程序发起系统调用 mmap() 将磁盘数据从设备拷贝到内核空间的缓冲区,
- 内核空间的缓冲区,映射到用户空间
- 这里不需要拷贝程序,再发起系统调用 write(), 数据从内核空间缓冲区拷贝到 socket 发送缓冲区
- 从 socket 发送缓冲区拷贝到网卡
mmap 作为一种零拷贝技术,指的是用户空间到内核空间,这个过程不需要拷贝整个过程本机内发生了两次系统调用: mmap()/write()
对应四次用户空间到内核空间切换: mmap 调用/返回, write 调用/返回
以及 三次数据拷贝
对比之前, 省下一次内核空间到用户空间的拷贝
sendfile
sendfile 也是内核提供的一个方法, 就是用来发送文件数据的
+-----------------------------+
| |
User | |
Space | sendfile() |
| |
+-----------------------------+
socket | |
+-----------------------------+
| |
Kernal | kernal buffer |
Space | ^ \ |
| / SG-DMA |
+------/--------------\-------+
/ v
disk NIC
- 程序发起系统调用 sendfile 内核会将数据从磁盘设备拷贝到内核空间的缓冲区
- 内核空间缓冲区里的数据可以直接拷贝到网卡
sendfile 作为一种零拷贝技术,指的是零 CPU 拷贝整个过程发生了一次系统调用,对应两次用户空间和内核空间的切换: sendfile 调用/返回
以及 两次数据拷贝
sendfile 场景下需要的两次拷贝都不是 CPU 直接参与的拷贝,而是 DMA 控制器在干活
Kafka 为什么性能比 RocketMQ 好?
这是因为 RocketMQ 使用的是 mmap 技术, 而 kafka 使用的是 sendfile; kafka 以更少的拷贝次数以及系统内核切换次数获得了更高的性能。
为什么 RocketMQ 不使用 sendfile?
sendfile 函数长啥样
int sendfile(int out_fd, in_fd, off_t* offset, int count);
// num = sendfile(xxx);
sendfile 返回的则是成功发送了几个字结束,具体发了什么内容,应用层根本不知道。
mmap 函数长啥样
void *mmap(void *addr, int length, prot, flags, fd, off_t offset);
// buf = mmap(xxx);
mmap 返回的是数据的具体内容,应用层能获取到消息内容,并进行一些逻辑处理。
总结
而 RocketMQ 的一些功能,却需要了解具体的消息内容,方便二次投递的,比如将消费失败的消息重新投递到死性队列中。
如果 RocketMQ 使用 sendfile,那根本没机会获取到消息内容长什么样子,也就没办法实现一些好用的功能了,而 kafka 却没有这些功能特性,除求极致性能正好可以使用。