理解page cache的设计与作用

什么是page cache

page cache即页高速缓存,这是提高虚拟文件系统和磁盘文件系统速度的关键,在绝大多数请下,内核在读写磁盘时都引用了页高速缓存。

读数据

如果页不在缓存中,就会创建一个新页添加到缓存中,然后用磁盘读出的数据填充它,如果内存有足够的空闲空间,就让该页在缓存中长期保留,使其他进程再使用该页时不再访问磁盘。

写数据

同样,写数据时,内核首先检查对应的页是否已经在高速缓存中了,如果不在,就要先在其中增加一个,并用要写入磁盘中的数据填充它,也就是先入高速缓存中,被写入高速缓存中的数据一般并不会直接刷新到磁盘中,而是会根据某些参数配置决定何时把缓存中的数据写入到磁盘中。

脏页

page cache一旦产生增、改操作就会被标记为脏,当page cache达到使用阈值时,就会触发淘汰策略,而脏页再被淘汰之前,脏页中的数据是必要要写入磁盘的,数据一旦页入磁盘之后,脏的标记就会被移除。

page cache刷写磁盘策略

1、页高速缓存变得太满,但还需要更多的页,或者脏页的数量已经太多。
2、自从页变成脏页以来已过去太长的时间。
3、用户进程通过调用sync()、fsync()或者fdatasync()系统调动来触发。

前两项都可以通过系统参数配置来调整。

使用sysctl -a | frep dirty命令可以查看默认配置

在这里插入图片描述

vm.dirty_background_ratio = 10
vm.dirty_ratio = 20

这两个参数表示的就是,当脏页的容量达到系统内存10%时,就会触发后台刷写磁盘进程,将缓存的脏页异步的写入磁盘中,并且如果脏页的容量达到系统内存20%时,系统就会阻塞其他IO请求,直到脏页中的数据被写入磁盘中,这也是造成IO卡顿的重要原因。

vm.dirty_background_bytes = 0
vm.dirty_bytes = 0

这两个参数表示的含义与上面两个一样,只不过一个是百分比,一个是字节大小。

注意:上面两组配置会冲突,只会生效一组,如果配置了按字节,同时又配置了按比例,则只会生效按字节的配置。

vm.dirty_writeback_centisecs = 500
vm.dirty_expire_centisecs = 3000

这两个参数表示,每隔5秒钟异步写脏页数据的进程就会执行一次,判断是否有脏页的数据存活的时间已经超过了30秒,如果超过,则直接把这些数据写入到磁盘中。

page cache丢数据

正是因为有如上的一些刷盘策略,所以也就造成了使用page cache必然会有丢数据的现象产生,即使你每次写完数据都刷盘,那也不能保证数据在page cache写时磁盘过程中的绝对可靠。

演示数据丢失

通过 vi /etc/sysctl.conf,修改参数配置,设置缓存大小为1M,阻塞时为2M,可以缓存300秒。

在这里插入图片描述

简单的向磁盘文件写数据的代码,每隔1毫秒,写入10个字节

import java.io.File;
import java.io.FileOutputStream;

public class PageCacheTest {
    
    
    public static void main(String[] args) {
    
    
        try {
    
    
            FileOutputStream fileOutputStream = new FileOutputStream(new File("/usr/test_io/cache.txt"));
            while(true){
    
    
                Thread.sleep(1);
                fileOutputStream.write("1234567890".getBytes());
            }
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
    }
}

1、让程序运行起来

在这里插入图片描述
2、已经写入31K数据到cache.txt文件中。

在这里插入图片描述

3、强制关机,再开机后查看cache.txt文件,数据全部丢失了。

在这里插入图片描述


1、修改配置,分为设置为1KB和2KB,更加频繁的刷写磁盘。

在这里插入图片描述
2、关机前数据

在这里插入图片描述
3、开机后数据,可以看到数据没有完全丢失(从我截图到操作关机这段时间,数据还在写入)

在这里插入图片描述

通过这个小案例,把问题放大后可以得知使用page cache必然会带来数据丢失的问题,所以在配置的时候就需要我们进行权衡。

kafka、redis中的应用

写到这,我想到kafka的akcs配置中,有0,1,all这样的配置,其中0就是由操作系统参数配置决定何时持久化消息,以及redis中的aof持久化策略,aof_fsync_no这也是由操作系统参数配置决定。

并且我们应该了解到,既然单机不能保证数据不丢失,所以在kafka中有副本的架构,redis持久化中有主从的架构,通过这些手段就可以避免数据丢失的问题。

猜你喜欢

转载自blog.csdn.net/CSDN_WYL2016/article/details/109119787