在Ubuntu服务器运维中,swapiness参数设置不当是导致系统频繁换页、响应延迟的常见元凶。默认值60意味着内核会比较积极地将内存数据迁移到swap分区,当物理内存压力增大时,系统会大量进行磁盘I/O操作,造成明显的卡顿和延迟。最直接的解决办法是将swapiness调低到10甚至1,让内核尽量使用物理内存,只在真正内存不足时才启用swap。具体命令就是执行sudo sysctl vm.swappiness=10,然后把这个值写入/etc/sysctl.conf文件中永久生效。这一调整在数据库服务器、Web应用服务器、容器宿主机等场景下效果非常显著。

什么是swapiness以及它为什么会导致延迟

swapiness是Linux内核的一个参数,取值范围是0到100,它控制内核将内存中不活跃的页面移动到swap分区的积极程度。数值越高,内核越倾向于把数据往swap里搬;数值越低,内核越倾向于保留数据在物理内存中。Ubuntu默认设置为60,这个值对于桌面用户可能还行,但对于服务器来说偏高了。因为服务器通常需要快速响应请求,而swap分区的读写速度比物理内存慢几个数量级,一旦触发大量换页操作,CPU等待I/O的时间会急剧增加,用户感受到的就是系统变慢、请求超时、服务不稳定。

如何查看当前swapiness值和swap使用情况

在动手调整之前,先看一下当前的状态。打开终端执行以下命令查看swapiness当前值:

cat /proc/sys/vm/swappiness

同时查看系统swap分区的使用情况:

free -h

或者用更详细的方式:

swapon --show

如果你看到swap分区已经被大量使用,比如8G内存的机器swap用了2G以上,那基本可以确认swapiness设置有问题,需要立刻调整。

临时调整swapiness值的方法

临时调整不需要重启,立即生效,适合先测试效果。执行以下命令:

sudo sysctl vm.swappiness=10

如果你的服务器是专门跑数据库的,比如MySQL、PostgreSQL,可以直接设为1:

sudo sysctl vm.swappiness=1

设为1并不是完全禁用swap,而是告诉内核除非物理内存真的快用完了,否则不要主动换页。这对于需要大量缓存的数据库服务来说是最佳实践。调整后可以用cat /proc/sys/vm/swappiness再次确认值已经改变。

永久修改swapiness配置

临时调整重启后会失效,所以必须写入配置文件。编辑/etc/sysctl.conf文件:

sudo nano /etc/sysctl.conf

在文件末尾添加一行:

vm.swappiness=10

保存退出后,执行以下命令让配置立即生效:

sudo sysctl -p

这样即使服务器重启,swapiness也会保持你设定的值。建议把这个操作写入你的服务器初始化脚本或者运维文档中,确保每台新机器都按这个标准配置。

不同业务场景下的推荐值

不是所有服务器都适合同一个swapiness值,要根据实际业务来定。下面给出几种常见场景的推荐:

数据库服务器(MySQL、PostgreSQL、Redis等):推荐设为1。数据库需要大量内存做缓存和缓冲池,频繁换页会直接导致查询变慢、事务延迟。

Web应用服务器(Nginx、Apache、Tomcat等):推荐设为10。Web服务需要快速响应,但偶尔有些不活跃进程可以适当换出。

容器宿主机(Docker、K8s节点):推荐设为10或更低。容器本身就有内存限制,宿主机层面应该尽量避免换页影响容器性能。

开发测试机或者桌面环境:可以保持默认60,或者设为30-40。这类机器对延迟不敏感,适当换页反而能腾出内存给前台应用。

除了swapiness还需要关注哪些相关参数

光调swapiness有时候不够,还有几个相关的内核参数需要一起优化。首先是vm.dirty_ratio和vm.dirty_background_ratio,它们控制内核将脏数据刷到磁盘的时机。如果这两个值太高,大量脏数据堆积会导致I/O突然飙升。推荐设置:

vm.dirty_ratio = 10
vm.dirty_background_ratio = 5

其次是vm.vfs_cache_pressure,控制内核回收目录和inode缓存的积极程度。文件服务器可以设低一些:

vm.vfs_cache_pressure = 50

这些参数同样写入/etc/sysctl.conf中,然后sudo sysctl -p生效。

如何监控调整后的效果

调整完不是就完事了,要持续监控确认效果。可以用vmstat命令实时查看换页情况:

vmstat 1

重点关注si和so两列,分别代表从swap换入和换出的数据量(单位是KB/s)。如果这两个值长期接近0,说明换页基本停止了,调整成功。如果还是有较大数值,说明内存确实不够用,需要考虑加内存或者优化应用本身的内存占用。

另外可以用sar -W查看历史换页统计,或者用iostat -x 1监控磁盘I/O是否因为swap操作而升高。这些工具组合使用,能让你对系统状态有全面的把握。

什么时候不应该降低swapiness

虽然降低swapiness对大多数服务器有好处,但也有例外情况。如果你的服务器物理内存本身就很小(比如1G或2G),而且跑的是多个轻量级服务,适当的换页反而是必要的,设太低可能导致OOM Killer直接杀掉进程。这种情况下建议设为30-40,同时尽快升级内存。

还有一种情况是服务器上运行了某些特殊应用,它们自己管理内存比内核更高效,比如某些Java应用通过JVM参数控制堆内存。这时候swapiness设为1也没问题,因为JVM不会让自己的堆被换出到swap。

swap分区本身的配置也很重要

除了调参数,swap分区的大小和位置也影响性能。如果你用的是SSD,swap放在SSD上比放在机械硬盘上好得多,因为SSD的随机读写速度快很多。但即便是SSD,也比物理内存慢,所以能不用swap就不用。

swap分区大小建议:如果内存小于4G,swap设为内存的2倍;内存4G到16G,swap设为等于内存大小;内存16G以上,swap设为4G到8G就够了。现在很多云服务器默认不配swap,你可以手动创建一个swap文件:

sudo fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

然后写入/etc/fstab实现开机自动挂载:

/swapfile none swap sw 0 0

实战案例:调整前后的性能对比

我之前运维过一台8G内存的Ubuntu 22.04服务器,跑MySQL和一个Node.js应用。默认swapiness=60的时候,vmstat显示si和so经常有几百KB/s的换页,MySQL慢查询频繁出现,页面响应时间从200ms飙到2秒以上。把swapiness改成1之后,换页基本归零,MySQL慢查询消失,平均响应时间稳定在150ms以内。这个改动零成本,效果立竿见影。

总结和运维建议

Ubuntu运维中调整swapiness是一个简单但高回报的优化手段。核心要点就是:服务器场景把值设低(1-10),配合监控确认效果,同时关注内存总量是否足够。不要盲目追求设为0,因为设为0在极端情况下可能触发OOM。建议把这项调整纳入服务器标准化部署流程,每台机器上线前都检查一遍。配合vm.dirty_ratio等参数一起调优,能让你的Ubuntu服务器在高负载下依然保持流畅响应。

最后提醒一点,任何参数调整都要先在测试环境验证,确认没有副作用再上生产。运维的本质是在稳定性和性能之间找到平衡点,swapiness的调整只是其中一个环节,但往往是最容易被忽视、效果最明显的一个。