Buffer和Cache的设计目的,是为了提升系统的IO性能。他们利用内存,充当起慢速磁盘与快速CPU之间的桥梁,可以加速IO的访问速度
Buffer和Cache分别缓存的是对磁盘和文件系统的读写数据。
- 从写的?度来说,不仅可以优化磁盘和?件的写?,对应?程序也有好处,应?程序可以在数据真正落盘前,就返回去做其他?作。
- 从读的?度来说,不仅可以提?那些频繁访问数据的读取速度,也降低了频繁 I/O 对磁盘的压?。
既然Buffer和Cache对系统性能有很大影响,那我们在软件开发的过程中,能不能利用这一点,来优化IO性能,提升应用程序的销量呢/p>
当然可以。
缓存指标
缓存命中率
缓存命中率可以衡量缓存使用的好坏
- 是指直接通过缓存获取数据的请求次数,占所有数据请求次数的百分比。
- 命中率越?,表示使?缓存带来的收益越?,应?程序的性能也就越好。
实际上,缓存是现在所有高并发系统必需的核心模块,主要作用就是把经常访问的数据(也就是热点数据),提前读入到内存中。这样,下次访问时就可以直接从内存中读取数据,而不需要经过硬盘,从而加快应用程序的响应速度。
这些独立的缓存模块通常会提供查询接口,方便我们随时查看缓存的命中情况。不过Linux系统中并没有直接提供这些接口,但是我们可以使用cachestat和cachetop来查看系统缓存命中情况的工具:
- cachestat提供了这个操作系统缓存的读写命中情况
- cachetop提供了每个进程的缓存命中情况。
这两个工具都是bcc软件包的一部分,它们基于Linux内核的eBPFF(extended Berkeley Packet Filters)机制,来跟踪内核中管理的缓存,并输出缓存的使用和命中情况。
使? cachestat 和 cachetop 前,我们?先要安装 bcc 软件包。?如,在 Ubuntu 系统中,你可以运?下?的命令来安装:
注意:bcc-tools需要内核版本为4.1或者更新的版本,如果你?的是CentOS,那就需要?动升级内核版本后再安装。
操作完这些步骤,bcc 提供的所有?具就都安装到 /usr/share/bcc/tools 这个?录中了。不过这?提醒你,bcc 软件包默认不会把这些?具配置到系统的 PATH 路径中,所以你得???动配置:
配置完,你就可以运? cachestat 和 cachetop 命令了。?如,下?就是?个 cachestat 的运?界?,它以1秒的时间间隔,输出了3组缓存统计数据:
cachestat 的输出其实是?个表格。每?代表?组数据,?每?列代表不同的缓存统计指标。这些指标从左到右依次表示:
- TOTAL ,表示总的 I/O 次数;
- MISSES ,表示缓存未命中的次数;
- HITS ,表示缓存命中的次数;
- DIRTIES, 表示新增到缓存中的脏?数;
- BUFFERS_MB 表示 Buffers 的??,以 MB 为单位;
- CACHED_MB 表示 Cache 的??,以 MB 为单位。
它的输出跟 top 类似,默认按照缓存的命中次数(HITS)排序,展示了每个进程的缓存命中情况。
- HITS:间隔时间内的缓存命中次数
- MISSES:未命中次数
- DIRTIES :新增到缓存中的脏?数。
- READ_HIT :读的缓存命中率。
- WRITE_HIT :写的缓存命中率。
指定文件的在内存中的缓存大小
可以使用pcstat这个工具,来查看文件在内存中的缓存大小和缓存比例。
pcstat是一个基于golang开发的工具,所以在安装它之前,应该先安装golang语言,之后再安装pcstat:
全部安装完成后,你就可以运? pcstat 来查看?件的缓存情况了。?如,下?就是?个 pcstat 运?的示例,它展示了 /bin/ls这个?件的缓存情况:
上面输出中,Cached就是/bin/ls在缓存中的大小,Percent就是缓存的百分比。他们都是0,说明/bin/ls并不在缓存中。
接着,如果你执??下 ls 命令,再运?相同的命令来查看的话,就会发现 /bin/ls 都在缓存中了:
案例
准备
- 机器配置:2 CPU,8GB 内存。
- 预先按照上?的步骤安装 bcc 和 pcstat 软件包,并把这些?具的安装路径添加到到 PATH 环境变量中。
- 预先安装 Docker 软件包,?如 apt-get install docker.io
案例一
dd是一个磁盘和文件的拷贝工具,常被用来测试磁盘或者文件系统的读写性能。不过,既然缓存会影响性能,如果用dd对同一个文件进行多次读写测试,测试的结果会怎么样呢/p>
我们来动?试试。?先,打开两个终端,连接到 Ubuntu 机器上,确保 bcc 已经安装配置成功。
然后,使? dd 命令?成?个临时?件,?于后?的?件读取测试:
继续在第?个终端,运? pcstat 命令,确认刚刚?成的?件不在缓存中。如果?切正常,你会看到 Cached 和 Percent 都是0:
还是在第一个中断中,现在运行cachetop命令:
这次是第?个终端,运? dd 命令测试?件的读取速度:
从dd的结果中可以看出,这个文件的读性能是33.4MB/s。由于在dd命令运行前我们已经清理了缓存,所以dd命令读取数据时,肯定要通过文件系统从磁盘中读取。
这是不是意味着,dd所有的读请求都能直接发送到磁盘呢/p>
我们再回到第一个终端,查看cachetop界面的缓存命中情况:
从cachetop的结果可以发现,并不是所有的读都落到了磁盘上,事实上读请求的缓存命中率只有50%。
接下来,我们继续尝试相同的测试命令。先切换到第?个终端,再次执?刚才的 dd 命令:
看到这次的结果,有没有点?惊讶盘的读性能居然变成了 4.5 GB/s,?第?次的结果明显?了太多。为什么这次的结果这么好呢/p>
不妨再回到第?个终端,看看 cachetop 的情况:
显然,cachetop也有了不?的变化。你可以发现,这次的读的缓存命中率是100.0%,也就是说这次的 dd 命令全部命中了缓存,所以才会看到那么?的性能。
然后,回到第?个终端,再次执? pcstat 查看?件 file 的缓存情况:
从pcstat的结果你可以发现,测试文件file已经被全部缓存了起来,这跟刚才观察到的缓存命中率100%是一致的。
这两次结果说明,系统缓存对第二次dd操作有着明显的加速效果,可以大大提高文件读取的性能。
但同时也要注意,如果我们把dd当成测试文件系统的工具,由于缓存的存在,就会导致测试结果严重失真。
案例二
接下来,我们再来看?个?件读写的案例。这个案例类似于前?学过的不可中断状态进程的例?。它的基本功能?较简单,也就是每秒从磁盘分区区 /dev/sda1 中读取 32MB 的数据,并打印出读取数据花费的时间。
这个案例被打包成了?个 Docker 镜像。 并提高了下?两个选项,你可以根据系统配置,??调整磁盘分区的路径以及 I/O 的??。
- -d 选项,设置要读取的磁盘或分区路径,默认是查找前缀为 /dev/sd 或者 /dev/xvd 的磁盘。
- -s 选项,设置每次读取的数据量??,单位为字节,默认为 33554432(也就是 32MB)。
这个案例同样需要开启两个终端。分别 SSH 登录到机器上后,先在第?个终端中运? cachetop 命令:
接着,再到第?个终端,执?下?的命令运?案例:
案例运?后,我们还需要运?下?这个命令,来确认案例已经正常启动。如果?切正常,应该可以看到类似下?的输出:
从这?你可以看到,每读取 32 MB 的数据,就需要花 0.9 秒。这个时间合理吗想你第?反应就是,太慢了吧。那这是不是没?系统缓存导致的呢/p>
我们再来检查?下。回到第?个终端,先看看 cachetop 的输出,在这?,我们找到案例进程 app 的缓存使?情况:
这个输出似乎有点意思了。1024 次缓存全部命中,读的命中率是 100%,看起来全部的读请求都经过了系统缓存。但是问题?来了,如果真的都是缓存 I/O,读取速度不应该这么慢。
不过,话说回来,我们似乎忽略了另一个重要因素。每秒实际读取的数据大小。HITS代表缓存的命中次数,那么每次命中能读取多少数据呢然是一页。
内存以页为单位进行管理,而每个?的??是 4KB。所以,在5秒的时间间隔?,命中的缓存为 1024*4K/1024 =4MB,再除以5 秒,可以得到每秒读的缓存是 0.8MB,显然跟案例应?的32 MB/s 相差太多。
这也进?步验证了我们的猜想,这个案例估计没有充分利?系统缓存。其实前?我们遇到过类似的问题,如果为系统调?设置直接 I/O 的标志,就可以绕过系统缓存。
那么,要判断应?程序是否?了直接I/O,最简单的?法当然是观察它的系统调?,查找应?程序在调?它们时的选项。使?什么?具来观察系统调?呢然还是 strace。
继续在终端?中运?下?的 strace 命令,观察案例应?的系统调?情况。注意,这?使?了 pgrep 命令来查找案例进程的PID :
从 strace 的结果可以看到,案例应?调?了 openat 来打开磁盘分区 /dev/sdb1,并且传?的参数为O_RDONLY|O_DIRECT(中间的竖线表示或)。
O_RDONLY 表示以只读?式打开,? O_DIRECT 则表示以直接读取的?式打开,这会绕过系统的缓存。
验证了这?点,就很容易理解为什么读 32 MB的数据就都要那么久了。直接从磁盘读写的速度,?然远慢于对缓存的读写。这也是缓存存在的最?意义了。
找出问题后,我们还可以在再看看案例应?的源代码,再次验证?下:
上?的代码,很清楚地告诉我们:它果然?了直接 I/O。
找出了磁盘读取缓慢的原因,优化磁盘读的性能?然不在话下。修改源代码,删除 O_DIRECT 选项,让应?程序使?缓存I/O ,?不是直接 I/O,就可以加速磁盘读取速度。
app-cached.c 就是修复后的源码,我也把它打包成了?个容器镜像。在第?个终端中,按 Ctrl+C 停?刚才的 strace 命令,运?下?的命令,你就可以启动它:
# 删除上述案例应?$ docker rm -f app声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!