备份与业务共用磁盘必然引发I/O争抢,表现为备份进程I/O wait飙升、业务r_await/w_await超20ms;根本解法是物理磁盘隔离或对从库备份,并合理限速xtrabackup、优化mysqldump参数及避开真实业务批处理时段。

备份任务和业务共用同一块磁盘时,I/O争抢几乎必然发生
MySQL备份(尤其是全量)会触发大量连续读,而OLTP业务则是高频率随机读写。两者在机械盘或低配SSD上共享同一数据盘时,iotop 会明显看到 mysqldump 或 xtrabackup 进程的 I/O wait 暴涨,同时业务查询的 r_await 和 w_await 超过 20ms 是常见信号。这不是配置问题,是物理层资源冲突。
最直接的解法是物理隔离:
- 备份目标路径必须挂载在与
/var/lib/mysql完全不同的物理磁盘(不是不同目录、不是LVM逻辑卷) - 若用云盘,确保备份盘和数据盘属于不同后端存储节点(例如 AWS 中 data volume 和 backup volume 不在同一 AZ 的 EBS 队列)
- 对只读从库做备份,主库磁盘完全不参与读操作——这是成本最低、效果最确定的方案
用 --throttle 和 --parallel 控制 xtrabackup 的 I/O 压力
xtrabackup 默认尽可能跑满磁盘带宽,尤其在 SSD 上容易压垮队列。不加限速的 --parallel=4 在万兆网络+NVMe 环境下可能瞬间打出 1.2GB/s 读流量,远超业务能容忍的余量。
实操建议:
- 先用
dd if=/dev/zero of=/tmp/test bs=1M count=1000 oflag=direct测出磁盘裸写吞吐,再按 30%~50% 设定--throttle值(例如实测 800MB/s,则设--throttle=300) -
--parallel值不要超过 CPU 核心数的一半,避免线程调度开销反噬性能 - 务必搭配
--no-lock(InnoDB 表)或--lock-ddl-per-table(混合引擎),否则仍可能触发元数据锁等待
mysqldump 备份期间 CPU 和内存吃紧,本质是序列化瓶颈
mysqldump 不是纯 I/O 工具:它要把每行数据转成 SQL 字符串,再拼接 INSERT 语句。这个过程大量消耗 CPU 和内存。当表有 TEXT/BLOB 字段或单行超 1MB 时,mysqldump 进程自身内存占用可能飙到 5GB+,触发系统 SWAP,连带拖慢所有进程。
缓解方法很具体:
- 加
--skip-extended-insert:避免单条超长 INSERT,降低内存峰值(但会增大 SQL 文件体积) - 用
--where="id BETWEEN 1 AND 10000"分批导出大表,配合脚本循环,把压力摊薄 - 绝对不要在 mysqldump 命令里加
--opt(默认开启),它隐含--add-drop-table和--create-options,加重解析负担;显式指定需要的参数更可控 - 如果只是为恢复用,优先选
xtrabackup;mysqldump更适合跨版本迁移或审计类导出
真正被忽略的点:备份窗口 ≠ 业务低峰,而是“无关键批处理”的时段
凌晨 2–4 点看似低峰,但如果业务有定时月结、报表生成、风控模型训练等后台任务,此时启动备份照样抢 I/O。曾有个案例:备份脚本固定在 2:30 启动,而财务系统每月 1 号凌晨 2:15 开始跑 45 分钟账务核对,两者撞上后 aqu-sz 长期 > 16,P99 查询延迟从 80ms 拉到 2.3s。
所以必须查清三件事:
- 用
crontab -l和ps aux | grep -E "(python|java|sh)"扫描所有定时任务 - 检查监控系统中过去一周的
%iowait和load average波谷,找真实空闲区间 - 把备份调度时间写死成固定值,不如用轻量脚本检测:
pgrep -f "report_gen.py" >/dev/null || /path/to/backup.sh


















