数据库备份是每个DBA和运维人员的必修课。简单来说,备份就是给数据库"拍照片",而恢复则是把照片"洗"出来。但实际操作中,这个"拍照"过程远比想象中复杂。
全量备份就像给整个房子拍照,每次都会完整记录所有数据。而增量备份则只记录上次拍照后新添的家具或重新粉刷的墙面。在MySQL生态中,mysqldump是最常用的全量备份工具,而binlog则是实现增量备份的关键。
重要提示:生产环境中,备份策略必须考虑RPO(恢复点目标)和RTO(恢复时间目标)。全量+增量备份组合通常能在存储成本和恢复速度间取得平衡。
mysqldump的基本语法看似简单,但每个参数都暗藏玄机:
bash复制mysqldump -u[用户名] -p[密码] [选项] [数据库名] > [备份文件].sql
实际生产环境中,我强烈建议使用以下增强版命令:
bash复制mysqldump -uroot -p'ComplexP@ssw0rd!' \
--single-transaction \
--master-data=2 \
--routines \
--triggers \
--events \
--hex-blob \
--flush-logs \
testdb | gzip > /backup/testdb_full_$(date +%Y%m%d).sql.gz
参数详解:
--single-transaction:创建事务一致性快照,对InnoDB特别重要--master-data=2:以注释形式记录binlog位置,恢复时自动识别--routines/--triggers/--events:备份存储过程、触发器和事件--hex-blob:二进制数据以十六进制存储,避免编码问题| gzip:即时压缩备份文件,节省60%以上空间单库备份是最常见需求:
bash复制mysqldump -uroot -p db_name > backup.sql
多库备份时使用--databases:
bash复制mysqldump -uroot -p --databases db1 db2 db3 > multi_backup.sql
全库备份慎用,特别是大集群:
bash复制mysqldump -uroot -p --all-databases > full_backup.sql
血泪教训:曾经有同事在全库备份时没加
--single-transaction,导致业务表锁死,直接引发线上事故。切记MyISAM表必须用--lock-tables!
mydumper替代mysqldump,支持多线程pigz替代gzip,多核压缩速度快3-5倍md5sum校验备份文件完整性在my.cnf中配置binlog时,这些参数直接影响备份可靠性:
ini复制[mysqld]
server-id = 1
log_bin = /data/mysql/binlog/mysql-bin
binlog_format = ROW
binlog_row_image = FULL
expire_logs_days = 7
binlog_group_commit_sync_delay = 100
binlog_group_commit_sync_no_delay_count = 10
max_binlog_size = 1G
sync_binlog = 1
关键参数说明:
binlog_format=ROW:确保精准记录行变更sync_binlog=1:每次事务都刷盘,性能有损耗但最安全max_binlog_size:控制单个文件大小,方便管理bash复制mysqldump -uroot -p --single-transaction --flush-logs --master-data=2 testdb > full.sql
bash复制#!/bin/bash
LAST_BINLOG=$(mysql -uroot -p -e "SHOW MASTER STATUS" | awk 'NR==2{print $1}')
cp /data/mysql/binlog/${LAST_BINLOG}* /backup/increment/
mysql -uroot -p -e "PURGE BINARY LOGS BEFORE NOW() - INTERVAL 3 DAY"
bash复制mysqlbinlog --base64-output=DECODE-ROWS -v mysql-bin.000123 > changes.sql
SHOW BINARY LOGS监控binlog增长情况PURGE BINARY LOGS TO 'mysql-bin.000123'手动清理旧日志FLUSH BINARY LOGS创建新文件mysqlbinlog --start-datetime按时间筛选日志bash复制mysql -uroot -p -e "DROP DATABASE IF EXISTS testdb; CREATE DATABASE testdb"
bash复制gunzip < full_backup.sql.gz | mysql -uroot -p testdb
bash复制mysqlbinlog mysql-bin.000123 mysql-bin.000124 | mysql -uroot -p testdb
精确恢复到故障前最后一秒:
bash复制mysqlbinlog --stop-datetime="2024-01-01 23:59:59" mysql-bin.000123 | mysql -uroot -p
sql复制SET FOREIGN_KEY_CHECKS=0;
SOURCE backup.sql;
SET FOREIGN_KEY_CHECKS=1;
myloader并行恢复(对应mydumper)案例1:binlog磁盘爆满
案例2:恢复后数据不一致
必须监控的关键指标:
推荐Prometheus监控配置示例:
yaml复制- name: mysql_backup
rules:
- alert: BackupFailed
expr: increase(mysql_backup_failed_total[1h]) > 0
labels:
severity: critical
完整的备份系统应包含:
示例备份脚本框架:
bash复制#!/bin/bash
# 备份日志记录
LOGFILE="/var/log/mysql_backup.log"
# 执行全量备份
do_full_backup() {
# ...备份实现...
}
# 执行增量备份
do_increment_backup() {
# ...增量实现...
}
# 主逻辑
main() {
case "$1" in
full) do_full_backup ;;
increment) do_increment_backup ;;
*) echo "Usage: $0 {full|increment}" ;;
esac
}
main "$@"
| 特性 | mysqldump(逻辑) | XtraBackup(物理) |
|---|---|---|
| 备份速度 | 慢 | 快 |
| 恢复速度 | 慢 | 快 |
| 锁表情况 | 可能锁表 | 不锁表 |
| 存储空间 | 大 | 小 |
| 版本兼容性 | 好 | 有限制 |
推荐生产环境采用:
AWS RDS/Aliyun RDS等托管服务建议:
使用openssl加密敏感备份:
bash复制mysqldump -uroot -p dbname | openssl enc -aes-256-cbc -salt -out backup.sql.enc -k password
解密恢复:
bash复制openssl enc -d -aes-256-cbc -in backup.sql.enc | mysql -uroot -p dbname
最小权限原则:
sql复制CREATE USER 'backup'@'localhost' IDENTIFIED BY 'StrongP@ss!';
GRANT SELECT, SHOW VIEW, TRIGGER, LOCK TABLES, RELOAD ON *.* TO 'backup'@'localhost';
FLUSH PRIVILEGES;
bash复制mysqldump --quick --skip-add-drop-table --skip-comments --skip-disable-keys
参数作用:
--quick:逐行检索数据,减少内存使用--skip-add-drop-table:避免恢复时先删表--skip-comments:减少备份文件大小--skip-disable-keys:加速数据导入降低备份影响的方法:
--low-priority选项常用压缩工具性能测试结果(10GB数据库备份):
| 工具 | 压缩时间 | 压缩率 | 解压时间 |
|---|---|---|---|
| gzip | 15min | 75% | 8min |
| pigz | 5min | 75% | 7min |
| bzip2 | 45min | 68% | 25min |
| xz | 60min | 62% | 12min |
生产建议:pigz -6是最佳平衡点
bash复制#!/bin/bash
# 恢复测试数据库
mysql -uroot -p -e "CREATE DATABASE restore_test"
gunzip < backup.sql.gz | mysql -uroot -p restore_test
# 数据校验
CHECKSUM=$(mysql -uroot -p restore_test -e "CHECKSUM TABLE important_table" | awk 'NR==2{print $2}')
if [[ $CHECKSUM != $EXPECTED_CHECKSUM ]]; then
echo "数据校验失败!" >&2
exit 1
fi
Kubernetes环境下的备份策略:
使用Debezium等工具实现:
使用Terraform管理备份策略:
hcl复制resource "aws_db_instance" "example" {
# ...其他配置...
backup_retention_period = 7
backup_window = "02:00-03:00"
maintenance_window = "sun:03:00-sun:04:00"
}
在多年数据库运维实践中,我发现最可靠的备份策略必须满足3-2-1原则:至少3份备份,存储在2种不同介质上,其中1份在异地。同时要记住,没有经过恢复验证的备份,本质上就是没有备份。建议每个季度至少做一次完整的恢复演练,这样才能在真正的灾难来临时从容应对。