详细讲解内核的 swap 行为机制 、常用调优开关 、在 SLES 上怎么查配置与用量/怎么改 。最后附实战小抄 与常见场景建议。
1) 内核的 Swap 行为(怎么决定"换出/换入")
-
目标:在内存紧张时回收匿名页(anonymous pages)以维持可用内存与缓存命中率,避免 OOM。
-
优先回收顺序(简化理解)
- 回收页缓存(file cache:可从磁盘重读的页面)。
- 如果匿名页压力仍高 → 换出(swap out)匿名页,把其内容写到 swap 空间。
- 如果回收/换出仍无法满足水位线(watermarks) → 触发 direct reclaim ,甚至 OOM Killer。
-
参与组件
kswapd
:后台页面回收守护,按水位线扫描 LRU(active/inactive 列表)。- LRU 列表:匿名页/文件页各有 active 与 inactive 两套 LRU,内核按访问频率和脏页情况移动页面。
- Direct reclaim:分配内存的进程自己参与回收,可能导致明显延迟。
- NUMA:优先在本节点回收,不足才跨节点迁移/回收。
- THP(透明大页)被换出前通常会被拆分为 4K 页。
-
换入/换出指标
- swap out :把匿名页写到 swap(
vmstat
中so
)。 - swap in :访问换出的页,再从 swap 读回(
vmstat
中si
)。 - 高
si/so
长时间持续通常意味着内存压力大或参数不合适。
- swap out :把匿名页写到 swap(
2) 关键调优开关(/proc/sys/vm/*)
-
vm.swappiness
(0--100,默认 60)- 数值高:更积极换出匿名页,留更多页缓存。
- 数值低:尽量少换匿名页(但不是完全不换)。
- 经验:数据库/延迟敏感应用 1--10;通用服务器 30--60;桌面 60 附近。
-
vm.vfs_cache_pressure
(默认 100)- 越大越积极回收 inode/dentry 缓存。I/O 密集型可适当降低以保留缓存。
-
vm.watermark_scale_factor
/vm.min_free_kbytes
- 控制回收触发的"余量"。在高内存主机上,适当调大
min_free_kbytes
可减轻抖动。
- 控制回收触发的"余量"。在高内存主机上,适当调大
-
vm.dirty_*
(dirty_ratio
/dirty_background_ratio
等)- 影响脏页回写节奏,与 swap 没直接关系,但会影响整体回收压力。
-
vm.page-cluster
- 影响 swap 的读聚合大小(换入时的预读页数),默认 3(2^3=8 页)。
-
zswap / zram(可选)
- zswap:匿名页先压缩后放内存后备区,必要时才写物理 swap,减少 I/O。
- zram:在内存中创建压缩块设备作为 swap,适合 I/O 受限环境。
3) 在 SLES 上如何查看与管理 Swap
3.1 查看当前 swap 配置与用量
bash
# 列出所有 swap 设备/文件(含优先级)
cat /proc/swaps
# 或
swapon --show --bytes --priority
# 汇总:总量/已用/剩余
free -h
grep -E 'Swap(Total|Free|Cached)' /proc/meminfo
# 实时换入/换出速率
vmstat 1 # 看 si/so 列
# 或:sar(需 sysstat)
sar -W 1
# 看整体内存/回收状态
cat /proc/meminfo | egrep 'Active|Inactive|Swap|MemFree|Cached'
3.2 看系统挂载与 fstab
bash
# 所有 swap 单元(systemd)
systemctl list-units --type=swap
# fstab 配置
grep -n swap /etc/fstab
3.3 查看/调整内核参数
bash
# 当前 swappiness
cat /proc/sys/vm/swappiness
# 临时调整(立即生效,重启丢失)
sudo sysctl vm.swappiness=10
# 持久化(新建/修改)
echo "vm.swappiness = 10" | sudo tee /etc/sysctl.d/99-swap-tuning.conf
sudo sysctl --system
3.4 每进程使用了多少 swap?
ini
# 列出最占 swap 的进程(需要 root)
sudo bash -c 'for f in /proc/[0-9]*/status; do
pid=${f#/proc/}; pid=${pid%/status}
name=$(grep -m1 ^Name: $f | awk "{print $2}")
vswap=$(grep -m1 ^VmSwap: $f | awk "{print $2}")
[[ -n "$vswap" ]] && echo -e "$vswap\t$pid\t$name"
done | sort -nr | head -50'
3.5 启用/关闭 swap(谨慎)
bash
# 立刻启用所有 fstab 定义的 swap
sudo swapon -a
# 关闭所有 swap(可能触发大量换入,谨慎)
sudo swapoff -a
3.6 新建一个 swap 文件(SLES 通用)
bash
# 例:创建 32G swapfile
sudo fallocate -l 32G /swapfile # 或 dd if=/dev/zero of=/swapfile bs=1M count=32768
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
# 持久化到 fstab(优先级 100)
echo '/swapfile none swap defaults,pri=100 0 0' | sudo tee -a /etc/fstab
3.7 使用 zswap(若内核/发行版支持,SLES15 可用)
bash
# 查看是否启用
cat /sys/module/zswap/parameters/enabled # Y/N
# 临时启用
echo 1 | sudo tee /sys/module/zswap/parameters/enabled
# 或加到内核参数:zswap.enabled=1(下次引导生效)
统计信息通常在
debugfs
:/sys/kernel/debug/zswap/
(需挂载 debugfs)。
3.8 使用 zram 作为压缩内存 swap(可选)
bash
# 加载并创建一个 16G 的 zram 设备
sudo modprobe zram
sudo zramctl -f -s 16G
# 格式化为 swap 并启用
sudo mkswap /dev/zram0
sudo swapon /dev/zram0
持久化可用
systemd-zram-generator
(若 SLES 仓库提供)或开机脚本。
3.9 多个 swap 的"优先级"和并发
- 相同优先级:Linux 会**条带化(striping)**使用它们,提高并行吞吐。
- 不同优先级:总是先用高优先级(数值越大优先级越高)。
- 查看优先级:
cat /proc/swaps
的Priority
列。 - 设置优先级:
/etc/fstab
加pri=200
,或swapon --priority 200 /dev/...
。
3.10 cgroup 对 swap 的限制(容器/服务)
-
cgroup v2(SLES 15 多为 v2):
- 目录下的
memory.swap.max
设置可用 swap 上限;memory.swap.current
查看已用。
- 目录下的
-
判断是否 v2:
mount | grep cgroup2
。 -
Systemd 单元里可用
MemorySwapMax=
(v2)限制服务可用的 swap。
4) 实战小抄(现场排查顺序)
-
有没有 swap?够不够?
cswapon --show; free -h
-
是否在"抖"(频繁换入/换出)?
bashvmstat 1 # 看 si/so 是否持续非零
-
谁在用 swap?
- 用上面的 per-process 脚本找大头。
-
是否 swappiness 太高/太低?
bashcat /proc/sys/vm/swappiness
-
I/O 是否跟不上(swap 设备很慢)?
iostat -xz 1
(来自sysstat
包),看 swap 设备的等待。
-
是否需要启用 zswap/zram 来减 I/O?
- 适合云主机/慢盘场景。
5) 常见场景建议
- 数据库/低延迟服务 :
vm.swappiness=1~10
,尽量避免匿名页换出;swap 只作保险。 - 通用应用服务器 :
vm.swappiness=30~60
,保留一定页缓存。 - 容器平台 :考虑用 cgroup v2 控制每个服务的
MemoryMax
/MemorySwapMax
。 - I/O 受限(云盘/机械盘) :启用 zswap 或小容量 zram,减少物理交换写入。
- 超大内存主机 :适当增大
vm.min_free_kbytes
(保持更高的可用水位,降低抖动)。