目录
[二:broker 端](#二:broker 端)
在如今的MQ中三分天下性能之王的必然是Kafkka呢,为什么呢?最简单的就是kafka的单机吞吐量在百万级别以上。而RabbitMQ单机吞吐量在10万级别以下,而阿里开源的RocketMQ在二者之间十万到百万级别,那为什么kafka可以这么快呢,我总结了以下几点原因,如下图,我们可以从以下几个角度来分析分析。
一:生产者
在生产者这一方面,主要是消息的生产者,关键在于一个异步,怎么说呢,异步是指事件或操作在时间上不同步,即事件的发生和完成不依赖于其他事件的状态或速度。在通信领域,异步通信指的是发送端和接收端之间的字符或帧之间没有固定的时间间隔要求,每个字符或帧的开始和结束通过特定的标志位来界定。异步通信的好处是设备简单、便宜,但传输效率较低,因为开始位和停止位的开销较大。在多道程序环境下,异步指的是每道程序以人们不可预知的速度向前推进。
而在kafka中异步提交:主要是指我们应用 调用 kafka send接口 发送消息是个异步接口。 这个接口,底层其实是没有把消息发给broker端,它把消息直接写入内存里,然后就返回了;所以说他是一个异步写消息接口;因为这个接口它不需要经过网络通信,broker端进行存储,然后应答给发送端这个过程。它直接写消息数据到本地内存,当然很快了。
那批量导入又是什么意思呢?
批量导入其实也很好理解,在kafka中并不是生产者生产一条消息就直接发送给broker端的,而是将消息都暂存在内存里,而在kafka 生产端 还会有一个专门的IO 发送线程:把内存中的消息,按照消息路由算法,把发往相同broker的消息,聚合到一个消息集合(可以理解为一个消息zip包)里,作为一个消息集的数据包 发送给对应的broker。如果不是批量发送,那么就会出现一条消息要请求一次网络IO,而在面对大量的并发的场景下,网络IO的请求是十分消耗性能的,而我一次性就将消息集发送只需要请求一次网络IO,这对kafka的性能有很大的提升。
二:broker 端
在生产者方面,通过异步发送消息和批量导入到broker端就已经提升了一部分性能,那么在broker端,kafka是如何保证性能的呢?下面我们先看一张图:
将上图总结为一段话就是:broker端 接受到生产者发送的消息后,是需要写消息到磁盘里的;这里的写,使用了 同步写数据到磁盘缓存;然后异步顺序刷数据到磁盘
kafka写数据到文件系统的主流程,其实是写入到page cache里,类似与往内存中写数据,所以主流程是很快的;然后涉及到刷新数据到磁盘,其实是要把数据写入到磁盘的,那这个速度就很慢了;所以刷新数据到磁盘这种比较慢的操作,采用了异步,以减少对数据写入这个主流程的延迟。
但kafka在刷数据到磁盘这个比较慢的动作里,也还是做了优化的,他用顺序追加文件内容的方式,而不是随机写文件内容的方式,其实是为了 减少 底层硬盘磁头随机定位的次数,以此来提高刷数据到磁盘的速度。
而零拷贝呢,其原理是通过减少或消除数据在内核态和用户态之间的拷贝次数,从而提高数据传输的效率和性能。这一原理的实现主要依赖于操作系统提供的底层支持,特别是直接内存映射(Direct Memory Mapping)和sendfile系统调用等机制。
在没有使用零拷贝的情况下是这样的:
但kafka使用零拷贝后就变成了以下这个样子:
但需要注意的是,零拷贝技术并不是完全的零拷贝,而是尽可能地减少数据的复制。在某些情况下,仍然需要进行一定的数据复制操作。
假设有一个应用程序需要将一个100MB的文件发送到另一台机器上。如果不使用零拷贝技术,传输过程可能如下:
应用程序将文件的内容读入内存缓冲区中
应用程序将缓冲区中的数据复制到操作系统内核缓冲区中
操作系统将内核缓冲区中的数据复制到网络套接字缓冲区中
网络将数据发送到目标机器上
目标机器将数据写入到本地文件系统中
在这个过程中,数据被复制了多次,这会导致性能瓶颈。而使用零拷贝技术后,传输过程可以如下:
应用程序使用sendfile系统调用将文件直接发送到网络套接字缓冲区中
网络将数据发送到目标机器上
目标机器将数据写入到本地文件系统中
在这个过程中,数据只被复制了一次,即从文件中读入到内核缓冲区中。由于避免了数据的多次复制,所以零拷贝技术可以大大提高数据传输效率和性能。
三:消费者
在kafka架构设计中,是不支持推送消息的,需要用户主动去拉消息,而在传统的MQ中认为推消息是比较快的,其实不然,这种拉消息其实kafka是支持批量拉取的,消费端拉取broker消息时,不是每次获取单条消息,而是在从broker端获取消息时,尽量一次网络IO获取尽量多消息(默认最大上限为500条)。这也是kafka 使用"批量"这个提升系统吞吐量优化手段之一的体现;这里的消费端批量拉取和生产端使用的批量方式,有相似的效果,都是为了尽可能节约资源,把主要精力放到真正的消息处理里。
而在消息处理时,又采取了数据压缩的方式更能提升效率,这是因为 kafka 生产端是批量发送消息的,这个压缩,是指把这个批量消息作为一个整体进行压缩,然后通过一次网络IO发送给broker端。这种方式比不压缩,节约了网络带宽;并且在broker端存储的时候,也不会对消息进行解压,还节约了磁盘存储空间;另外压缩后的消息,直到消费者从broker端获取后,才会在消费者端进行解压缩。
这样就带来了,消息从生产端到broker端,再从broker端到消费者端的网络传输里,都是经过压缩的消息,从整体上节约了网络带宽和网络层传输的效率。
因此,综上终于知道kafka为什么会这么快的原因,其实在我的理解中就是kafka将异步+批量这两个技术用到了极致,因此才会在性能上远超RabbitMQ和RocketMQ。