Linux性能调优--Swap变高

上一篇总结了内存泄漏。
那么当发生了内存泄漏时,或者运行了大内存的应用程序,导致系统的内存资源紧张时,系统会如何应对呢?
会导致两种可能结果,内存回收和 OOM 杀死进程
OOM指的是系统杀死占用大量内存的进程,释放这些内存,再分配给其他更需要的进程。
内存回收指的是系统释放掉可以回收的内存,比如我前面讲过的缓存和缓冲区,就属于可回收内存。它们在内存管理中,通常被叫做文件页(File-backed Page)。
没有被修改过的直接回收,以后从硬盘直接读取就可以了。而那些被应用程序修改过的脏页必须要刷回硬盘,然后才能进行从内存释放。
刷回硬盘的两种方式:
1 可以在应用程序中,通过系统调用 fsync ,把脏页同步到磁盘中;
2 也可以交给系统,由内核线程 pdflush 负责这些脏页的刷新。
缓存和缓冲区,通过内存映射获取的文件映射页,都是可以释放的。而应用程序动态分配的堆内存,也就是我们在内存管理中说到的匿名页(Anonymous Page)。由于下次有可能还要访问,所以不能释放。但是可以暂时存在硬盘里面,下次要用的时候从硬盘直接读取。释放内存给其他需要的进程使用。这个就是Llinux的swap机制。
Swap 把这些不常访问的内存先写到磁盘中,然后释放这些内存,给其他更需要的进程使用。再次访问这些内存时,重新从磁盘读入内存就可以了。
原理
Swap 就是把一块磁盘空间或者一个本地文件(以下讲解以磁盘为例),当成内存来使用。它包括换出和换入两个过程
换出,就是把进程暂时不用的内存数据存储到磁盘中,并释放这些数据占用的内存。
换入,则是在进程再次访问这些内存的时候,把它们从磁盘读到内存中来。
现在的机器动不动就几G的内存,相比与以前几M的空间已经大了很多了。那是不是SWAP没有用处了吗?
内存在大,都有不够用的时候。
一个很典型的场景就是,即使内存不足时,有些应用程序也并不想被 OOM 杀死,而是希望能缓一段时间,等待人工介入,或者等系统自动释放其他进程的内存,再分配给它。
既然 Swap 是为了回收内存,那么 Linux 到底在什么时候需要回收内存呢?前面一直在说内存资源紧张,又该怎么来衡量内存是不是紧张呢?
直接内存回收,比如有新的大块内存分配请求,但是剩余内存不足。这个时候系统就需要回收一部分内存(比如前面提到的缓存),进而尽可能地满足新内存请求。
kswapd0,一个专门的内核线程用来定期回收内存。kswapd0 定义了三个内存阈值(watermark,也称为水位),分别是页最小阈值(pages_min)、页低阈值(pages_low)和页高阈值(pages_high)。
剩余内存小于页最小阈值,说明进程可用内存都耗尽了,只有内核才可以分配内存。
剩余内存落在页最小阈值和页低阈值中间,说明内存压力比较大,剩余内存不多了。这时 kswapd0 会执行内存回收,直到剩余内存大于高阈值为止。
剩余内存落在页低阈值和页高阈值中间,说明内存有一定压力,但还可以满足新内存请求。
剩余内存大于页高阈值,说明剩余内存比较多,没有内存压力。
可以通过内核选项 /proc/sys/vm/min_free_kbytes 来间接设置min_free_kbytes
pages_low = pages_min5/4
pages_high = pages_min
3/2
NUMA 与 Swap
NUMA架构图:
在这里插入图片描述
在 NUMA 架构下,多个处理器被划分到不同 Node 上,且每个 Node 都拥有自己的本地内存空间。而同一个 Node 内部的内存空间,实际上又可以进一步分为不同的内存域(Zone),比如直接内存访问区(DMA)、普通内存区(NORMAL)、伪内存区(MOVABLE)等。
可以通过 numactl 命令,来查看处理器在 Node 的分布情况,以及每个 Node 的内存使用情况。
numactl --hardware
available: 1 nodes (0)
node 0 cpus: 0 1 2 3
node 0 size: 7934 MB
node 0 free: 1621 MB
node distances:
node 0
0: 10
这跟SWAP有什么关系呢?
前面提到的三个内存阈值(页最小阈值、页低阈值和页高阈值),都可以通过内存域在 proc 文件系统中的接口 /proc/zoneinfo 来查看。
cat /proc/zoneinfo
输出有大量的指标,解释其中几个比较常用的
pages 处的 min、low、high,就是上面提到的三个内存阈值,
free 是剩余内存页数,它跟后面的 nr_free_pages 相同。
nr_zone_active_anon 和 nr_zone_inactive_anon,分别是活跃和非活跃的匿名页数。
nr_zone_active_file 和 nr_zone_inactive_file,分别是活跃和非活跃的文件页数。
如果某个 Node 内存不足时,系统可以从其他 Node 寻找空闲内存,也可以从本地内存中回收内存。具体选哪种模式,你可以通过 /proc/sys/vm/zone_reclaim_mode 来调整。它支持以下几个选项:
默认的 0 ,也就是刚刚提到的模式,表示既可以从其他 Node 寻找空闲内存,也可以从本地回收内存。
1、2、4 都表示只回收本地内存,2 表示可以回写脏数据回收内存,4 表示可以用 Swap 方式回收内存。
swappiness
回收的内存既包括了文件页,又包括了匿名页。回收的方式有:
对文件页的回收,当然就是直接回收缓存,或者把脏页写回磁盘后再回收。
而对匿名页的回收,其实就是通过 Swap 机制,把它们写入磁盘后再释放内存。
既然有两种不同的内存回收机制,那么在实际回收内存时,到底该先回收哪一种呢?
Linux 提供了一个 /proc/sys/vm/swappiness 选项,用来调整使用 Swap 的积极程度。
虽然 swappiness 的范围是 0-100,不过要注意,这并不是内存的百分比,而是调整 Swap 积极程度的权重,即使你把它设置成 0,当剩余内存 + 文件页小于页高阈值时,还是会发生 Swap。
实验环境
1 Ubuntu 18.04
2 你需要预先安装 sysstat 等工具,如 apt install sysstat
步骤:
1 free查看
在这里插入图片描述
2 如果没有开启swap,开启SWAP:

创建Swap文件

$ fallocate -l 8G /mnt/swapfile
# 修改权限只有根用户可以访问
$ chmod 600 /mnt/swapfile
# 配置Swap文件
$ mkswap /mnt/swapfile
# 开启Swap
$ swapon /mnt/swapfile

3 使用dd模拟大文件读取
dd if=/dev/sda1 of=/dev/null bs=1G count=2048
间隔1秒输出一组数据
-r表示显示内存使用情况,-S表示显示Swap使用情况
sar -r -S 1
在这里插入图片描述
sar 的输出两个表格,
第一个表格表示内存的使用情况,
第二个表格表示 Swap 的使用情况
各个字段什么意思?
kbcommit,表示当前系统负载需要的内存。它实际上是为了保证系统内存不溢出,对需要内存的估计值。
%commit,就是这个值相对总内存的百分比。
kbactive,表示活跃内存,也就是最近使用过的内存,一般不会被系统回收。
kbinact,表示非活跃内存,也就是不常访问的内存,有可能会被系统回收。
分析:
刚开始,剩余内存(kbmemfree)不断减少,而缓冲区(kbbuffers)则不断增大,由此可知,剩余内存不断分配给了缓冲区。
一段时间后,剩余内存已经很小,而缓冲区占用了大部分内存。这时候,Swap 的使用开始逐渐增大,缓冲区和剩余内存则只在小范围内波动。
退出sar,使用cachetop 查看是谁使用了缓存
在这里插入图片描述
dd 进程的读写请求只有 50% 的命中率,并且未命中的缓存页数(MISSES)为 849864(单位是页)。这说明,正是案例开始时运行的 dd,导致了缓冲区使用升高。
为什么 Swap 也跟着升高了呢?直观来说,缓冲区占了系统绝大部分内存,还属于可回收内存,内存不够用时,不应该先回收缓冲区吗?
通过 /proc/zoneinfo ,观察剩余内存、内存阈值以及匿名页和文件页的活跃情况。
-d 表示高亮变化的字段
-A 表示仅显示Normal行以及之后的15行输出
watch -d grep -A 15 ‘Normal’ /proc/zoneinfo
在这里插入图片描述
剩余内存(pages_free)在一个小范围内不停地波动。当它小于页低阈值(pages_low) 时,又会突然增大到一个大于页高阈值(pages_high)的值。
当剩余内存小于页低阈值时,系统会回收一些缓存和匿名内存,使剩余内存增大。其中,缓存的回收导致 sar 中的缓冲区减小,而匿名内存的回收导致了 Swap 的使用增大。紧接着,由于 dd 还在继续,剩余内存又会重新分配给缓存,导致剩余内存减少,缓冲区增大。
有一个有趣的现象,如果多次运行 dd 和 sar,你可能会发现,在多次的循环重复中,有时候是 Swap 用得比较多,有时候 Swap 很少,反而缓冲区的波动更大。
系统回收内存时,有时候会回收更多的文件页,有时候又回收了更多的匿名页。
swappiness,正是调整不同类型内存回收的配置选项。
$ cat /proc/sys/vm/swappiness
在这里插入图片描述
另一个问题就是,刚才的 Swap 到底影响了哪些应用程序呢?换句话说,Swap 换出的是哪些进程的内存?
按VmSwap使用量对进程排序,输出进程名称、进程ID以及SWAP用量
for file in /proc/*/status ; do awk ‘/VmSwap|Name|^Pid/{printf $2 " " $3}END{ print “”}’ $file; done | sort -k 3 -n -r | head
当然,一开始配置了 Swap,不要忘记在案例结束后关闭。你可以运行下面的命令,关闭 Swap:
swapoff -a

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章