Linux 操作系统原理 — Cache 和 Buffer

目录

文章目录

  • 目录
  • Cache 和 Buffer 的区别在哪里?
  • 为什么需要缓存?
  • Linux 缓存机制
  • Page Cache 的同步机制(一致性问题)

Cache 和 Buffer 的区别在哪里?

Cache 和 Buffer 是两个不同的概念,简单的说,Cache 是加速 “读”,而 Buffer 是缓冲 “写”,前者解决读的问题,保存从磁盘上读出的数据,后者是解决写的问题,保存即将要写入到磁盘上的数据。在很多情况下,这两个名词并没有严格区分,常常把读写混合类型称为 buffer/ cache。

为什么需要缓存?

Linux 操作系统原理 — Cache 和 Buffer_第1张图片

可以看到,CPU 最快,一个时钟周期是 0.3 纳秒,内存访问需要 120 纳秒,固态硬盘访问需要 50-150 微秒,传统硬盘访问需要 1-10 毫秒, 网络访问最慢,都是几十毫秒。

如果一个时钟周期如果按 1 秒算:

  • 内存访问就是 6 分钟
  • 固态硬盘是 2-6 天
  • 传统硬盘是 1-12 个月
  • 网络访问就是几年了!

如果你是 CPU,你会觉得这个世界真是慢死了!从硬盘访问数据得等待 “几天” 甚至 “几个月”!

Linux 操作系统原理 — Cache 和 Buffer_第2张图片
所以存储器的层级关系出来了,存储器越往上速度越快,但是价格越来越贵, 越往下速度越慢,但是价格越来越便宜。

Linux 缓存机制

在 Linux 系统中,为了提高文件系统性能,内核利用一部分物理内存分配出缓存区,用于缓存系统操作和数据文件,当内核收到读写的请求时,内核先去缓存区找是否有请求的数据,有就直接返回,如果没有则通过驱动程序直接操作磁盘。

  • buffers 用来缓存 metadata 及 pages,可以理解为系统缓存,例如:vi 打开一个文件。

  • cached 用来给文件做缓存,可以理解为数据块缓存,例如:dd if=/dev/zero of=/tmp/test count=1bs=1G 测试写入一个文件,就会被缓存到缓冲区中,当下一次再执行这个测试命令时,写入速度会明显很快。

  • Swap 是交换分区,即通常我们说的虚拟内存,是从硬盘中划分出的一个分区。当物理内存不够用的时候,内核就会释放缓存区(buffers/cache)里一些长时间不用的程序,然后将这些程序临时放到 Swap 中,也就是说如果物理内存和缓存区内存不够用的时候,才会用到 Swap。

缓存机制优点: 减少系统调用次数,降低 CPU 上下文切换和磁盘访问频率。

CPU上下文切换: CPU 给每个进程一定的服务时间,当时间片用完后,内核从正在运行的进程中收回处理器,同时把进程当前运行状态保存下来,然后加载下一个任务,这个过程叫做上下文切换。实质上就是被终止运行进程与待运行进程的进程切换。

查看到系统内存的使用情况:
Linux 操作系统原理 — Cache 和 Buffer_第3张图片
可以看出,系统内存为 16G,Swap 内存 16G,mem free 虽然显示为 1118,因缓存的存在,不能认为系统目前内剩下这么多内存。而应该把 buffers、cached 的也算上,即 free+cached+buffers=1118+7110+430=8658,总内存再减去 8658=7314,与 buffers/cache 行中对应 free 列的 7312 和 8659 基本一致。

Page Cache 的同步机制(一致性问题)

广义上 Cache 的同步方式有两种,即 Write Through(写穿)和 Write back(写回)。从名字上就能看出这两种方式都是从写操作的不同处理方式引出的概念,单存读不存在 Cache 一致性问题。

对应到 Linux 的 Page Cache 上所谓 Write Through 就是指 write 操作将数据拷贝到 Page Cache 后立即和下层进行同步的写操作,完成下层的更新后才返回。而 Write back 正好相反,指的是写完 Page Cache 就可以返回了。Page Cache 到下层的更新操作是异步进行的。

Linux 下 Buffered IO 默认使用的是 Write back 机制,即文件操作的写只写到 Page Cache 就返回,之后 Page Cache 到磁盘的更新操作是异步进行的。Page Cache 中被修改的内存页称之为脏页(Dirty Page),脏页在特定的时候被一个叫做 pdflush(Page Dirty Flush)的内核线程写入磁盘,写入的时机和条件如下:

  • 当空闲内存低于一个特定的阈值时,内核必须将脏页写回磁盘,以便释放内存。
  • 当脏页在内存中驻留时间超过一个特定的阈值时,内核必须将超时的脏页写回磁盘。
  • 用户进程调用 sync、fsync、fdatasync 系统调用时,内核会执行相应的写回操作。

刷新策略由以下几个参数决定(数值单位均为 1/100 秒):

# flush 每隔 5 秒执行一次
$ sysctl vm.dirty_writeback_centisecs
vm.dirty_writeback_centisecs = 500

# 内存中驻留 30 秒以上的脏数据将由 flush 在下一次执行时写入磁盘
$ sysctl vm.dirty_expire_centisecs
vm.dirty_expire_centisecs = 3000

若脏页占总物理内存 10% 以上,则触发 flush 把脏数据写回磁盘
$ sysctl vm.dirty_background_ratio
vm.dirty_background_ratio = 10

默认是写回方式,如果想指定某个文件是写穿方式呢?即写操作的可靠性压倒效率的时候,能否做到呢?当然能,除了之前提到的 fsync 之类的系统调用外,在 open 打开文件时,传入 O_SYNC 这个 flag 即可实现。

你可能感兴趣的:(Linux,操作系统原理)