有一些缓存软件在索引实现上使用mmap来实现读写,例如ats,并且ats在磁盘上有两份索引区域;
那么我们需要解决以下问题:
1. mmap的效率如何?
mmap的效率比pread、pwrite的效率高很多;所以在缓存启动的时候,为了让缓存能够快速使用到磁盘上的索引,可以用mmap将索引映射到虚拟内存中(这样比读取磁盘索引文件要快),待将索引文件load到内存以后,执行unmap,然后就可以一直使用内存中的索引了;
2. mmap的flush效率如何?是否适用于缓存?
由于缓存的索引是一个大文件,读写比较频繁,使用mmap会产生大量的随机写,所以不太适合缓存;mmap有自动flush也可以调用msync,不过无论哪种都会产生随机写;ats有时候为了减少mmap对磁盘的压力,故意设置flush的时间很长,我上家公司设置的flush时间间隔是3600s;
3. 为什么ats会有两份索引
为了防止磁盘损坏或者服务器异常crash导致索引损坏,在磁盘索引相同目录下,交替同步索引,即这次写入一个索引,下次会同步到另外一个索引;
下面详细介绍下mmap对缓存的影响:
文件映射是虚存的中心概念。设备驱动的mmap实现主要是将一个物理设备的可操作区域(设备空间)映射到一个进程的虚拟地址空间。虚拟页和物理页之间是以页表的方式关联起来。
1. mmap的特点是按需调页,当进程访问页面时产生一个缺页中断,内核将页面读入内存并且更新页表指向该页面。
2. 虚拟内存通常大于物理内存,在使用过程中虚拟页通过页表关联一切对应的物理页,当物理页不够时,会选择性的牺牲一些页,也就是将物理页与虚拟页之间切断,重现关联其他的虚拟页,保证物理内存够用。
以上两点表示内存中只保存有读写操作的地址区域,对于没有读写操作的区域依然保存在磁盘上;当物理空间不够的时候,会将一部分页置换到磁盘上;
对于缓存索引而言,一般短时间内有大量的更新操作(包括insert和delete),使用mmap会导致很多缓存页都有更新,flush只会flush这些更新的页面到磁盘上(没有更新的页面估计都不会在内存中),由于这些页面大部分是不连续的,这导致大量的随机写啊;所以针对缓存而言,mmap的flush是大量的随机写;
优化方法:
放弃使用mmap,使用pread/pwrite操作,并且不覆盖原来的文件;
使用下面操作:
1. 在旧文件目录下创建一个临时文件
2. 写数据到临时文件;
3. 同步临时文件;
4. 关闭临时文件;
5. 重命名旧文件到*.bak;
6. 重命名临时文件到最终文件;
这种即使服务器crash,磁盘上也有两份文件,至少能保证其中一份文件是完全安全可靠的;
08-31 18:42