真正该盯vmstat的si/so列,持续超1000kb/s且swpd>0才是swap抖动硬证据;仅调vm.swappiness=1不够,须配memlock unlimited、innodb_use_sys_malloc=0及禁用thp、排查numa伪抖动。

怎么确认MySQL抖动真是Swap惹的祸
别看CPU、慢日志或SHOW PROCESSLIST——这些全会误导你。真正该盯的是内存换页行为:vmstat 1里si(swap-in)和so(swap-out)两列,单位KB/s;只要任一值持续超过1000,再配合free -h看到SwapUsed在涨,基本就坐实了。注意:swpd > 0且si/so > 0同时成立才是硬证据,used高但available还剩2G以上,通常不是Swap问题。
为什么只改vm.swappiness=1还不够
vm.swappiness=1只是降低内核换页倾向,不等于禁用Swap。当Buffer Pool配得过大、其他进程吃光剩余内存时,Linux仍会把mysqld的匿名页踢进Swap,导致查询线程卡在缺页中断里,延迟突增几毫秒到几百毫秒。关键点在于:swappiness控制的是“什么时候开始考虑Swap”,不是“会不会用Swap”。生产环境必须配套做三件事:
- 在
/etc/security/limits.conf里加mysql hard memlock unlimited和mysql soft memlock unlimited - 在
my.cnf的[mysqld]段加innodb_use_sys_malloc=0 - 确保mysqld由root启动(否则
memlock不生效),用prlimit -p $(pgrep mysqld) | grep memlock验证输出是unlimited
容器里MySQL的Swap陷阱特别多
宿主机上设了vm.swappiness=1,对Docker里的MySQL完全无效。必须单独给容器加--memory-swappiness=1参数,否则它默认继承宿主机的60。更隐蔽的是:Kubernetes Pod的resources.limits.memory没配swappiness字段时,也会回退到默认高值。验证方式很简单:docker exec -it mysql-container sysctl vm.swappiness,输出必须是1,而不是宿主机的值。
别漏掉NUMA和THP这两个伪Swap元凶
现象是vmstat显示si/so波动,但free -h里available充足,这时大概率是NUMA导致的伪抖动。运行numastat -p $(pgrep mysqld),如果numa_miss持续>5%,说明MySQL进程跨节点分配内存,触发远端访问+隐式换页。另一个干扰项是transparent_hugepage:如果cat /sys/kernel/mm/transparent_hugepage/enabled输出是[always]或[madvise],哪怕没真用大页,khugepaged也会干扰内存路径,造成类似Swap的毛刺。永久关掉它得改/etc/default/grub,加transparent_hugepage=never,再update-grub && reboot。











