内容梗概:
系统缓存+顺序写+批处理+mmap(生产者角度-高并发写入)
零拷贝技术(消费者角度-高并发读取)
Kafka在生产者写入消息的时候会将数据最终写入磁盘,既然它是基于磁盘读写,那么频繁的IO操作肯定会影响读写的性能,为何会有高性能呢?
1.系统缓存+顺序写+批处理+mmap(生产者角度-高并发写入)
在这里,Kafka生产者将消息写入各个broker中的时候,并不会直接写入磁盘,会将数据先写入缓存OS Cache(基于操作系统,所以命名OS),然后操作系统会决定什么时候将消息成批地将数据写入磁盘(批处理),因为写入数据时是直接和内存交互,所以其写入性能很高,而且在从缓存写入磁盘的时候,它会将随机写优化为顺序写,我们都知道,磁盘的写入是基于磁道寻址的,随机写会引发大量的磁盘寻址(即要先找到数据在磁盘上的位置,再进行数据读写),浪费大量的时间,而顺序写避免了频繁的寻址操作(直接追加数据至末尾),写入性能提高了数倍。(画外音:很多优秀的开源框架都采用了顺序来优化写入,比如HBase memestore)
![170fefbb87cf9803a8bef05be2873760.png](https://i-blog.csdnimg.cn/blog_migrate/37b45bffbd2406707dd796db05b591f0.jpeg)
[mmap]:即便是顺序写入硬盘,硬盘的访问速度还是不可能追上内存。所以Kafka的数据并不是实时的写入硬盘 ,它充分利用了现代操作系统分页存储来利用内存提高I/O效率。
Memory Mapped Files(mmap 内存映射文件) ,它的工作原理是直接利用操作系统的Page来实现硬盘和物理内存之间的映射。完成映射之后你对物理内存的操作会被同步到硬盘上(操作系统在适当的时候)。通过mmap,进程像读写硬盘一样读写内存(当然是虚拟机内存),也不必关心内存的大小有虚拟内存为我们兜底。(Oda.你以为你在操作硬盘,实际你在操作内存,内存会定时同步到硬盘)
但也有一个很明显的缺陷——不可靠,写到mmap中的数据并没有被真正的写到硬盘,操作系统会在程序主动调用flush的时候才把数据真正的写到硬盘。
Kafka提供了一个参数——producer.type来控制是不是主动flush,如果Kafka写入到mmap之后就立即flush然后再返回Producer叫 同步 (sync);写入mmap之后立即返回Producer不调用flush叫异步(async)。
2.零拷贝技术(消费者角度-高并发读取)
非零拷贝的流程:
(1)操作系统将数据从磁盘文件中读取到内核空间的页面缓存;
(2)应用程序将数据从内核空间读入用户空间缓冲区;(优化)
(3)应用程序将读到数据写回内核空间并放入 socket 缓冲区;
(4)操作系统将数据从 socket 缓冲区复制到网卡接口,此时数据才能通过网络发送。
![16e0796926f46cb4e82f8b841c3e1290.png](https://i-blog.csdnimg.cn/blog_migrate/77927a016ab78b301b083e6769823a9d.jpeg)
在磁盘上的数据格式、producer发送到broker的数据格式、和consumer收到的数据格式一模一样。由于磁盘格式与consumer以及producer的数据格式一模一样,这样就使得Kafka可以通过Linux的sendFile技术(NIO),省去了进程切换和一次数据拷贝,让性能变得更好。
SendFile优化后,直接把数据从内核区copy到socket,然后发送到网卡,避免了在内核Buffer与用户Buffer来回拷贝的弊端。
![99ecf9ff75e4558923f25c56034da60b.png](https://i-blog.csdnimg.cn/blog_migrate/1b4089c5aadaf3f79bd3f9bd95337b7b.jpeg)
本笔记本内容综合整理自多方资料加上个人心得,只用于非盈利内容分享,如有侵权,请联系删除。