NFS的缓存IO机制
<一> async 参数模式下分析
NFS 默认的mount参数为async,async 参数表示内核不会透传程序的IO请求给sever,对于写IO会延迟执行,积累一定的时间以便合并上层的IO请求以提高效率。
读分析
1: 顺序读请求的合并预读
dd if=/mnt/nfs/3 of=/dev/null bs=1500 count=100
测试发现仅仅发送了6个read请求 16384 + 32768 * 4 + 2544 =150000,并且其中后5个请求是连续发送的。
2:随机读读惩罚
随机读情况下,由于都有预读,所有每次预读都会多读一部分数据,导致可能实际使用的数据量不到接受到数据的10分之一,称为读惩罚。
写分析
1:追加写
dd if=/dev/zero of=/mnt/nfs/ddtest bs=1 count=100
dd将已经存在的文件的size(SETATTR)设置为0,然后从头开始追加写入这个文件,每次写1B,写100次。但是内核并没有像NFS服务器发送100次写,实际上指发送了一次写。
2:覆盖写
连续覆盖写:内核行为和追加写一样,内核对写操作进行了合并。
随机覆盖小:随机模式下,内核无法对写进行合并,直接完全透传用户程序发起的I/O。
<二> sync参数模式下的分析
读分析
1:如果mount的时候选用sync参数,或者如果上层使用 sync 调用,那么其产生的读I/O一定在内核处也是同步的,因为只有在前一个读请求数据成功返回给客户端程序,客户端程序才会发起下一个读请求,(对于异步读调用,内核可以在短时间内接受到多个读请求,此时内核可以将这些读请求合并,这就是异步过程)。但是同步读并不影响nfs的预读,比如
dd if=/mnt/nfs/ddtest bs=1 count=150,并不是向server发送150个一次1B的请求,而是根据rsize进行预读,把150B的数据一次性读回来,其他159次就直接命中缓存了。
写分析
1:对于sync同步的写调用,程序只有在第一个写调用结束之后才会发起下一个写。
dd if=/dev/zero of=/mnt/nfs/ddtest bs=1 count=1500 (1B为单位的写操作),那么就是发送150个write请求,效率非常低下。
注意:DIO模式由于每次都绕过了内核的pagecache ,所以每一个请求都会向服务端发起请求,不会进行预读,异步写,写合并,读合并等策略。