在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的调整只是其中一个环节,但往往是最容易被忽视、效果最明显的一个。
