数据只存一份,等于没备份。
备份只存本地,机房着火了一样全没。
这篇聊聊异地备份的几种方案和实操经验。
为什么要异地备份
本地备份能防:
- 误删数据
- 程序bug
- 硬盘损坏
本地备份防不了:
- 机房故障(断电、火灾、水灾)
- 整机被黑
- 勒索病毒
3-2-1备份原则:
- 3份数据(1份原始 + 2份备份)
- 2种介质(比如硬盘 + 云存储)
- 1份异地(物理隔离的另一个位置)
方案一:定时备份 + 云存储
最简单的方案:mysqldump导出,传到云存储。
备份脚本
#!/bin/bash# backup_mysql.sh# 配置MYSQL_USER="backup"MYSQL_PASS="your_password"BACKUP_DIR="/data/backup/mysql"DATE=$(date+%Y%m%d_%H%M%S)KEEP_DAYS=7# 创建备份目录mkdir-p$BACKUP_DIR# 备份所有数据库mysqldump -u$MYSQL_USER-p$MYSQL_PASS\--all-databases\--single-transaction\--routines\--triggers\--events\|gzip>$BACKUP_DIR/all_db_$DATE.sql.gz# 删除旧备份find$BACKUP_DIR-name"*.sql.gz"-mtime +$KEEP_DAYS-delete# 上传到云存储(以阿里云OSS为例)ossutilcp$BACKUP_DIR/all_db_$DATE.sql.gz oss://your-bucket/mysql-backup/echo"Backup completed: all_db_$DATE.sql.gz"定时执行
# crontab -e# 每天凌晨3点执行03* * * /path/to/backup_mysql.sh>>/var/log/mysql_backup.log2>&1优缺点
优点:
- 简单易懂
- 成本低(云存储很便宜)
- 恢复简单(下载回来,mysql导入)
缺点:
- 备份期间有锁(大表会影响业务)
- 只能恢复到备份时间点
- 大数据量备份慢
方案二:binlog实时同步
比定时备份更进一步:实时同步binlog到异地。
原理
主库 → binlog → 同步到备份服务器 → 可以恢复到任意时间点配置主库
# my.cnf [mysqld] server-id = 1 log-bin = mysql-bin binlog_format = ROW expire_logs_days = 7同步binlog
#!/bin/bash# sync_binlog.shMYSQL_HOST="主库IP"MYSQL_USER="repl"MYSQL_PASS="your_password"BACKUP_DIR="/data/backup/binlog"# 使用mysqlbinlog远程获取binlogmysqlbinlog --read-from-remote-server\--host=$MYSQL_HOST\--user=$MYSQL_USER\--password=$MYSQL_PASS\--raw\--stop-never\--result-file=$BACKUP_DIR/\mysql-bin.000001恢复到指定时间点
# 先恢复全量备份mysql -u root -p<full_backup.sql# 再应用binlog到指定时间mysqlbinlog --stop-datetime="2024-01-15 10:30:00"\binlog.000001 binlog.000002|mysql -u root -p方案三:主从复制到异地
更专业的方案:在异地建立从库。
架构
本地机房 异地机房 ┌─────────┐ ┌─────────┐ │ 主库 │ ──复制──→ │ 从库 │ └─────────┘ └─────────┘ (只读备份)配置
主库配置:
# my.cnf [mysqld] server-id = 1 log-bin = mysql-bin binlog_format = ROW创建复制用户:
CREATEUSER'repl'@'%'IDENTIFIEDBY'password';GRANTREPLICATIONSLAVEON*.*TO'repl'@'%';FLUSHPRIVILEGES;从库配置:
# my.cnf [mysqld] server-id = 2 relay-log = relay-bin read-only = 1配置复制:
CHANGE MASTERTOMASTER_HOST='主库IP',MASTER_USER='repl',MASTER_PASSWORD='password',MASTER_LOG_FILE='mysql-bin.000001',MASTER_LOG_POS=154;STARTSLAVE;网络问题
异地复制最大的挑战是网络:
- 公网带宽贵
- 延迟高
- 不稳定
解决方案一:专线
企业级方案,贵但稳定。
解决方案二:压缩传输
# my.cnf [mysqld] slave_compressed_protocol = 1解决方案三:组网方案
如果没有专线预算,可以用虚拟组网把两地服务器打通。
我自己用星空组网把公司服务器和家里的备份NAS连起来,配置好之后MySQL从库复制就像在同一个内网一样,不用担心公网IP暴露的安全问题。
公司服务器(10.26.0.1) ←→ 星空组网 ←→ 家里NAS(10.26.0.2) 主库 从库从库配置直接用内网IP:
CHANGE MASTERTOMASTER_HOST='10.26.0.1',-- 组网的内网IPMASTER_USER='repl',...方案四:云数据库跨地域备份
如果用的是云数据库(RDS),直接用云厂商的跨地域备份功能最省心。
阿里云RDS
控制台 → 备份恢复 → 跨地域备份 → 开启 选择目标地域(比如:上海→杭州)AWS RDS
RDS控制台 → 自动备份 → 启用跨区域复制 选择目标区域优点:
- 省心,云厂商帮你搞定
- 稳定可靠
- 恢复方便
缺点:
- 要花钱
- 被云厂商绑定
备份验证
备份了不验证 = 没备份。
定期恢复测试
#!/bin/bash# test_restore.sh# 下载最新备份ossutilcposs://your-bucket/mysql-backup/latest.sql.gz /tmp/# 解压gunzip /tmp/latest.sql.gz# 恢复到测试库mysql -h test-db-host -u root -p test_restore</tmp/latest.sql# 验证数据mysql -h test-db-host -u root -p -e"SELECT COUNT(*) FROM test_restore.users;"# 清理mysql -h test-db-host -u root -p -e"DROP DATABASE test_restore;"建议每月至少做一次恢复测试。
备份完整性检查
# 检查备份文件是否能正常解压gunzip -t backup.sql.gz# 检查SQL文件是否完整(看结尾有没有正常的注释)tail-5 backup.sql# 正常应该有类似这样的结尾:# -- Dump completed on 2024-01-15 03:00:01我的备份策略
分享一下我自己的做法:
全量备份:每天凌晨3点,mysqldump + gzip ↓ 上传云存储:阿里云OSS,保留30天 ↓ 异地从库:家里NAS跑一个MySQL从库,通过星空组网连接 ↓ binlog备份:实时同步到NAS这样:
- 误删数据 → 从OSS下载最近的全量备份 + binlog恢复
- 本地机器挂了 → 切到异地从库
- 云厂商跑路 → 还有家里的备份
成本不高,就一个OSS + 家里的NAS,但心里踏实。
总结
| 方案 | 复杂度 | 成本 | RPO | 适用场景 |
|---|---|---|---|---|
| 定时备份+云存储 | 低 | 低 | 小时级 | 小项目、个人 |
| binlog同步 | 中 | 低 | 分钟级 | 需要精确恢复 |
| 异地从库 | 高 | 中 | 秒级 | 高可用要求 |
| 云数据库跨地域 | 低 | 高 | 分钟级 | 不差钱、求省心 |
选哪个看你的:
- 数据重要程度:越重要,方案越要完善
- 恢复时间要求:能接受停多久
- 预算:钱多就上云,钱少就自己搞
但不管用哪个方案,一定要定期验证。备份了没验证过的,关键时刻可能恢复不了。
有问题评论区聊。