Linux 小内存 VPS 配置 Swap 完整指南(btrfs 踩坑记录)

Contersion 发布于 2026-04-20 42 次阅读


本文内容基于作者本人在实际部署过程中与 AI(Claude / ChatGPT 等)的多轮讨论与请教整理而成,并在部署完成、验证可行后由 AI 协助归纳成文。
文中所有命令、配置与流程均经过作者真实环境验证,但因服务器环境、软件版本、网络条件等差异,读者在复现时仍可能遇到本文未覆盖的问题。请结合自身实际情况谨慎操作,并自行承担相关风险。

本文记录在一台 1C 0.5G 配置的 KVM VPS 上配置 Swap 的完整过程,包含 btrfs 文件系统下的踩坑解决方案,以及针对代理/端口转发场景的内核参数优化建议。

背景

最近新开了一台 1 核 512MB 内存的 KVM 小鸡,主要用途是做代理和端口转发。这种低内存机器为了防止 OOM,配置 Swap 是必要操作。本以为是五分钟搞定的事,结果在 btrfs 文件系统上翻车了,记录一下完整流程。

一、Swap 大小怎么选

常见的经验法则是 swap = RAM × 2,但更实用的是按用途来定:

用途推荐 Swap 大小
轻量 web / 代理 / bot512MB ~ 1GB
Node.js / Python 应用1GB
偶尔编译代码1 ~ 2GB
数据库(MySQL/Postgres)1 ~ 2GB

0.5G 内存机器推荐 1GB Swap,够用且不会太占磁盘空间。

二、标准配置流程

通用步骤

# 1. 创建 1GB 的 swap 文件
sudo fallocate -l 1G /swapfile

# 2. 设置权限(必须只能被 root 读写)
sudo chmod 600 /swapfile

# 3. 格式化为 swap
sudo mkswap /swapfile

# 4. 立即启用
sudo swapon /swapfile

# 5. 添加到 /etc/fstab 开机自动挂载(先备份原文件)
sudo cp /etc/fstab /etc/fstab.bak
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

# 6. 验证是否生效
sudo swapon --show
free -h

正常情况下,执行到 swapon 这一步就能看到 Swap 生效。但这次翻车了。

三、踩坑:swapon failed: Invalid argument

问题现象

root@server:~# sudo swapon /swapfile
swapon: /swapfile: swapon failed: Invalid argument

mkswap 能正常执行,但 swapon 直接拒绝。

排查步骤

第一步:确认虚拟化类型

systemd-detect-virt
# 输出:kvm

KVM 是完整虚拟化,支持 swap,排除 OpenVZ/LXC 容器限制的可能。

第二步:换用 dd 创建文件

有时候 fallocate 在某些文件系统上会创建稀疏文件,导致 mkswap 能过但 swapon 拒绝。但这次换成 dd 依然报错。

第三步:查看内核日志

df -T /
# Filesystem  Type   ...
# /dev/vda3   btrfs  ...

sudo dmesg | tail -20
# [141925.195702] BTRFS warning (device vda3): swapfile must not be copy-on-write

真相大白:根分区是 btrfs,而 btrfs 的 swapfile 不能带 copy-on-write (CoW) 属性。

为什么 btrfs 有这个限制

btrfs 默认所有文件都启用 CoW,即修改数据时会写到新的块位置,原数据块不变。但 swapfile 需要固定的物理块位置,内核要能稳定地往这些块里读写页数据。CoW 会让块地址动态变化,swap 机制就无法工作,所以内核直接拒绝。

正确做法

必须在文件为空时chattr +C 禁用 CoW,然后再写入数据。

# 1. 清理之前失败的文件
sudo swapoff /swapfile 2>/dev/null
sudo rm -f /swapfile

# 2. 创建空文件(注意必须是 touch,不能用 dd/fallocate)
sudo touch /swapfile

# 3. 关键步骤:禁用 CoW(必须在文件为空时执行)
sudo chattr +C /swapfile

# 4. 现在才能写入数据
sudo dd if=/dev/zero of=/swapfile bs=1M count=1024 status=progress

# 5. 后续常规步骤
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

# 6. 验证
free -h
swapon --show

执行成功后的输出:

               total        used        free      shared  buff/cache   available
Mem:           457Mi       116Mi        22Mi       6.4Mi       336Mi       340Mi
Swap:          1.0Gi          0B       1.0Gi

NAME      TYPE  SIZE USED PRIO
/swapfile file 1024M   0B   -2

小贴士:如何判断自己的根分区是不是 btrfs?执行 df -T / 看 Type 列即可。常见的 ext4xfs 不需要这步操作。

四、swappiness 调优

什么是 swappiness

vm.swappiness 控制内核将内存页换到 swap 的倾向。

  • 值越大:越倾向于把内存页换到 swap
  • 值越小:越倾向于保留在 RAM,优先回收文件 cache

Linux 默认值是 60,适合通用服务器,但不适合低内存 VPS

推荐值

场景推荐值原因
桌面 / 通用服务器60默认值,通用平衡
低内存 VPS(≤1G)10 ~ 20swap 在磁盘,频繁换页拖慢响应
代理 / 端口转发10对延迟敏感,swap 只做保险
数据库服务器1 ~ 10避免热数据被换出

关于 swappiness 和 OOM 的常见误解

误解:swappiness 越高越不容易 OOM。

真相:swappiness 不决定"是否 OOM",只决定"日常回收倾向"。当 RAM 真的快满时,不管 swappiness 是 10 还是 60,内核都会强制使用 swap

也就是说:

  • swappiness=10:RAM 用到 ~85% 才开始换
  • swappiness=60:RAM 用到 ~60% 就开始主动换页

真正防 OOM 的是 swap 总大小,而不是 swappiness。

配置方法

# 临时生效
sudo sysctl vm.swappiness=10

# 永久生效
echo "vm.swappiness=10" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

# 验证
cat /proc/sys/vm/swappiness

五、代理 / 端口转发场景的完整内核优化

对于代理、转发这类对延迟和并发敏感的场景,除了 swappiness,还有几个参数值得一起调:

sudo tee -a /etc/sysctl.conf <<EOF

# === 内存管理 ===
vm.swappiness=10
vm.vfs_cache_pressure=50

# === 网络转发(必开) ===
net.ipv4.ip_forward=1
net.ipv6.conf.all.forwarding=1

# === TCP 优化 ===
net.ipv4.tcp_fastopen=3
net.core.default_qdisc=fq
net.ipv4.tcp_congestion_control=bbr

# === 连接数上限 ===
net.core.somaxconn=4096
net.ipv4.tcp_max_syn_backlog=8192
EOF

sudo sysctl -p

参数说明

参数作用
vfs_cache_pressure=50降低内核回收文件 cache 的倾向,减少重复读盘
ip_forward内核级启用 IPv4 转发,做端口转发/NAT 必开
ipv6.conf.all.forwardingIPv6 版本的转发开关
tcp_fastopen=3启用 TFO,减少握手延迟(客户端+服务端)
default_qdisc=fq + tcp_congestion_control=bbr启用 Google BBR 拥塞控制,代理场景吞吐提升明显
somaxconnlisten 队列上限,代理并发连接多时防止丢连接
tcp_max_syn_backlogSYN 半连接队列,抗突发连接

BBR 需要内核 ≥ 4.9,现代主流发行版(Ubuntu 20.04+、Debian 10+)都已支持。

六、完整脚本

把前面的步骤整合成一个一键脚本,适用于 btrfs/ext4/xfs:

#!/bin/bash
# 1GB Swap 配置脚本(兼容 btrfs)

SWAPFILE="/swapfile"
SIZE_MB=1024

# 如已存在则清理
[ -f "$SWAPFILE" ] && swapoff "$SWAPFILE" 2>/dev/null && rm -f "$SWAPFILE"

# 创建空文件
touch "$SWAPFILE"

# 若是 btrfs 则禁用 CoW
FS_TYPE=$(df -T / | awk 'NR==2 {print $2}')
if [ "$FS_TYPE" = "btrfs" ]; then
    echo "检测到 btrfs,禁用 CoW..."
    chattr +C "$SWAPFILE"
fi

# 写入数据
dd if=/dev/zero of="$SWAPFILE" bs=1M count=$SIZE_MB status=progress
chmod 600 "$SWAPFILE"
mkswap "$SWAPFILE"
swapon "$SWAPFILE"

# 添加开机自动挂载
if ! grep -q "$SWAPFILE" /etc/fstab; then
    echo "$SWAPFILE none swap sw 0 0" >> /etc/fstab
fi

# swappiness 优化
sysctl vm.swappiness=10
grep -q "vm.swappiness" /etc/sysctl.conf || echo "vm.swappiness=10" >> /etc/sysctl.conf

echo "=== 配置完成 ==="
free -h
swapon --show

总结

  1. 低内存 VPS 必配 Swap,1GB 内存推荐 1~2GB Swap,0.5GB 内存推荐 1GB。
  2. **btrfs 下必须先 touchchattr +C**,最后才写数据,否则 swapon 必报 Invalid argument
  3. swappiness 不防 OOM,只影响日常换页倾向。代理机建议设为 10。
  4. 代理场景顺便开启 BBR,吞吐提升立竿见影。

踩坑不可怕,可怕的是踩了坑没记录。希望这篇文章能帮到同样遇到 btrfs 问题的朋友。

此作者没有提供个人介绍。
最后更新于 2026-04-20