PageCache

目录

  • buffers和cached的区别:
  • 操作系统层提供了page cache,为什么还要在应用层加缓存?

  page cache是针对文件系统的文件的缓存,在文件层面上的数据会缓存到page cache。文件的逻辑层需要映射到实际的物理磁盘,这种映射关系由文件系统来完成。当page cache的数据需要刷新时,page cache中的数据交给buffer cache来完成。
  那么,buffer cache是对磁盘块的缓存,也就是在没有文件系统的情况下,直接对磁盘进行操作的数据会缓存到buffer cache中。

page cache的数据结构:基树
1、每个文件都对应了一颗基树,是文件磁盘内容在内存的拷贝
2、本质上是一颗64叉树

缓冲读在pagecache层的调用路径
PageCache_第1张图片
aops->readpage()最终调用submit_bio()将读操作提交到通用块层。

  对于系统的所有文件I/O请求,操作系统都是通过page cache机制实现的,对于操作系统而言,磁盘文件都是由一系列的数据块顺序组成,数据块的大小随系统不同而不同,x86 linux系统下是4KB(一个标准页面大小)。内核在处理文件I/O请求时,首先到page cache中查找(page cache中的每一个数据块都设置了文件以及偏移信息),如果未命中,则启动磁盘I/O,将磁盘文件中的数据块加载到page cache中的一个空闲块。之后再copy到用户缓冲区中。
  很明显,同一块文件数据,在内存中保存了两份,这既占用了不必要的内存空间、冗余的拷贝、以及造成的CPU cache利用率不高。针对此问题,操作系统提供了内存映射机制。
  在使用mmap调用时,系统并不是马上为其分配内存空间,而仅仅是添加一个VMA到该进程中,当程序访问到目标空间时,产生缺页中断。在缺页中断中,从pagecaches中查找要访问的文件块,若未命中,则启动磁盘I/O从磁盘中加载到pagecaches。然后将文件块在pagecaches中的物理页映射到进程mmap地址空间。
  当程序退出或关闭文件时,系统不会马上清除page caches中的相应页面。由于该文件可能被其他进程访问,或该进程一段时间后会重新访问,因此,在物理内存足够的情况下,系统总是将其保持在page caches中,这样可以提高page caches的命中率,尽量少的访问磁盘。只有当系统物理内存不足时,内核才会主动清理page caches。
  当进程调用write修改文件时,由于page cache的存在,修改并不是马上更新到磁盘,而只是暂时更新到page caches中,同时mark 目标page为dirty,当内核主动释放pagecaches时,才将更新写入磁盘(主动调用sync时,也会更新到磁盘)。

buffers和cached的区别:

1、buffers和cached都是pagecache
2、buffers表示直接读取块设备,缓存在块设备基树中的数据,一般来说,这些数据是文件系统使用__bread()读取的元数据
3、执行dd if=/dev/sda of=/dev/zero bs=1M count=100,可以明显的看到buffers在增大
4、cached表示除buffers外,kernel缓存的文件数据,一般来说,是文件系统的文件数据
5、执行dd if=~/A_BIG_FILE of=/dev/zero bs=1M count=100,可以明显的看到cached在增大
6、cached表示除buffers外,kernel缓存的文件数据,一般来说,是文件系统的文件数据
7、执行dd if=~/A_BIG_FILE of=/dev/zero bs=1M count=100,可以明显的看到cached在增大

操作系统层提供了page cache,为什么还要在应用层加缓存?

  操作系统提供了一个通用的选择,没办法针对应用做个性化定制。kafka基本是顺序读写,这点是OS缓存可以很好的处理的情况;但是对于更多应用层系统来说,存在数据热点分布不均的情况,这些OS就不能很好的处理了。例如MySQL的innoDB缓存,如果采用OS的缓存策略,来一次全表扫描那么就可以让InnoDB辛辛苦苦热起来的数据冷了。但是InnoDB自己维护缓存情况下,就可以处理得很好,例如MySQL的InnoDB会对缓冲数据拆分为young以及old数据;会在整个缓存空间中腾出3/8的数据来用缓存这种多次访问的热点数据;这样全表扫描情况下,至少大多数热点数据还在内存中。甚至应用层可以在程序中直接指定热点数据,直接缓存起来;还有一个问题,OS缓存单位是页,不够应用层灵活。

你可能感兴趣的:(OPS,java)