所有分类
  • 所有分类
  • 未分类

RocketMQ–为什么性能不如Kafka?

简介

本文介绍RocketMQ为什么性能不如Kafka?

阿里中间件团队对它们做过压测,同样条件下,kafka 比 RocketMQ 快 50% 左右。

为什么 RocketMQ 参考了 Kafka 的架构,却不能跟 kafka 保持一样的性能呢?

读消息的方式

为了防止消息队列的消息丢失,一般不会放内存里,而是放磁盘上。消息从消息队列的磁盘,发送到消费者,过程是怎样的呢?

传统方式(比如:RabbitMQ)

如果用户想要将数据从磁盘发送到网络。那么就会发生下面这几件事:

程序会发起系统调用read(),尝试读取磁盘数据:

  • 磁盘数据从设备拷贝到内核空间的缓冲区
  • 再从内核空间的缓冲区拷贝到用户空间

程序再发起系统调用write(),将读到的数据发到网络:

  • 数据从用户空间拷贝到 socket 发送缓冲区
  • 再从 socket 发送缓冲区拷贝到网卡

最终数据就会经过网络到达消费者。

整个过程,本机内发生了 2 次系统调用,对应 4 次用户空间和内核空间的切换,以及 4 次数据拷贝

上边传统方式一份数据来回拷贝,有没有办法优化呢?有:零拷贝技术,常见的方案有两种,分别是 mmap 和 sendfile。

零拷贝(mmap)

RocketMQ用的是mmap方式。

mmap 是操作系统内核提供的一个方法,可以将内核空间的缓冲区映射到用户空间。

用了它,发送流程就有了变化。程序发起系统调用mmap(),尝试读取磁盘数据,具体情况如下:

  • 磁盘数据从设备拷贝到内核空间的缓冲区。
  • 内核空间的缓冲区映射到用户空间,这里不需要拷贝。

程序再发起系统调用write(),将读到的数据发到网络:

  • 数据从内核空间缓冲区拷贝到 socket 发送缓冲区。
  • 再从 socket 发送缓冲区拷贝到网卡。

发生了 2 次系统调用,对应 4 次用户空间和内核空间的切换,以及 3 次数据拷贝,对比之前,省下一次内核空间到用户空间的拷贝。 

不是说零拷贝吗,怎么还有 3 次拷贝?mmap 作为一种零拷贝技术,指的是用户空间到内核空间这个过程不需要拷贝,而不是指数据从磁盘到发送到网卡这个过程零拷贝。

确实省了一点,但不多。有没有更彻底的零拷贝?有,用 sendfile。

零拷贝(sendfile)

Kafka的零拷贝用的是sendfile

sendfile,也是内核提供的一个方法,从名字可以看出,就是用来发送文件数据的。程序发起系统调用sendfile(),内核会读取磁盘数据然后发送,具体情况如下:

  • 磁盘数据从设备拷贝到内核空间的缓冲区。
  • 内核空间缓冲区里的数据可以直接拷贝到网卡。

发生了 1 次系统调用,对应 2 次用户空间和内核空间的切换,以及 2 次数据拷贝。

说好的拷贝怎么还有 2 次拷贝? 

这里的零拷贝指的是零 CPU拷贝。也就是说 sendfile 场景下,需要的两次拷贝,都不是 CPU 直接参与的拷贝,而是其他硬件设备(DMA)做的拷贝,不耽误我们 CPU 跑程序。

为什么RocketMQ不用Sendfile?

mmap 返回的是数据的具体内容,应用层能获取到消息内容并处理。

sendfile 返回的则是发送成功了几个字节数,具体发了什么内容,应用层根本不知道

RocketMQ 的一些功能,要了解具体这个消息内容,方便二次投递等,比如将消费失败的消息重新投递到死信队列中,如果 RocketMQ 使用 sendfile,那根本没机会获取到消息内容,也就没办法实现一些好用的功能了。

RocketMQ 和 Kafka 相比,在架构上做了减法,在功能上做了加法。

RocketMQ 简化了协调节点和分区以及备份模型。同时增强了消息过滤、消息回溯和事务能力,加入了延迟队列,死信队列等新特性。

RocketMQ 牺牲了一部分性能,换取了比 Kafka 更强大的功能特性。 ​

0

评论0

请先

显示验证码
没有账号?注册  忘记密码?

社交账号快速登录