本文是通过学习倪朋飞老师的《Linux性能优化实战》 :如何利用系统缓存优化程序的运行效率?
如何利用系统缓存优化程序的运行效率?
前面我们学习了内存性能中 Buffer 和 Cache 的概念。简单复习一下,Buffer 和 Cache 的设计目的,是为了提升系统的 I/O 性能。它们利用内存,充当起慢速磁盘与快速 CPU 之间的桥梁,可以加速 I/O 的访问速度。
Buffer 和 Cache 分别缓存的是对磁盘和文件系统的读写数据。
- 从写的角度来说,不仅可以优化磁盘和文件的写入,对应用程序也有好处,应用程序可以在数据真正落盘前,就返回去做其他工作。
- 从读的角度来说,不仅可以提高那些频繁访问数据的读取速度,也降低了频繁 I/O 对磁 盘的压力。
既然 Buffer 和 Cache 对系统性能有很大影响,那我们在软件开发的过程中,能不能利用这一点,来优化 I/O 性能,提升应用程序的运行效率呢?那当然是可以的。
缓存命中率
所谓缓存命中率,是指直接通过缓存获取数据的请 求次数,占所有数据请求次数的百分比。
命中率越高,表示使用缓存带来的收益越高,应用程序的性能也就越好。
实际上,缓存是现在所有高并发系统必需的核心模块,主要作用就是把经常访问的数据(也就是热点数据),提前读入到内存中。这样,下次访问时就可以直接从内存读取数据,而不需要经过硬盘,从而加快应用程序的响应速度。
这些独立的缓存模块通常会提供查询接口,方便我们随时查看缓存的命中情况。不过 Linux 系统中并没有直接提供这些接口,所以这里要介绍一下,cachestat 和 cachetop ,它们正是查看系统缓存命中情况的工具。
- cachestat 提供了整个操作系统缓存的读写命中情况。
- cachetop 提供了每个进程的缓存命中情况。
这两个工具都是 bcc 软件包的一部分,它们基于 Linux 内核的 eBPF(extended Berkeley Packet Filters)机制,来跟踪内核中管理的缓存,并输出缓存的使用和命中情况。
使用 cachestat 和 cachetop 前,我们首先要安装 bcc 软件包。比如,在 centos 系统 中,你可以运行下面的命令来安装:
yum install -y bcc-tools
#操作完这些步骤,bcc 提供的所有工具就都安装到 /usr/share/bcc/tools 这个目录中了。不过,bcc 软件包默认不会把这些工具配置到系统的 PATH 路径中,所以得自己手动配置:
# 配置 PATH 路径
export PATH=$PATH:/usr/share/bcc/tools
配置完,就可以运行 cachestat 和 cachetop 命令了。比如,下面就是一个 cachestat 的运行界面,它以 1 秒的时间间隔,输出了 3 组缓存统计数据:
cachestat 1 3
HITS MISSES DIRTIES HITRATIO BUFFERS_MB CACHED_MB
0 0 0 0.00% 2 2114
0 0 0 0.00% 2 2114
5690 0 0 100.00% 2 2114
可以看到,cachestat 的输出其实是一个表格。每行代表一组数据,而每一列代表不同 的缓存统计指标。这些指标从左到右依次表示:
我得这个版本没有显示总的io数
- TOTAL ,表示总的 I/O 次数
- HITS:表示缓存命中的次数
- MISSES:表示缓存未命中的次数
- DIRTIES:表示新增到缓存中的脏页数
- BUFFERS_MB:表示 Buffers 的大小,以 MB 为单位
- CACHED_MB:表示 Cache 的大小,以 MB 为单位
接下来再来看一个 cachetop 的运行界面:
cachetop
14:13:41 Buffers MB: 2 / Cached MB: 2129 / Sort: HITS / Order: descending
PID UID CMD HITS MISSES DIRTIES READ_HIT% WRITE_HIT%
60894 www php 5505 0 0 100.0% 0.0%
60934 www supervisord 1370 0 0 100.0% 0.0%
60934 www php 1111 0 0 100.0% 0.0%
它的输出跟 top 类似,默认按照缓存的命中次数(HITS)排序,展示了每个进程的缓存命 中情况。具体到每一个指标,这里的 HITS、MISSES 和 DIRTIES ,跟 cachestat 里的含义一样,分别代表间隔时间内的缓存命中次数、未命中次数以及新增到缓存中的脏页数。
而 READ_HIT 和 WRITE_HIT ,分别表示读和写的缓存命中率。
指定文件的缓存大小
除了缓存的命中率外,还有一个指标可能也会很感兴趣,那就是指定文件在内存中的缓存大小。可以使用 pcstat 这个工具,来查看文件在内存中的缓存大小以及缓存比例。
pcstat 是一个基于 Go 语言开发的工具,所以安装它之前,你首先应该安装 Go 语言。
go get github.com/tobert/pcstat/pcstat
全部安装完成后,你就可以运行 pcstat 来查看文件的缓存情况了。比如,下面就是一个 pcstat 运行的示例,它展示了 /bin/ls 这个文件的缓存情况:
pcstat /bin/ls
+---------+----------------+------------+-----------+---------+
| Name | Size (bytes) | Pages | Cached | Percent |
|---------+----------------+------------+-----------+---------|
| /bin/ls | 157376 | 39 | 0 | 000.000 |
+---------+----------------+------------+-----------+---------+
这个输出中,Cached 就是 /bin/ls 在缓存中的大小,而 Percent 则是缓存的百分比。你看到它们都是 ,这说明 /bin/ls 并不在缓存中。
接着,如果你执行一下 ls 命令,再运行相同的命令来查看的话,就会发现 /bin/ls 都在缓存中了:
ls
pcstat /bin/ls
+---------+----------------+------------+-----------+---------+
| Name | Size (bytes) | Pages | Cached | Percent |
|---------+----------------+------------+-----------+---------|
| /bin/ls | 157376 | 39 | 13 | 033.333 |
+---------+----------------+------------+-----------+---------+
总结
Buffers 和 Cache 可以极大提升系统的 I/O 性能。通常,我们用缓存命中率,来衡量缓存的使用效率。命中率越高,表示缓存被利用得越充分,应用程序的性能也就越好。
可以用 cachestat 和 cachetop 这两个工具,观察系统和进程的缓存命中情况。其中:
- cachestat 提供了整个系统缓存的读写命中情况。
- cachetop 提供了每个进程的缓存命中情况。
不过要注意,Buffers 和 Cache 都是操作系统来管理的,应用程序并不能直接控制这些缓存的内容和生命周期。所以,在应用程序开发中,一般要用专门的缓存组件,来进一步提升性能。
比如,程序内部可以使用堆或者栈明确声明内存空间,来存储需要缓存的数据。再或者, 使用 Redis 这类外部缓存服务,优化数据的访问效率。