前言
SWAP 内存交换分区对大家来说是一个经常被忽视的细节,如果大家对 SWAP 配置不是很熟悉可以参考文章内提到的 Red Hat SWAP SPACE 最佳实践配置链接。本文主要分享 SWAP 的基础知识和优化建议,以及如何使用 ansible 优雅的关闭和增加 SWAP 交换分区等实践心得。
Red Hat SWAP SPACE
Red Hat 官方给出的配置建议已经很详细了,我不再做多余介绍
当物理内存 (RAM) 量已满时,将使用 Linux 中的交换空间。如果系统需要更多内存资源并且 RAM 已满,则内存中的非活动页面将移动到交换空间。虽然交换空间可以帮助具有少量 RAM 的机器,但不应将其视为更多 RAM 的替代品。交换空间位于硬盘驱动器上,其访问时间比物理内存慢。交换空间可以是专用交换分区(推荐)、交换文件或交换分区和交换文件的组合。请注意,Btrfs 不支持交换空间。
在过去的几年里,推荐的交换空间量随着系统中的 RAM 量线性增加。然而,现代系统通常包含数百 GB 的 RAM。因此,推荐的交换空间被认为是系统内存工作负载的函数,而不是系统内存。
m 交换空间”说明了交换分区的建议大小,具体取决于系统中的 RAM 量以及您是否需要足够的内存供系统休眠。建议的交换分区大小是在安装过程中自动建立的。但是,要允许休眠,您需要在自定义分区阶段编辑交换空间。
表 15.1 “推荐的系统交换空间”中的建议对于内存较低(1 GB 或更少)的系统尤其重要。未能在这些系统上分配足够的交换空间可能会导致不稳定等问题,甚至导致已安装的系统无法启动。
在表 15.1“推荐的系统交换空间”中列出的每个范围之间的边界处,例如具有 2 GB、8 GB 或 64 GB 系统 RAM 的系统,可以根据选择的交换空间和休眠支持自行决定。如果您的系统资源允许,增加交换空间可能会带来更好的性能。对于具有超过 140 个逻辑处理器或超过 3 TB RAM 的系统,建议交换空间至少为 100 GB。 请注意,将交换空间分布在多个存储设备上还可以提高交换空间性能,尤其是在具有快速驱动器、控制器和接口的系统上
SWAP 预备知识
什么是 swap
swap 当我们指的名词的时候,它可以是一个分区,也可以是一个文件,是操作系统中一个存放从内存中置换出的数据的地方。 当我们指的是一个动词时候,代表的是从物理内存交换数据到 swap 分区这个动作。
为什么会 swap
- 当物理内存不够用时候,会根据特定的算法,把一部分内存交换到 swap 分区(此时还会伴随着高 IO)。但是并不是所有的内存都可以被交换到 swap 分区。
- kswapd 进程周期性对内存进行检查,如果发现高于水位线,则触发 swap,此举是为了不让系统剩余内存很少,防止出现突然的大内存申请。这块暂不深入讲解,后续再补充。
swap 的到底是什么
首先我们要知道,内存管理将内存分为 active 和 inactive,进程用户空间使用的映射包括了匿名映射 (anon) 和文件映射(file)。所有一共有 active anon,inactive anon,active file,inactive file。对于文件映射,由于本身是磁盘空间中的文件,所有它不会被 swap,当需要释放时候,脏数据直接写回磁盘,其他数据直接释放即可。内存交换到 swap,肯定是交换不活跃的数据,所有,inactive anon 是最主要的被交换的内存。那么对于操作系统来说,当我需要回收内存时候,你说它是针对文件映射好,还是针对匿名映射好,这就涉及到了一个参数:swapiness
swapiness
swapiness 是设置内存回收时候,更倾向于回收文件映射还是匿名映射,在 / proc/sys/vm/swappiness 设置值。对于 swapiness=100,那么两者之间的权重是一致的,值越小,越倾向于回收文件映射,不过如果达到系统高水位线,还是会 swap,除非直接使用 swapoff -a 等手段关闭系统 swap。
swap 的好坏
swap 的好处是当内存不足时候,可以将一部分交换出去,不会触发 oom-killer。跑得慢总比不能跑好。 swap 的坏处是交换时候,会触发高 IO,同时会降低系统的性能。对于我们隔离做的不好的时候,会影响到其他应用的性能。
swap 查看方法
一个工具往往具有多种用途,但是本文只说明针对 swap 问题
工具名称 | 使用姿势 | 采集指标来源 |
---|---|---|
free | free -h | /proc/meminfo |
top | 按 f,选择 swap | /proc/$pid/smaps |
vmstat | vmstat | /proc/meminfo |
iotop | iotop | |
iostat | iostat -xdm | |
pidstat | pidstat -d 1 | /proc/$pid/io |
# 通过此命令查看内存被哪些进程占用(单位是 MByte)
for i in `cd /proc;ls | grep "^[0-9]" | awk '$0 >100'` ;do awk '/Swap:/{a=a+$2}END{print '"$i"',a/1024"M"}' /proc/$i/smaps ;done 2>&1 | sort -k2nr | head
3131 102.676M
3127 94.4414M
3136 69.9648M
3129 61.1445M
3097 50.7695M
3086 47.0078M
3119 46.4102M
3106 42.4648M
3094 37.5547M
3092 36.8398M
# 注:以上结果输出 PID 与内存占用大小,通过 PID 可以找到对应进程
常见的 swap 优化思路
以 K8s 为代表的容器编排已经给出了比较简单粗暴的分类
- 有状态(Stateful)
- 无状态(Stateless)
针对有状态的服务比如 Database 数据库,Cache 缓存等,为了减少核心服务出现 Out of Memory(OOM)的情况,合理的使用 swap 并做好监控是非常有必要的。
针对无状态的服务比如 K8s,ElasticSearch 等,禁用 swap 的核心原因都是出于性能的考虑,但也需要注意配置内存的限制以及告警策略
Swap Off - why is it necessary?
Set up Elasticsearch » Important System Configuration » Disable swapping
swap 对性能的影响
这是显而易见的,但是还是有必要说的更清楚一点:内存交换 到磁盘对服务器性能来说是 致命 的。想想看:一个内存操作必须能够被快速执行。
如果内存交换到磁盘上,一个 100 微秒的操作可能变成 10 毫秒。再想想那么多 10 微秒的操作时延累加起来。不难看出 swap 对于性能是多么可怕。
最好的办法就是在你的操作系统中完全禁用 swap。这样可以暂时禁用:
sudo swapoff -a
如果需要永久禁用,你可能需要修改 /etc/fstab
文件,这要参考你的操作系统相关文档。
如果你并不打算完全禁用 swap,也可以选择降低 swappiness
的值。 这个值决定操作系统交换内存的频率。 这可以预防正常情况下发生交换,但仍允许操作系统在紧急情况下发生交换。
对于大部分 Linux 操作系统,可以在 sysctl
中这样配置:
vm.swappiness = 1
wappiness
设置为 1
比设置为 0
要好,因为在一些内核版本 swappiness
设置为 0
会触发系统 OOM-killer(注:Linux 内核的 Out of Memory(OOM)killer 机制)。
vm.swappiness 优化
swappiness 的值的大小对如何使用 swap 分区是有着很大的联系的。swappiness=0 的时候表示最大限度使用物理内存,然后才是 swap 空间,swappiness=100 的时候表示积极的使用 swap 分区,并且把内存上的数据及时的搬运到 swap 空间里面。linux 的基本默认设置为 60,具体如下:
cat /proc/sys/vm/swappiness
60
也就是说,你的内存在使用到 100-60=40% 的时候,就开始出现有交换分区的使用。大家知道,内存的速度会比磁盘快很多,这样子会加大系统 io,同时造的成大量页的换进换出,严重影响系统的性能,所以我们在操作系统层面,要尽可能使用内存,对该参数进行调整。
临时调整 swap,这只是临时调整的方法,重启后会回到默认设置的
# 配置
sysctl vm.swappiness=1
# 查看
cat /proc/sys/vm/swappiness
1
永久生效 swap 配置
# 要想永久调整的话,需要将在 / etc/sysctl.conf 修改,加上:
vim /etc/sysctl.conf
vm.swappiness=1
# 刷新生效
sysctl -p
关闭和开启 swap
使用 ansible 实现关闭 swap,config-swap-off.yml
---
- hosts: all
become: yes
gather_facts: no
tasks:
- name: Disable SWAP in fstab
replace:
path: /etc/fstab
regexp: '^(\s*)([^#\n]+\s+)(\w+\s+)swap(\s+.*)$'
replace: '#\1\2\3swap\4'
backup: yes
- name: Disable SWAP
shell: |
swapoff -a
使用 ansible 实现开启 swap,config-swap-on.yml
---
- hosts: all
become: yes
gather_facts: no
tasks:
- name: Reenable SWAP in fstab
replace:
path: /etc/fstab
regexp: '^#(\s*)([^#\n]+\s+)(\w+\s+)swap(\s+.*)$'
replace: '\1\2\3swap\4'
- name: Enable SWAP
shell: |
swapon -a
增加 swap
制作 swap 文件
# 创建一个 1G 的文件作为交换分区使用
dd if=/dev/zero of=/opt/swapfile bs=1M count=1000
# 格式化成 swap 分区
mkswap /opt/swapfile
# 打开 swap 分区
swapon /opt/swapfile
# 在 / etc/fstab 中增加一条记录如下
/opt/swapfile swap swap defaults 0 0
制作 swap 分区
# 创建一个 swap 分区
fdisk /dev/sdb
# 新建一个分区
n
p
default
default
...
# 修改分区 id 为 swap
t
82
# 写入分区表
w
# 同步内存和分区表信息
partprobe
# 格式化成 swap 分区
mkswap /dev/sdb1
# 打开 swap 分区
swapon /dev/sdb1
# 在 / etc/fstab 中增加一条记录如下
/opt/swapfile swap swap defaults 0 0
Tips: 如果本机已有 2G swap 交换分区, 又制作了一个 8G 的 swap 分区文件, 那么在执行 swapon
命令之后, swap 空间将为 10G(swap 空间会累加)