备份脚本须以租户专属系统用户运行,目录权限设为700,禁用--result-file和--all-databases,动态获取库名并显式指定,xtrabackup需限定--databases,备份用户禁跨库访问,错峰调度并限制i/o与cpu,文件名含租户、端口、库名及精确时间戳。

备份脚本必须以租户对应系统用户身份运行
直接用 root 或 mysql 用户执行所有备份,会导致文件权限失控、租户间可互相读取备份文件——MySQL自身不管理备份文件权限,全靠Linux文件系统控制。一旦多个租户的备份写进同一目录且属主混乱,就等于裸奔。
实操建议:
- 为每个租户创建独立系统用户(如
tenant_a、tenant_b),禁止共用 - 每个租户的备份目录归属其对应用户,权限设为
700:chown tenant_a:tenant_a /backup/tenant_a - 备份命令必须显式切换用户:
sudo -u tenant_a mysqldump -h127.0.0.1 -P3307 db_tenant_a > /backup/tenant_a/db_tenant_a_$(date +\%Y-\%m-\%d_\%H\%M\%S).sql - 禁用
mysqldump --result-file:该参数由mysqld进程自身写盘,权限继承自mysqld用户(通常是mysql),无法按租户隔离
避免全库 dump,严格限定 --databases 参数值
一个实例里混存多个租户库(如 db_tenant_a、db_tenant_b)很常见,但用 mysqldump --all-databases 会把所有库打包成一个文件,既无法恢复单租户,也破坏了隔离边界。
实操建议:
- 动态获取租户专属库名:
mysql -Nse "SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME LIKE 'db_tenant_a%'" - 显式指定库名列表:
mysqldump -u backup_user -p'xxx' --databases db_tenant_a db_tenant_a_log,不带通配符、不写* - Percona XtraBackup 同样要加
--databases=db_tenant_a,留空或写--databases=*等同于全量备份 - 备份用户禁止拥有
mysql、information_schema库的SELECT权限,防止跨库探测
错峰调度 + 资源限制,防止 I/O 和 CPU 打满
多个实例的备份任务如果在同一时间启动,会集中触发大量磁盘随机读(InnoDB页加载)、顺序写(SQL文件生成)、CPU压缩(若启用 gzip),极易导致其他实例响应延迟飙升,甚至触发 innodb_buffer_pool_wait_free 告警。
实操建议:
- 按实例端口或租户优先级错开 cron 时间:比如
tenant_a在02:17,tenant_b在02:47,避开整点 - 用
ionice -c2 -n7降低备份进程I/O优先级,避免抢占在线业务的磁盘队列 - 用
cpulimit -l 30限制 mysqldump 进程最多使用30%单核CPU(注意:需安装 cpulimit) - 不推荐在备份时启用
gzip:压缩本身吃CPU,且无法流式限速;改用备份后异步压缩,或直接存为未压缩 SQL
备份文件名必须含租户标识与精确时间戳
名字叫 backup.sql 或 full.sql 的文件,在多实例环境中等于没命名。三天后你根本分不清它是哪个租户、哪个实例、哪天凌晨跑出来的,恢复时选错就是生产事故。
实操建议:
- 固定格式:
tenant_a_3307_db_tenant_a_2026-10-15_021722.sql(租户_端口_库名_日期_时分秒) - 时间戳用
$(date +\%Y-\%m-\%d_\%H\%M\%S),不用%T(含冒号,Windows/FTP 不兼容) - 不依赖脚本所在路径或环境变量拼接名称——cron 中的
$PWD可能为空,容器里更不可靠 - 可加轻量校验码:
md5sum $file | cut -c1-4,追加到文件名末尾防覆盖误判











