您的位置:首页 > 运维架构 > Linux

Linux性能优化从入门到实战:12 内存篇:Swap 基础

2020-02-04 17:59 316 查看

内存资源紧张时,可能导致的结果

(1)OOM 杀死大内存CPU利用率又低的进程(系统内存耗尽的情况下才生效:OOM 触发的时机是基于虚拟内存,即进程在申请内存时,如果申请的虚拟内存加上服务器实际已用的内存之和,比总的物理内存还大,就会触发 OOM);
(2)回收内存

  • 1 )回收文件页(File-backed Page)。有两种:
      第一种,回收Buffer和Cache。大部分文件页直接回收,以后有需要时,再从磁盘重新读取,脏页先写入磁盘后释放内存。脏页可以通过两种方式写入磁盘:在应用程序中可以通过系统调用 fsync ,把脏页同步到磁盘中;也可以交给系统,由内核线程 pdflush 负责这些脏页的刷新。
      第二种,回收通过内存映射获取的文件映射页。可以先被释放掉,下次再访问的时候,从文件重新读取。
  • 2 )回收匿名页(Anonymous Page,应用程序动态分配的堆内存)。Linux 的 Swap 机制,把一些不常访问的内存先写到磁盘中,然后释放这些内存,给其他更需要的进程使用,再次访问这些内存时,重新从磁盘读入内存。

回收内存的方式

(1)直接内存回收,比如回收Buffer和Cache,回收通过内存映射获取的文件映射页。
(2)定期回收内存,有一个专门的内核线程 kswapd0 定期回收内存。不仅回收文件页,还有匿名页。但 Swap 中只有匿名页。
为了衡量内存的使用情况,kswapd0 定义了三个内存阈值,分别是页最小阈值(pages_min)、页低阈值(pages_low)和页高阈值(pages_high)。剩余内存,则使用 pages_free 表示。
  

  • 剩余内存小于页最小阈值,说明进程可用内存都耗尽了,只有内核才可以分配内存。
  • 剩余内存落在页最小阈值和页低阈值中间,说明内存压力比较大,剩余内存不多了。这时 kswapd0 会执行内存回收,直到剩余内存大于高阈值为止。可以通过内核选项
    /proc/sys/vm/min_free_kbytes
    来间接设置,并且其他两个阈值,也根据页最小阈值计算得到:pages_low = pages_min5/4;pages_high = pages_min3/2
  • 剩余内存落在页低阈值和页高阈值中间,说明内存有一定压力,但还可以满足新内存请求。
  • 剩余内存大于页高阈值,说明剩余内存比较多,没有内存压力。

通过

/proc/zoneinfo
查看系统memory情况:

$ cat /proc/zoneinfo
...
Node 0, zone Normal
pages free 227894
min 14896
low 18620
high 22344
...
nr_free_pages 227894
nr_zone_inactive_anon 11082
nr_zone_active_anon 14024
nr_zone_inactive_file 539024
nr_zone_active_file 923986
...
  • pages 处的 min、low、high,就是上面提到的三个内存阈值,而 free 是剩余内存页数,它跟后面的 nr_free_pages 相同。
  • nr_zone_active_anon 和 nr_zone_inactive_anon,分别是活跃和非活跃的匿名页数。
  • nr_zone_active_file 和 nr_zone_inactive_file,分别是活跃和非活跃的文件页数。

Swap 原理

  Swap 把一块磁盘空间或者一个本地文件,当成内存来使用。它包括换出和换入两个过程:

  • 换出,就是把进程暂时不用的内存数据存储到磁盘中,并释放这些数据占用的内存。
  • 换入,则是在进程再次访问这些内存的时候,把它们从磁盘读到内存中来。

应用场景
(1)当内存不足时,有些应用程序也并不想被 OOM 杀死,而是希望能缓一段时间,等待人工介入,或者等系统自动释放其他进程的内存,再分配给它。
(2)我们常见的笔记本电脑的休眠和快速开机的功能,也基于 Swap 。休眠时,把系统的内存存入磁盘,这样等到再次开机时,只要从磁盘中加载内存就可以。这样就省去了很多应用程序的初始化过程,加快了开机速度。

NUMA 与 Swap

  
  在 NUMA 架构下,多个处理器被划分到不同 Node 上,且每个 Node 都拥有自己的本地内存空间。而同一个 Node 内部的内存空间,实际上又可以进一步分为不同的内存域(Zone),比如直接内存访问区(DMA)、普通内存区(NORMAL)、伪内存区(MOVABLE)等:

$ numactl --hardware
available: 1 nodes (0)
node 0 cpus: 0 1
node 0 size: 7977 MB
node 0 free: 4416 MB
...

  当某个 Node 内存不足时,系统可以从其他 Node 寻找空闲内存,也可以从本地内存中回收内存。具体选哪种模式,你可以通过

/proc/sys/vm/zone_reclaim_mode
来调整。它支持以下几个选项:

  • 默认的 0 ,也就是刚刚提到的模式,表示既可以从其他 Node 寻找空闲内存,也可以从本地回收内存。
  • 1、2、4 都表示只回收本地内存,2 表示可以回写脏数据回收内存,4 表示可以用 Swap 方式回收内存。

swappiness

内存回收的机制有两种:
(1)对文件页的回收,当然就是直接回收缓存,或者把脏页写回磁盘后再回收。
(2)对匿名页的回收,其实就是通过 Swap 机制,把它们写入磁盘后再释放内存。
  在实际回收内存时,到底该先回收哪一种呢?
  Linux 提供了一个

/proc/sys/vm/swappiness
选项,用来调整使用 Swap 的积极程度。swappiness 的范围是 0-100,数值越大,越积极使用 Swap,也就是更倾向于回收匿名页;数值越小,越消极使用 Swap,也就是更倾向于回收文件页。
  不过要注意,这并不是内存的百分比,而是调整 Swap 积极程度的权重,即使你把它设置成 0,当剩余内存 + 文件页小于页高阈值时,还是会发生 Swap

案例

  通过 sar 可以观察系统 memory 和 swap 使用情况的变化:

# -r 表示显示内存使用情况,-S 表示显示 Swap 使用情况,间隔 1 秒输出一组数据
$ apt install sysstat
$ sar -r -S 1
04:39:56    kbmemfree   kbavail kbmemused  %memused kbbuffers  kbcached  kbcommit   %commit  kbactive   kbinact   kbdirty
04:39:57      6249676   6839824   1919632     23.50    740512     67316   1691736     10.22    815156    841868         4

04:39:56    kbswpfree kbswpused  %swpused  kbswpcad   %swpcad
04:39:57      8388604         0      0.00         0      0.00

04:39:57    kbmemfree   kbavail kbmemused  %memused kbbuffers  kbcached  kbcommit   %commit  kbactive   kbinact   kbdirty
04:39:58      6184472   6807064   1984836     24.30    772768     67380   1691736     10.22    847932    874224        20

04:39:57    kbswpfree kbswpused  %swpused  kbswpcad   %swpcad
04:39:58      8388604         0      0.00         0      0.00

…

04:44:06    kbmemfree   kbavail kbmemused  %memused kbbuffers  kbcached  kbcommit   %commit  kbactive   kbinact   kbdirty
04:44:07       152780   6525716   8016528     98.13   6530440     51316   1691736     10.22    867124   6869332         0

04:44:06    kbswpfree kbswpused  %swpused  kbswpcad   %swpcad
04:44:07      8384508      4096      0.05        52      1.27
  • kbcommit,表示当前系统负载需要的内存。它实际上是为了保证系统内存不溢出,对需要内存的估计值。%commit,就是这个值相对总内存的百分比。
  • kbactive,表示活跃内存,也就是最近使用过的内存,一般不会被系统回收。
  • kbinact,表示非活跃内存,也就是不常访问的内存,有可能会被系统回收。

观察得到:
(1)kbmemfree 减少、kbbuffers 增大,说明剩余内存不断分配给了缓冲区;
(2)一段时间后,剩余内存已经很小,而缓冲区占用了大部分内存。这时候,Swap 的使用开始逐渐增大,缓冲区和剩余内存则只在小范围内波动。
  如何解释以上过程?

  通过 cachetop 可以观察系统 cache 当前的情况:

$ cachetop 5
12:28:28 Buffers MB: 6349 / Cached MB: 87 / Sort: HITS / Order: ascending
PID      UID      CMD              HITS     MISSES   DIRTIES  READ_HIT%  WRITE_HIT%
18280 root     python                 22        0        0     100.0%       0.0%
18279 root     dd                  41088    41022        0      50.0%      50.0%

  可以看到,dd 进程的读写请求只有 50% 的命中率,这是导致缓冲区使用升高的原因。

  通过 /proc/zoneinfo 查看系统 memory 情况:

# -A 表示仅显示 Normal 行以及之后的 15 行输出
$ watch -d grep -A 15 'Normal' /proc/zoneinfo
Node 0, zone   Normal
pages free     21328
min      14896
low      18620
high     22344
spanned  1835008
present  1835008
managed  1796710
protection: (0, 0, 0, 0, 0)
nr_free_pages 21328
nr_zone_inactive_anon 79776
nr_zone_active_anon 206854
nr_zone_inactive_file 918561
nr_zone_active_file 496695
nr_zone_unevictable 2251
nr_zone_write_pending 0
  • 当剩余内存小于页低阈值 ( pages_low ) 时,系统会回收一些缓存和匿名内存,使剩余内存增大。其中,缓存的回收导致 sar 中的缓冲区减小,而匿名内存的回收导致了 Swap 的使用增大。
  • 紧接着,由于 dd 还在继续,剩余内存又会重新分配给缓存,导致剩余内存减少,缓冲区增大。
  • 由于 swappiness 的设置,系统会选择合适的回收类型进行回收。

通过

/proc/pid/status 中的 VmSwap
可以查看每个进程 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

$ smem --sort swap  # 另一个命令,按照swap使用量排序
$ swapoff -a  # 关闭 Swap

降低 Swap 的使用,可以提高系统的整体性能,方法:

(1)禁止 Swap,现在服务器的内存足够大,所以除非有必要,禁用 Swap 就可以了。随着云计算的普及,大部分云平台中的虚拟机都默认禁止 Swap。
(2)如果实在需要用到 Swap,可以尝试降低 swappiness 的值,减少内存回收时 Swap 的使用倾向。
(3)响应延迟敏感的应用,如果它们可能在开启 Swap 的服务器中运行,你还可以用库函数 mlock() 或者 mlockall() 锁定内存,阻止它们的内存换出。

转载于:https://www.cnblogs.com/qccz123456/p/11192087.html

  • 点赞
  • 收藏
  • 分享
  • 文章举报
ak18888 发布了0 篇原创文章 · 获赞 0 · 访问量 622 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: