Linux性能】Linux cache占用大量内存,如何分析是哪些进程、文件导致?

【Linux性能】Linux cache占用大量内存,如何分析是哪些进程、文件导致?

一、问题由来

我们使用Linux时,时常发现,cache占用大量内存。

如下面的示例,通过free命令查询内存情况,buff/cache已经占用了2.1G。Linux 2.4 开始, "buffer" 和 "cache" 已经被统一为页缓存,也就是cache整体是占用2.1G,而used才282M,导致了整体内存使用量很高。

[root@localhost ~]# free -h
              total        used        free      shared  buff/cache   available
Mem:           3.3G        282M        1.0G         40M        2.1G        2.8G
Swap:          3.0G          0B        3.0G

那我们如何能找出是由哪些进程和文件导致的cache?

二、Linux cache里的是什么?

首先,我们要了解 cache 是什么?

  • cache 是文件数据的页缓存,在使用MMap缓冲 I/O(Buffered I/O)预读取(Read-Ahead)*等技术*读、写文件时,内核会产生页缓存。当然,如果使用裸 I/O(Raw I/O)直接 I/O(Direct I/O)可以绕过页缓存,直接在磁盘或分区上进行 I/O 操作。
  • 从写的角度来说,不仅可以优化磁盘和文件的写入,对应用程序也有好处,应用程序可以在数据真正落盘前,就返回去做其他工作。
  • 从读的角度来说,不仅可以提高那些频繁访问数据的读取速度,也降低了频繁 I/O 对磁盘的压力。

三、查看Linux cache的工具

如何查看cache缓存了哪些文件内容?可以通过下面这些工具实现。

1 各种工具的功能对比

工具包含fincore、pcstat、hcache、vmtouch等,下面对这些工具做对比、功能介绍。

image-20240115204942441

incore已经很久不维护了,下面不再讲解fincore,对其他工具将做详细说明。

2 特殊系统的定制工具

2.1 es-pcstat

为Elasticsearch专门定制的工具。参考:Elasticsearch 内存占用分析及 page cache 监控

四、pcstat

1 安装

安装pcstat有下面几种方式。

1.1 直接使用官方提供的可执行文件

官方提供了可执行文件可以直接下载,这样就不用自己编译了,如下所示:

if [ $(uname -m) == "x86_64" ] ; then
    curl -L -o pcstat https://github.com/tobert/pcstat/raw/2014-05-02-01/pcstat.x86_64
else
    curl -L -o pcstat https://github.com/tobert/pcstat/raw/2014-05-02-01/pcstat.x86_32
fi

但是,注意上面方式下载的文件是2014年编译的,有一些不足:

  1. 有一些 bug
  2. 只针对部分操作系统和CPU架构可用
  3. 未包含当前最新的功能。

所以,推荐自己编译出可执行文件pcstat,该工具可以拷贝到各个机器上去执行。

1.2 手动编译、安装

按照下面步骤操作

1.如果没有安装go语言包,需要先安装go

dnf install -y golang

2.clone源码

# clone 源码
git clone https://github.com/tobert/pcstat.git

3.编译pcstat源码

cd pcstat
# pcstat源工程是go语言的,所以需要build go工程
# go build 会自动下载相应的包或依赖包,但是访问golang.org网络不一定通,用VPN也不一定
# 所以可以指定用阿里云的golang镜像
go env -w GO111MODULE=on
go env -w GOPROXY=https://mirrors.aliyun.com/goproxy/
# build好后会有一个pcstat文件
go build

4.运行、验证

# 给pcstat文件赋予执行权限
chmod 755 pcstat
# 用执行pcstat验证一下
./pcstat /usr/local/bin/*

# 也可以复制到/usr/local/bin目录下,这样可在任何位置运行 pcstat
sudo cp -a pcstat /usr/local/bin
# 验证
pcstat /usr/local/bin/*

1.3 注意事项

1.3.1 不同操作系统、CPU架构的可执行文件不一样

例如,我自己搭建的VM的操作系统是linux,CPU架构是arm64,使用官方提供的"2014-05-02-01/pcstat.x86_64",或者是linux\amd64的可执行文件,是无法执行的,错误如下:

./pcstat
-bash: ./pcstat: cannot execute binary file

所以,需要自己针对需要执行pcstat的目标系统,编译与目标系统操作系统、CPU架构匹配的可执行文件。

有哪些操作系统和CPU架构?

操作系统和CPU架构的枚举,可以参考go的文档:

github.com/golang/go/b…

var knownOS = map[string]bool{ // 操作系统
	"darwin":    true, // macOS
	"ios":       true,
	"linux":     true,
	........
}
var knownArch = map[string]bool{ // CPU架构
	"amd64":       true,
	"arm":         true,
	"arm64":       true,  // 注意是arm64,不是amd64
	........
}

怎么知道运行的系统是什么操作系统,什么CPU架构?

可以使用go env的命令

go env GOOS GOARCH
linux
arm64

如何为其他操作系统、CPU架构的目标系统编译可执行文件?

我是linux/arm64的系统,能否为darwin/arm64系统编译可执行文件?

答案是可以的,go支持构建针对自己以外的操作系统和架构的 Go 二进制文件,这称为交叉编译。

使用方式:

# GOOS=OS GOARCH=ARCH go build
GOOS=darwin GOARCH=arm64 go build

2 使用

使用方式非常简单。

2.1 查询文件/目录有多少被载入缓存

命令是pcstat 指定的path ,path的几种示例/usr/*/usr/lib64/libdl-2.17.so/usr/**/** 。命令示例

 pcstat /usr/local/bin/*
+------------------------+----------------+------------+-----------+---------+
| Name                   | Size (bytes)   | Pages      | Cached    | Percent |
|------------------------+----------------+------------+-----------+---------|
| /usr/local/bin/pcstat  | 2542244        | 621        | 621       | 100.000 |
| /usr/local/bin/vmtouch | 120992         | 30         | 21        |  70.000 |
+------------------------+----------------+------------+-----------+---------+

2.2 指定pid查询指定进程对应的文件cache:

pcstat -pid 20908
+------------------------------------------------------------+----------------+------------+-----------+---------+
| Name                                                       | Size (bytes)   | Pages      | Cached    | Percent |
|------------------------------------------------------------+----------------+------------+-----------+---------|
| /var/lib/containerd/io.containerd.metadata.v1.bolt/meta.db | 32768          | 8          | 6         |  75.000 |
| /usr/lib64/libc-2.17.so                                    | 1865776        | 456        | 456       | 100.000 |
| /usr/lib64/libdl-2.17.so                                   | 73984          | 19         | 19        | 100.000 |
| /usr/lib64/libpthread-2.17.so                              | 184376         | 46         | 46        | 100.000 |
| /usr/lib64/ld-2.17.so                                      | 160824         | 40         | 40        | 100.000 |
| /usr/bin/containerd                                        | 38979464       | 9517       | 9517      | 100.000 |
+------------------------------------------------------------+----------------+------------+-----------+---------+

输出结果中的各列的意思如下:

  • Size: 文件的总大小。这是文件在硬盘上的完整大小。
  • Pages: 文件大小对应的内存页数。在大多数 Linux 系统中,一个内存页的大小是 4KB,所以这个数值是文件大小除以4KB的结果。
  • Cached: 文件在内存中的缓存页数。这是当前被操作系统缓存的该文件的部分大小(以内存页为单位)。
  • Percent: 文件被缓存的百分比。这个百分比是 Cached 除以 Pages 的结果

五、hcache

1 安装

安装方式有下面几种。

1.1 直接使用官方提供的可执行文件

官方提供了可执行文件可以直接下载,下载地址

注意:该包是针对linux,且应该是2020年之前编译的,所以有些功能不支持或者不完善,建议自己编译源码、安装.

1.2 手动编译、安装

步骤和hcache很类似,编译的一些注意事项可以参考上面pcstat部分。可按照下面步骤操作:

1.如果没有安装go语言包,需要先安装go,go 版本需要大于 1.12。

2.clone源码

# clone 源码
git clone https://github.com/silenceshell/hcache.git

3.编译hcache源码

cd hcache
# 源工程是go语言的,所以需要build go工程
# go build 会自动下载相应的包或依赖包,但是访问golang.org网络不一定通,用VPN也不一定
# 所以可以指定用阿里云的golang镜像
go env -w GO111MODULE=on
go env -w GOPROXY=https://mirrors.aliyun.com/goproxy/
# build好后会有一个hcache文件
go build

4.运行、验证

# 给hcache文件赋予执行权限
chmod 755 hcache
# 用执行hcache验证一下
./hcache /usr/local/bin/*

# 也可以复制到/usr/local/bin目录下,这样可在任何位置运行 hcache
sudo cp -a hcache /usr/local/bin
# 验证
hcache /usr/local/bin/*

2 使用

大部分功能继承于pcstat,其中有下面这些不同点。

2.1 sum功能

相比pcstat的结果,多了一行Sum,这个很有帮助,因为结果数据行比较多的时候,自己计算总和挺麻烦,而工具很贴心地提供了总和。

./hcache -pid 20618
+---------------------------------+----------------+-------------+----------------+-------------+---------+
| Name                            | Size           │ Pages       │ Cached Size    │ Cached Pages│ Percent │
|---------------------------------+----------------+-------------+----------------+-------------+---------|
| /usr/lib64/libc-2.17.so         | 1.779M         | 456         | 1.779M         | 456         | 100.000 |
| /usr/lib64/libpcre.so.1.2.0     | 259.742K       | 65          | 259.742K       | 65          | 100.000 |
| /usr/lib64/libselinux.so.1      | 200.172K       | 51          | 200.172K       | 51          | 100.000 |
| /usr/lib64/ld-2.17.so           | 157.055K       | 40          | 157.055K       | 40          | 100.000 |
|---------------------------------+----------------+-------------+----------------+-------------+---------|
│ Sum                             │ 2.857M         │ 738         │ 2.857M         │ 738         │ 100.000 │

2.2 查询全局top【结果不准确】

注意:该功能的初衷是挺好的,但是实际验证发现不准确,例如某一个文件被cached 1G,但是sudo ./hcache --top结果最高的可能才100M。

使用方式:sudo ./hcache --top xxx

sudo ./hcache --top 3
+--------------------------------+----------------+-------------+----------------+-------------+---------+
| Name                           | Size           │ Pages       │ Cached Size    │ Cached Pages│ Percent │
|--------------------------------+----------------+-------------+----------------+-------------+---------|
| /usr/lib/locale/locale-archive | 101.259M       | 25923       | 101.259M       | 25923       | 100.000 |
| /usr/bin/dockerd               | 66.375M        | 16993       | 66.375M        | 16993       | 100.000 |
| /usr/bin/containerd            | 37.174M        | 9517        | 37.174M        | 9517        | 100.000 |
|--------------------------------+----------------+-------------+----------------+-------------+---------|
│ Sum                            │ 204.808M       │ 52433       │ 204.808M       │ 52433       │ 100.000 │

六、查看文件被哪些进程占用

通过上面的命令,我们知道了哪些文件占用较多cache。下面就可以通过lsof命令查看文件被哪些使用了,然后再去分析进程是如何在操作文件的。

1 lsof查看文件被进程占用情况

lsof /root/logfile/app.log
COMMAND  PID USER   FD   TYPE DEVICE  SIZE/OFF     NODE NAME
less    4964 root    4r   REG  253,0 110081812 17563958 app.log
tail    5184 root    3r   REG  253,0 110081812 17563958 app.log

七、小结

以上对查询cache的工具做了介绍:

  • 通过pcstat、hcache、vmtouch等工具可以查看哪些文件被加载到了cache,占用多少,以及进程关联的文件cache,通过lsof。
  • 通过lsof命令查看文件被哪些进程使用了。
posted @ 2024-01-16 09:08  寻梦99  阅读(2893)  评论(0)    收藏  举报