持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第14天,点击查看活动详情
kafka高效读写的原因
大伙都知道kafka的读写很快,能够实现每秒上百万的读写,那么它是做了什么优化才能这么快呢?
根据网上的资料主要有以下几大优化
- 利用分区实现并行处理
- 顺序读写磁盘
- 零拷贝技术
- 批处理和数据压缩
下面就来学习一下具体的优化细节把~
利用分区实现并行处理
生产者在发送信息时都需要指定一个Topic,而Topic又可以包含一个或者多个的Partition,这些不同的partition又通常存放在不同的物理机器上。所以可以更好的利用多节点的优势,实现机器的并行处理,发挥磁盘IO读取的优势。
顺序读写磁盘
Kafka通过顺序读写方式来操作分区文件,对于每个分区文件都会提前分配好磁盘空间,随后不断追加消息。
零拷贝技术
通常我们进行一次普通的读写操作,会发生四次上下文切换和数据拷贝。
生产者写入kafka优化
例如下面生产者将数据写入kafka后,kafka需要读取网络数据并把它持久到磁盘里
data = socket.read() // 读取操作
File file = new File()
file.write(data) // 写入操作
kafka为了提高写入效率,使用mmap+write方式来减少一次CPU的拷贝。
Memory Mapped Files:简称 mmap,使用的效果是将内核中读缓冲区(read buffer)的地址与用户空间的缓冲区(user buffer)进行映射。从而实现内核缓冲区与应用程序内存的共享,从而省去了将数据从内核读缓冲区(read buffer)拷贝到用户缓冲区(user buffer)的过程(一次CPU拷贝)。它的工作原理是直接利用操作系统的 Page 来实现文件到物理内存的直接映射。完成映射之后你对物理内存的操作会被同步到硬盘上。
使用mmap会带来一个缺点:不可靠,即数据并没有真正写入硬盘中,操作系统会等到应用程序使用flush时才会把数据刷到磁盘中。因此Kafka提供了一个producer.type属性来控制是不是主动刷新到磁盘中,默认是当数据写入mmap中就立即同步到磁盘中即sync,或者异步刷入磁盘中即async。
消费者读取kafka优化
通常情况下将磁盘数据写入网卡也同样是要四次上下文切换和数据拷贝。
buffer = File.read()
socket.send(buffer)
kafka使用sendfile技术优化了数据发送,将上下文切换减少到两次。可以看到将硬盘数据通过DMA复制到内核缓冲区后,直接通过DMA COPY的方式将数据拷贝到网卡上,并不需要CPU来进行复制,提高了性能。
批处理和数据压缩
kafka会试着累积多个读写操作,然后在一次性进行发送,减少多次操作多带来的网络开销,能够更好利用网络带宽。同时生产者在将数据发送给kafka时,会将消息进行压缩,也是为了减少数据包的大小,提高IO效率。