admin管理员组文章数量:1598868
- 1. 相关概念
- 页
- 页缓存和块缓存概念
- 页缓存(page cache)
- 块缓存(buffer cache)
- 缓存机制的利弊
- 写缓存
- 2. 数据同步(刷缓存)
- flush内核线程
- 可调参数
- flush/sync/fsync系列API及命令介绍
- sync 系统命令
- sync()
- fsync()
- fdatasync()
- open()之O_SYNC/O_DSYNC选项
- msync()
- fflush()
- 3. 页面回收(page reclaim)
-
- 缓存回收策略
- 双LRU
- 系统触发页面回收
- 手动清理缓存
- 应用
-
- 4. 相关工具
- 查看缓存中的文件
- free命令
- free命令各个指标含义
- /proc/meminfo
- 5. 参考资料
1. 相关概念
页
- 页的概念 : 内核把物理页作为内存管理的基本单位. 通常32位系统页大小为4KB, 64位是8KB
- 如何查看当前系统页大小:
# getconf PAGESIZE
4096
页缓存和块缓存概念
- 内核为块设备提供两种通用缓存方案:
页缓存(page cache)
- 缓存的是内存页面,缓存中的页来自于对正规文件、块设备文件和内存映射文件的读写。也就是说页缓存中包含最近被访问的文件数据块。我们通常所说的系统cache主要就是指页缓存。
- 在进行一个读操作前(如read),内核会检查数据是否已经在页缓存中,如果在,就可以从内存中快速返回所需的页,而不是从磁盘上读取。
块缓存(buffer cache)
- 以块(块设备的block)为操作单位。在进行IO操作时,存取的单位是单个块设备的各个块,而不是整个内存页。
- 早期版本写文件,先经过页缓存,刷盘时再同步到块缓存最后再落盘. 即:如果用dd写裸盘,则不经过页缓存。
- 从linux内核2.4开始二者统一起来了,缓存用页映射块,块缓存实际上就在页缓存中了。
缓存机制的利弊
- 好处:
- 提高性能(且对应用程序透明)
- 写缓存,可将零碎IO聚齐起来
- ……
- 负面影响:
- 物理内存通常远小于块设备,必须仔细挑选缓存哪些数据
- 缓存在一定程度上会影响应用程序实际可用的内存容量
- 如果系统崩溃,缓存的数据可能来不及刷回块设备(硬盘/ssd等),造成数据丢失
写缓存
- 通常缓存有三种实现策略:
- 不缓存(很少使用)
- 写透缓存(write-through cache):写操作会立刻穿透缓存存到磁盘中
- 回写(writeback):即linux采取的策略,写操作后将对应缓存页面标记为“dirty”,由回写进程周期性刷到磁盘
- “脏页”这个词有误导性,实际上脏的是磁盘上的数据而不是缓存中的数据。准确讲应该叫“未同步的页”。
2. 数据同步(刷缓存)
- 数据总是在物理内存中操作,随后在适当的时机点写回(或刷出)到磁盘,以持久化保存修改
- 几种不同的刷出数据机制:
- 周期性内核线程将扫描脏页链表,并根据页面变脏的时间,选择一些页会写
- 如系统中脏页太多,内核将触发进一步机制对脏页与后备存储器进行同步,直到脏页降低到一个可接受的程度
- 内核各个组件要求数据必须在特定事件发生时同步,例如重新装在文件系统
flush内核线程
- 上述刷新机制前2条由flusher线程实现。内核中每个磁盘设备对应一个flush线程,通过块设备号区分,
[flush-8:48]
。 - 如何查看块设备号,可参考 http://www.lenky.info/archives/2012/02/1141 ,块设备一般都是8开头
- 历史上(2.6以前)还有bdflush,kupdated和pdflush等.其中pdflush线程数量不固定,而现在flush线程通常和磁盘一一对应,这样有助于在某个磁盘拥塞情况下避免所有IO拥塞,并简化处理逻辑。
- 关于线程数量和磁盘对应关系,以及周期性创建flush线程这部分逻辑,2.6前后内核版本有一定改动。查阅了几本内核的参考书,这部分介绍都不完全相同。
- 有些资料中提到,如1秒内没有空闲的flusher线程可用,内核将创建新的线程;如某个线程空闲超过1秒,将被销毁.flush线程数量一般被限制在2-8个
可调参数
- 可通过
/proc/sys/vm/
目录下的内核参数控制脏页回写行为:
参数 | 描述 |
---|---|
dirty_background_ratio | 占全部内存的百分比,当脏页数量超过该比例时,pdflush机制开始(在后台)回写脏页.此时对write调用没有影响 |
dirty_background_bytes | 同上,以字节描述。与dirty_background_ratio不可同时生效 |
dirty_writeback_centisecs | pdflush线程运行的频率,单位1/100秒。默认500,即pdflush两次调用间隔是5秒。早期版本该参数可能是 dirty_writeback_interval |
dirty_ratio | 脏页占全部内存的比例,超出该阈值时脏页开始刷出。此时新的IO请求可能会被阻塞直到脏页刷完 |
dirty_bytes | 同上,以字节描述。与dirty_ratio不可同时生效 |
dirty_expire_centisecs | 以百分之一秒为单位,默认3000.即超时30秒的脏页将会被pdflush线程写出,或者说一个脏页在回写之前,保持脏页状态最长可达30秒 |
- 在写密集的系统中,通常可配置dirty_ratio
较高(如60)以增大可用缓存、dirty_background_ratio
较低(如20)以遍在后台及时将数据刷入磁盘。同时保持dirty_writeback_centisecs
较高(如5秒)
- 内核源码中好像有一个检查,dirty_background_ratio
不能大于dirty_ratio
的1/2,否则内核会自动调整为后者的1/2.参见内核代码global_dirty_limits()
函数:
void global_dirty_limits(unsigned long *pbackground, unsigned long *pdirty)
{
……
if (background >= dirty)
background = dirty / 2;
……
}
- 效果示意图:
flush/sync/fsync系列API及命令介绍
sync 系统命令
- Force changed blocks to disk, update the super block.
sync()
- 允许进程把所有脏缓冲区刷新到磁盘.网上有说:
sync函数只是将所有修改过的块缓冲区排入写队列,然后就返回,它并不等待实际写磁盘操作结束。通常称为update的系统守护进程会周期性地(一般每隔30秒)调用sync函数
- 但从代码看,
do_sync()
会调用2次sync_inodes()
和sync_filesystems()
,第一次传参数0,表示异步执行;第二次传参数1,表示同步执行.
fsync()
- 允许进程把属于特定打开文件的所有块刷新到磁盘. 它等待写磁盘操作结束,然后返回(The call blocks until the device reports that the transfer has completed. It also flushes metadata information associated with the file)。fsync可用于数据库这样的应用程序.
- 但正由于它会将元数据也刷回磁盘,所以相比
fdatasync()
它多了一次IO操作。对于机械盘来说,这个耗时通常是毫秒(平均10ms左右)级别的!! fync()
不保证其所在目录也被刷到磁盘,因此针对其所在目录显示调用一次fsync()
是有必要的
fdatasync()
- 与fsync()类似,但不刷新文件的索引节点块(inode等)
- 诸如对文件access time等的修改,不会被fsync刷回磁盘; 但对文件大小的改变,由于会影响到后面的读数据,会被刷回磁盘。
- 通过这种机制减少不必要的磁盘IO,提高性能
- 网上提到,数据库系统中为了使用fdatasync来记录WAL日志的方法(因为日志都是追加写,文件长度会不断变化,不太适合直接用fdatasync):(https://
版权声明:本文标题:Linux缓存相关知识整理(史上最全!!) 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://www.elefans.com/xitong/1728314592a1153406.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论