1. 磁盘顺序写
Kafka在数据写入到磁盘时,采用的是顺序写方式(因为磁盘随机写方式的性能很差),即将数据追加到文件的末尾。这种方式极大的降低了寻址时间,提高性能。
2.页面缓存(PageCache)
PageCache是操作系统级别的缓存,它把尽可能多的空闲内存当作磁盘缓存来使用,从而进一步提高I/O效率。另外,当其他进程申请内存时,回收PageCache的代价也很小。
由于PageCache时操作系统级别的缓存,所以不会收到JVM的GC影响。
生产者把消息发送到Kafka之后,消息会先写入到PageCache中,之后再由内存中的处理线程采用同步或异步的方式将PageCache中的数据写入到磁盘中。
消费者会优先从PageCache中获取消息处理,获取不到时才会去磁盘获取。
如果生产者跟消费者的处理速率接近,那么大概率是只会再PageCache中读写数据,磁盘的访问会很少。这样在内存中处理数据的话速度会很快。
3.零拷贝
传统的网络I/O过程如下:
- 操作系统把数据从磁盘中读到内核区的 Read Buffer 中。
- 用户进程把数据从内核区的Read Bufler 中复制到用户区的 Applcation Buifer 中。
- 用户区的 Appicatlon Buter 把数据写入Socket通道,数据被复制到内核区的Socket Buffer 中。
- 操作系统把数据从内核区的 Socket Buffer 发送到网卡中。
可以看出,同一份数据在操作系统内核区的 Read Butter 与用戶区的 Application Buffer 之同需要复制两次。为了进行这两次复制,发生了好几次上下文切换,一会儿是应用程序在执行,一会是操作系统在执行。所以,用这种方式读取数据是比较消耗性能的。
为了解決这个问题,Kafa 在读取数据时使用了零拷贝技木:直授把数据从内核区的 ReadBufer 复制到 Socket Buffer 中,然后发送到网卡中。这样避免了任操作系统内核区的Read Buffer 和用户区的Application Buffer 之间来回复制数据的弊端。