通俗解释:在应用程序读取磁盘文件时,操作系统内核在读取磁盘时会经过一层Cache,利用这个Cache可以更快速读取数据(毕竟磁盘速度和内存速度还是差了很多)。那么这个Cache就是PageCache
01. Pagecache(页缓存)的作用和原理
在磁盘进行标准IO操作时,操作系统内核会先把数据写入到PageCache,这样我读取数据时会直接从Cache中读取同时减少了IO的次数,达到了提升读写效率。
文件读取流程:
- 应用程序发起读请求,触发系统调用read()函数,用户态切换为内核态。
- 文件系统通过目录项,页缓存树,查询Page Cache是否存在,如果存在则直接读取,避免了对物理磁盘I/O操作。
- Page Cache不存在产生缺页中断,CPU向DMA发出控制指令
DMA 控制器将数据从主存或硬盘拷贝到内核空间(kernel space)的缓冲区(read buffer);
4. DMA 磁盘控制器向 CPU 发出数据读完的信号,由 CPU 负责将数据从内核缓冲区拷贝到用户缓冲区
5. 用户进程由内核态切换回用户态,获得文件数据
写入流程
- 应用程序发起写请求,触发系统调用write()函数,用户态切换为内核态;
- 文件系统通过目录项,页缓存树,查询 Page Cache是否存在,如果不存在则需要创建;
- Page Cache 存在后,CPU将数据从用户缓冲区拷贝到内核缓冲区,Page Cache 变为脏页(Dirty Page,内存数据页跟磁盘数据页内容不一致),写流程返回;
- 用户主动触发刷盘或者达到特定条件内核触发刷盘,唤醒 pdflush 线程,pdflush 将内核缓冲区的数据刷入磁盘
02. PageCache在大数据组件中的应用
在大数据组件中,基本上涉及到文件层级的读写操作的底层都会用到pagecache的技术,比如Kafka、HDFS。
比如大数据高性能消息队列组件Kafka之所以高性能其中之一的因素就在于它将Cache技术用到了极致,
Kafka 使用Page Cache作为缓存而不是用JVM缓存,包含以下原因:
- JVM 中的一切皆对象,所以无论对象的大小,总会有些额外的 JVM 的对象元数据浪费空间。
- 在大数据量场景下,如果使用JVM进行缓存会造成对象频繁的GC操作。会直接影响程序的稳定性。
- 在程序异常退出时,那么缓存也会直接失效,难免会造成局部数据丢失。pagecahce是操作系统的缓存,与进程无关。
- 即便是使用堆外内存,也会进行刷盘操作造成数据IO的性能下降,并且使用的物理内存空间会被放大。
首先我们在往kafka producer发送数据之后,producer端内部会调用pwrite函数(对应Java NIO中的FileChannel.write() 函数)
producer生产消息时,会使用pwrite()系统调用【对应到Java NIO中是FileChannel.write() API】按偏移量写入数据,并且都会先写入page cache里。consumer消费消息时,会使用sendfile()系统调用【对应FileChannel.transferTo() API】,零拷贝地将数据从page cache传输到broker的Socket buffer,再通过网络传输。
FileChannel(Java.NIO) 在将ByteBuffer中的数据写入磁盘之前,中间会现将数据存入pagecache这一层。一般我们认为 filechannel.write 写入 PageCache 便是完成了落盘操作,但实际上,操作系统最终帮我们完成了 PageCache 到磁盘的最终写入,理解了这个概念,你就应该能够理解 FileChannel 为什么提供了一个 force() 方法,用于通知操作系统进行及时的刷盘。
那么如果kafka producer的生产速率和consumer的消费速率基本一致的话,那么整个过程对于磁盘的访问非常少,基本都是走的缓存层进行处理的数据,所以生产和消费的性能会非常的高
本文参考 :
https://cloud.tencent.com/developer/article/1807349
https://www.infoq.cn/article/7VQD5xiz2l6P1yjucMvu