优化MySQL备份IO效率需调整内核参数:SSD/NVMe应设noop调度器、nomerges=1、read_ahead_kb=0、nr_requests=1024,并配noatime挂载及合理脏页控制,否则默认HDD优化策略会将随机读转为低效顺序预读,导致吞吐下降30%~50%。

直接改 nr_requests 和 read_ahead_kb 就能见效,但必须配合 SSD 调度器和禁用预读——否则备份时大量随机读反而被系统强行转成顺序预读,拖慢速度。
为什么 mysqldump 或 xtrabackup 备份小表时 IO 效率低
海量小表(比如几万张 information_schema 风格的分表)会导致备份工具频繁 open/close 文件、反复 seek,产生大量随机 I/O。Linux 默认对 HDD 优化的调度策略(如 cfq)和默认预读(read_ahead_kb=16384)会把本该零散的读请求合并、预取,结果是:磁盘头乱跑(HDD)或 SSD 内部队列拥堵(NVMe),实际吞吐下降 30%~50%。
- 现象:
iostat -x 1显示%util接近 100%,但r/s很低、await高达 20ms+,avgqu-sz堆积 - 本质:内核在“帮倒忙”——用顺序逻辑处理随机负载
- 关键点:物理备份(xtrabackup)直接读
.ibd文件,绕过 MySQL 缓存,完全暴露底层 I/O 路径问题
SSD/NVMe 上必须设为 noop + nomerges + 小预读
对 NVMe 或 SATA SSD,关闭所有调度干预,让设备自己管理队列。MySQL 物理备份是典型的高并发小 I/O 场景,不需要内核做请求排序或合并。
- 查当前调度器:
cat /sys/block/nvme0n1/queue/scheduler(输出应含[noop]) - 切到 noop:
echo noop > /sys/block/nvme0n1/queue/scheduler - 关请求合并:
echo 1 > /sys/block/nvme0n1/queue/nomerges(避免 CPU 消耗在合并上) - 预读设为 0:
echo 0 > /sys/block/nvme0n1/queue/read_ahead_kb(小表备份全是随机读,预读纯属污染 cache) - 队列深度调高:
echo 1024 > /sys/block/nvme0n1/queue/nr_requests(匹配 NVMe 多队列能力)
脏页与 swap 控制影响备份稳定性
备份过程本身不写数据,但若系统同时有其他写入(如 binlog 刷盘、监控采集),脏页堆积会触发后台刷盘,抢占 I/O 带宽。swap 活跃更致命——xtrabackup 进程一旦被换出,恢复时卡顿数秒,await 直接飙升。
Linux 安全审计工具,检查 SSH 配置、开放/监听端口、防火墙规则(ufw/iptables/nftables)、失败登录尝试、sudoers 权限...
- 临时禁用 swap 倾向:
sysctl -w vm.swappiness=1(不是 0,避免 OOM killer 误杀) - 收紧脏页刷写节奏:
sysctl -w vm.dirty_ratio=15、vm.dirty_background_ratio=5(防突发写压垮备份流) - 确认无 swap 使用:
free -h中Swap行used为 0;如有,swapoff -a临时关闭
文件系统挂载参数不能忽略
xtrabackup 读的是原始文件,挂载选项直接影响 open/read 系统调用开销。尤其 noatime 对海量小表意义极大——每 open 一个表就少一次元数据更新。
- XFS 推荐挂载:
defaults,noatime,nodiratime,discard(discard对长期运行的备份任务帮助不大,但无害) - ext4 必加:
noatime,nodiratime,commit=60(commit=60减少日志刷盘争抢,noatime是刚需) - 验证是否生效:
findmnt -o SOURCE,TARGET,FSTYPE,OPTIONS /var/lib/mysql,检查输出含noatime
最易被忽略的是 nomerges 和 read_ahead_kb=0 的组合——单独调一个没用,必须一起关。很多运维只改了调度器,发现效果不明显,其实预读还在后台偷偷拉几十 MB 数据进来,把 SSD 的 DRAM cache 占满,真正备份需要的 page 反而被挤出去了。










