ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

定时全量备份方案实战:基于mysqldump的脚本设计与恢复演练

定时全量备份方案实战:基于mysqldump的脚本设计与恢复演练 1. 备份方案整体设计与任务拆解接上一篇聊完逻辑备份与物理备份的选型差异之后这一篇直接进入正题怎么把全量备份真正跑起来而且是定时跑。很多团队其实不缺备份命令缺的是一套不会在半夜挂掉、挂了能发现、发现后能恢复的定时全量备份方案。我这次分享的是自己常用的一套mysqldump全量备份的落地做法从脚本编写、定调度、压缩存储到恢复演练一条链都过一遍适合中小规模业务库和早期搭建备份体系的团队直接抄作业。1.1 定时全量备份在备份体系里的定位定时的含义是固定周期、固定时间点执行备份任务比如每天凌晨2点跑一次全量备份。全量的含义是每次备份都把整个实例或指定库的所有数据完整导出一份。定时和全量这两个词合在一起意味着方案的关键在于“确定性”到了时间就执行、执行完能确认成功、失败有报警、产物可恢复。相比临时手工备份定时全量解决的核心痛点是人的不可靠性。让运维同学每天记得手动执行备份短期没问题长期必然翻车。一旦漏备且恰好当天数据出问题那种场景没人想经历。全量备份在整体备份体系中的位置也很明确它是所有恢复动作的底稿和基石。增量备份、binlog重放全都依赖最近一次全量备份作为还原起点。换句话说全量备份的质量直接决定了整个数据恢复链路的上限。全量备份本身不解决“恢复到任意时间点”的问题但它把“至少恢复到昨天凌晨”这个底线锁死了。1.2 方案选型前的三个硬性约束在写脚本之前先把约束条件列清楚因为方案里的很多细节选择都是由这些约束倒推出来的。第一数据量级。单实例数据量在50GB以内使用mysqldump逻辑备份完全够用恢复也比较灵活。数据量更大时逻辑备份的导入导出时间会变得很难接受这种情况下通常优先考虑物理备份工具。本方案按中小数据量设计如果你的库已经上百GB配套的备份工具和恢复策略需要另行调整。第二业务允许的锁表窗口。mysqldump默认做一致性快照在InnoDB引擎下使用--single-transaction参数可以在不锁表的情况下利用MVCC机制拿到一致性的数据视图。但如果有MyISAM表一致性备份依然需要对相关表加读锁锁表期间的写入会被阻塞。对于在线业务来说需要提前确认实例里是否有MyISAM表以及备份窗口是否在业务低峰期。第三存储空间和保留周期。全量备份每天一份单份压缩后假如是5GB保留30天就是150GB。磁盘规划要和保留策略一起设计好否则备份任务会先于数据库把磁盘写满。常见做法是备份文件与数据文件分盘存放避免备份写入挤占数据库所在磁盘的IO和空间。这三条约束会在后续脚本的参数选择和清理策略中反复体现。方案不是越高级越好是在自己的场景里能够稳定运转才叫好。2. 核心工具与脚本实现细节2.1 为什么还是选mysqldump明确一下这套定时全量备份用的工具是mysqldump。虽然现在有不少更现代化的备份工具物理备份工具在速度上也明显占优但mysqldump依然是我在中小数据量场景下的首选原因有三点。第一可用性最高。mysqldump随MySQL安装包一起分发所有环境里默认都有不需要额外安装客户端或依赖特定版本的内核模块。这在多套环境、跨版本实例的备份场景里省了大量适配工作。第二产物可读性强。mysqldump生成的是SQL文本文件可以直接用文本编辑器查看内容可以按库按表拆分可以grep关键词快速确认某些数据是否存在。它的备份文件本质上是一份完整的SQL恢复脚本这给手工救援和局部恢复留下了非常大的操作空间。第三恢复粒度灵活。使用mysqldump备份恢复时可以全量导入也可以只导入某些表甚至可以把备份文件中的部分INSERT语句单独提取出来执行。物理备份文件在这方面的灵活性就差很多。当然mysqldump的劣势也很明显备份和恢复的速度都受单线程限制全量备份大库时耗时较长。所以我的判断标准是单实例数据量在50GB以内mysqldump是性价比最高的选择超过这个量级就要考虑物理备份工具或者专门的备份组件了。2.2 备份脚本的完整实现直接把脚本抛出来然后逐段拆解。整个脚本的功能是连接MySQL实例使用mysqldump导出全部业务库的数据压缩后按日期命名存放同时附带一份备份日志。#!/bin/bash # MySQL定时全量备份脚本 # 适用环境MySQL 5.7 / 8.0CentOS 7 / Ubuntu 20.04 set -o pipefail # ---------- 可配置参数 ---------- BACKUP_BASE/data/mysql_backup BACKUP_DIR${BACKUP_BASE}/$(date %Y%m%d) MYSQL_HOST127.0.0.1 MYSQL_PORT3306 MYSQL_USERbackup_user MYSQL_PASSWORDBackupPassw0rd MYSQL_SOCKET/var/run/mysqld/mysqld.sock LOG_FILE${BACKUP_BASE}/backup_$(date %Y%m%d).log REMOTE_KEEP_DAYS30 # ---------- 可配置参数 ---------- mkdir -p ${BACKUP_DIR} { echo Backup Start: $(date %Y-%m-%d %H:%M:%S) mysqldump \ --single-transaction \ --quick \ --routines \ --triggers \ --events \ --set-gtid-purgedOFF \ --host${MYSQL_HOST} \ --port${MYSQL_PORT} \ --user${MYSQL_USER} \ --password${MYSQL_PASSWORD} \ --all-databases \ --socket${MYSQL_SOCKET} \ | gzip ${BACKUP_DIR}/full_backup_$(date %Y%m%d_%H%M%S).sql.gz echo mysqldump exit code: ${PIPESTATUS[0]} echo Backup End: $(date %Y-%m-%d %H:%M:%S) } ${LOG_FILE} 21 # 删除过期备份 find ${BACKUP_BASE} -maxdepth 1 -type d -name 20* -mtime ${REMOTE_KEEP_DAYS} -exec rm -rf {} \;这里有几个参数需要仔细说明每一个都是我实际踩过坑之后反复确认过的。--single-transaction参数是InnoDB表做一致性备份的核心。它通过开启一个RR隔离级别的事务让导出过程基于MVCC快照读取数据期间其他事务的写入不会影响备份内容备份也不会阻塞其他事务的提交。这里有个非常关键的前提只有使用InnoDB引擎的表才能真正享受到这个特性。如果实例中存在MyISAM表mysqldump会自动对这些表加读锁把写操作挡在外面。--routines --triggers --events三个参数负责导出存储过程、触发器、定时事件。很多备份漏掉这些对象恢复之后才发现应用层的存储过程全部丢失这种问题排查起来非常痛苦。这三个参数在默认情况下不会被导出必须显式指定。--set-gtid-purgedOFF是MySQL 5.6及以上版本在开启GTID模式下必须处理的参数。默认情况下mysqldump会生成SET GLOBAL.GTID_PURGED语句导入到目标库时要求目标库的GTID集合为空否则会直接报错。如果你在同一个实例上做恢复或者目标库已经处理过其他GTID事务默认值会导致导入失败。统一加上这个参数让备份文件不再包含GTID信息恢复时更省心。--quick参数让mysqldump逐行读取表数据而不是一次性缓存到内存对大表备份能显著降低内存占用。比如一个10GB的表不加这个参数mysqldump进程的内存占用可能冲到几个GB加上之后基本稳定在几百MB。在低配服务器上这个参数能直接救命的级别。另外注意到脚本里同时指定了--host和--socket。两者不冲突mysqldump会优先使用socket连接本地实例这样能绕过TCP/IP层的开销和认证差异速度更快也更稳定。如果你打算备份远程实例去掉socket参数即可但生产环境我强烈不建议远程跑全量备份网络抖动会让备份任务可靠性大打折扣。2.3 备份账号的最小权限配置mysqldump执行导出任务所需的权限比很多人想象的要小得多。按照最小权限原则专门创建一个备份账号是正确做法不要直接使用root账号跑定时任务。需要的权限包括这些CREATE USER backup_user127.0.0.1 IDENTIFIED BY BackupPassw0rd; GRANT SELECT, SHOW VIEW, EVENT, TRIGGER, LOCK TABLES ON *.* TO backup_user127.0.0.1; GRANT PROCESS ON *.* TO backup_user127.0.0.1; GRANT RELOAD ON *.* TO backup_user127.0.0.1; FLUSH PRIVILEGES;逐个权限拆解一下为什么是这些SELECT是导出表数据的必要权限SHOW VIEW对应视图导出EVENT对应定时器导出TRIGGER对应触发器导出。LOCK TABLES和RELOAD配合使用RELOAD权限用来执行FLUSH TABLES WITH READ LOCK当你需要确保所有表处于一致状态时这个操作会用到。虽然InnoDB表在--single-transaction下不依赖全局读锁但mysqldump在备份开始时依然会短暂获取全局读锁来获取一致的binlog位置信息。PROCESS权限用于查看线程信息mysqldump需要它来获取当前执行状态。有两点需要特别注意备份账号的密码不要写在脚本明文里可以使用~/.my.cnf配置文件代替将文件权限设置为600不要把ALL PRIVILEGES直接授权给备份账号这违背了最小权限原则一旦备份服务器被入侵数据库也可能跟着沦陷。2.4 为什么不建议直接压缩到单文件回头再看脚本mysqldump ... | gzip full_backup.sql.gz。这种做法的优点是一次性到位备份文件直接压缩节省磁盘空间。但实际使用中我建议在中间加一个步骤先导出为.sql文件再执行压缩。直接压缩的问题在于恢复时会多一步解压操作而且一旦管道中途断开你得到的可能是一个不完整的压缩文件可能连gunzip -t校验都过不了。先导出文本文件再压缩虽然多占用一段临时磁盘空间但每个步骤的产物是独立的排错时能定位到具体环节。空间紧张的环境可以保留管道的写法但要在备份结束后立即对压缩文件做完整性校验gzip -t full_backup.sql.gz确认压缩文件没有损坏。这是一个非常小的动作却能挡住一大批备份文件不可用的坑。3. 定时调度与备份链路落地3.1 cron任务配置与调度时间选择脚本准备好之后把它放到一个固定的目录比如/usr/local/bin/mysql_full_backup.sh然后赋予执行权限chmod x /usr/local/bin/mysql_full_backup.sh定时调度使用cron编辑crontabcrontab -e加入这样一行0 2 * * * /usr/local/bin/mysql_full_backup.sh表示每天凌晨2点整执行一次全量备份。调度时间的选择有几个讲究。第一避开业务高峰。对大多数业务来说凌晨2点到6点是最低峰时段备份任务对数据库和磁盘IO的影响最小。如果业务有夜间批量任务需要先梳理清楚批量任务的执行窗口宁可把备份时间往后挪也不要和批量任务抢IO。第二注意时区和夏令时问题。服务器时区如果设置了非UTCcron会按照本地时间触发这没问题。但有些云主机默认使用UTC时间如果你期望的是北京时间凌晨2点而服务器用的是UTC实际触发时间是北京时间上午10点这个偏差很容易被忽略。第三全量备份耗时估算。如果单次备份需要40分钟那么2点开始执行大约2点40分结束。要确保这个结束时间不会撞上业务早高峰初始化或定时任务启动。如果备份耗时过长考虑是不该拆分备份粒度比如按库备份而不是全实例备份。3.2 使用cron还是systemd timer绝大多数Linux发行版上cron已经足够用。但我更推荐在新环境上使用systemd timer来替代传统的cron特别是那些已经用systemd托管服务的机器。systemd timer的优势在于依赖管理明确可以设置为在指定时间点触发任务日志统一沉淀在journal里排错时直接journalctl -u mysql-backup.service查看不需要再翻脚本自己的日志文件可以设置Persistenttrue如果服务器在计划执行时段正好关机下次开机后会自动补执行漏掉的备份任务。这个特性对笔记本电脑和会定期重启的机器非常实用。对应的service和timer文件可以这样写# /etc/systemd/system/mysql-backup.service [Unit] DescriptionMySQL Full Backup [Service] Typeoneshot ExecStart/usr/local/bin/mysql_full_backup.sh# /etc/systemd/system/mysql-backup.timer [Unit] DescriptionRun MySQL Full Backup Daily [Timer] OnCalendar*-*-* 02:00:00 Persistenttrue [Install] WantedBytimers.target然后执行systemctl daemon-reload systemctl enable mysql-backup.timer systemctl start mysql-backup.timer如果团队里已有的机器都已经跑着cron强行迁移到systemd timer反而会增加维护成本。工具不是越新越好统一就好。只要调度方案能保证任务按时执行、有日志可查、失败有告警cron和timer都是合格的方案。3.3 备份脚本的日志策略与失败告警脚本里所有输出都被重定向到了日志文件backup_$(date %Y%m%d).log。只记录到文件是不够的还必须具备失败发现能力。最简单的做法在cron任务输出中配置MAILTOMAILTOopsexample.com 0 2 * * * /usr/local/bin/mysql_full_backup.sh这样脚本的任何标准输出和错误输出都会通过邮件发送给指定邮箱脚本执行成功时输出为空或只有少量信息失败时输出的错误内容会被邮件推送。这个机制简单有效但依赖本机邮件服务配置正确。更可靠的方案是接入企业微信、钉钉或飞书机器人的Webhook通知。在脚本末尾增加一个判断检查备份产物的文件大小和最近一次mysqldump的退出码如果异常就调用Webhook发送告警消息。我实际使用的版本会在备份成功后额外把文件大小和备份耗时写进结果消息。注意告警本身要小心设计避免“狼来了”效应。如果备份任务偶尔失败但没有人及时处理告警就会慢慢被忽略。建议为告警设置升级机制比如备份失败后15分钟内未确认恢复则通过电话或短信通知值班人。4. 备份文件的保留策略与清理机制4.1 保留周期的设定逻辑备份保留多少天不是拍脑袋决定的而是由三个因素交汇出来的。第一个是业务对数据恢复窗口的需求。如果业务规定“数据丢失最多允许回退到昨天”那么至少保留最近两天的全量备份昨日的和今日的再往前可以按天清理。如果业务要求“可以恢复到7天前”那么至少保留7天的日备。第二个是恢复时的数据精度需求。全量备份只能恢复到备份时刻的状态如果想要恢复到更细的时间点需要配合binlog做增量恢复。也就是说全量备份保留周期决定了“无条件恢复”的最远边界binlog保留周期决定了在这个边界之后可以精确定位到什么时刻。第三个是存储成本约束。假设单份备份压缩后是5GB保留30天就是150GB保留90天就是450GB。磁盘成本不高但也不应该无意义放大。我的默认建议是全量备份保留30天binlog保留至少3天。如果你有合规审计要求在这个基础上只加不减。4.2 清理脚本与避免误删的细节脚本中使用了这条清理命令find ${BACKUP_BASE} -maxdepth 1 -type d -name 20* -mtime ${REMOTE_KEEP_DAYS} -exec rm -rf {} \;这个命令有几个细节值得抠一抠。-maxdepth 1限制了find只在备份根目录的第一层查找子目录不会递归扫描深层目录防止误删嵌套目录。-name 20*限定只匹配以20开头的目录名避免了匹配到其他非备份目录。-mtime ${REMOTE_KEEP_DAYS}表示目录的最后修改时间超过30天才会被删除。但这里有个潜在问题-mtime是以天为单位计算基于文件的修改时间。如果备份目录每天都更新那昨天的目录mtime就是昨天不会被误删。但如果某一天备份失败导致旧目录的mtime停留在更早的时间清理逻辑依然按时间判断可能会提前删除还没到保留期的备份。更稳妥的做法是在清理前先检查当天的备份是否成功生成只有备份成功后才执行清理避免“今天的备份还没生成昨天的备份先被清了”的尴尬。改进后的逻辑是today_backup${BACKUP_BASE}/$(date %Y%m%d) if [ -d ${today_backup} ] [ -n $(ls -A ${today_backup}) ]; then find ${BACKUP_BASE} -maxdepth 1 -type d -name 20* -mtime ${REMOTE_KEEP_DAYS} -exec rm -rf {} \; else echo Today backup is missing, skip cleanup. ${LOG_FILE} 21 fi这一步虽然简单但解决了清理任务和备份任务互相纠缠的问题。备份失败时宁可多保留一些过期备份也不要冒风险删掉可能还有用的数据。4.3 异地备份与备份文件的二次保护严格来说定时全量备份方案的终点不应该停在“本机磁盘上存了一份压缩文件”。本机的备份和数据库在同一台机器上如果这台机器发生硬件故障、磁盘损坏或勒索病毒攻击备份文件很可能和数据文件一起被毁。所有备份策略的最终目标都是在服务器本身不可用的情况下依然可以拿到一份可恢复的数据。所以备份文件至少要同步到另一台机器或对象存储。成本最低的做法是在备份完成且校验通过后用rsync增量同步到局域网内的备份服务器rsync -avz --remove-source-files ${BACKUP_DIR}/ backup-server:/data/backups/$(date %Y%m%d)/--remove-source-files参数在文件成功传输后删除本地的源文件可以节省本地磁盘空间。但使用这个参数时要小心如果rsync传输不完整或者备份服务器拒绝写入源文件可能被提前删除。更稳妥的用法是先不删除本地文件而是保留到本地磁盘清理周期由本地清理策略统一处理。另外一个低成本思路是挂载对象存储备份完成后直接把压缩文件推上去。以对象存储为目标时通常按文件生命周期规则来管理保留周期不需要自己写清理脚本。提示无论同步到哪里都别忘了加密。数据库备份文件里是完整的数据一旦泄露就是整体泄露。在管道阶段用gpg或openssl对备份流加密或者依赖存储端加密这个环节不要省。5. 备份完整性校验与恢复演练5.1 校验备份文件的完整性定时任务跑了一段时间每个文件看起来都正常生成但有没有想过一个问题这些备份文件真的能恢复数据吗备份文件存在和备份文件可用是两回事。很多团队直到灾难发生时才第一次尝试恢复备份结果发现备份文件损坏、不完整或者中间有一段字符集问题导致导入失败那时候再挽救就异常被动了。所以备份脚本中必须内置完整性校验环节至少包含三件事。第一检查产物文件是否存在并且大小不为0backup_file$(ls -t ${BACKUP_DIR}/*.sql.gz | head -n1) if [ ! -s ${backup_file} ]; then echo ERROR: backup file is empty or missing. exit 1 fi第二检查gzip压缩文件的完整性gzip -t ${backup_file} if [ $? -ne 0 ]; then echo ERROR: gzip integrity check failed. exit 1 figzip -t会逐块验证压缩文件的CRC校验能发现大部分压缩过程或传输过程中的损坏。第三检查SQL文件内容的有效性。完全恢复需要时间但可以抽验关键内容比如备份文件中是否包含CREATE TABLE语句、INSERT INTO语句以及结束时是否有Dump completed的标记。mysqldump正常完成的备份文件末尾会有一行注释标记确认它的存在基本可以断定备份过程完整结束tail -n 5 ${backup_file} | grep -q Dump completed echo Backup seems complete.注意由于我们压缩成了.gz文件检查内容时需要先解压到标准输出再grep。如果你的备份脚本是先导出后压缩检查完原始.sql文件的尾部再压缩更省事。这也是我前面建议“先导出再压缩”的原因之一。5.2 定期恢复演练怎么做完整性校验只能证明文件没有物理损坏不能证明数据可以被正常导入到MySQL实例中。恢复演练是测试备份可用性的唯一金标准而且是需要周期性重复做的工作不是只在系统上线时做一次就结束。恢复演练我推荐使用一个独立的测试实例复用备份脚本生成的文件执行完整的恢复流程# 创建一个测试库实例 mysql -u root -p /dev/null # 解压备份文件 gunzip full_backup_20250401_020001.sql.gz full_backup.sql # 导入备份 mysql -u root -p full_backup.sql导入结束后随机抽取几张核心业务表做数据核对比如统计行数、抽查关键字段、对比最近几条订单记录。如果核心表和源库的数据一致这次恢复演练就算通过。恢复演练的频率取决于备份的重要程度。核心业务库建议每月至少做一次完整恢复演练次要库可以每季度一次。每次演练的结果要记录在案包括恢复耗时、导入遇到的问题、校验结果这些记录在真实的故障恢复时能提供非常可靠的预期参考让你知道恢复一个1GB的库大约需要多久什么量级的库需要多长时间心里有数。5.3 恢复时常见的坑和解决口诀恢复过程中最常遇到的问题主要有几类提前列在这里供参考。第一类GTID冲突。备份文件里包含了原实例的GTID信息导入到已经有GTID执行记录的目标实例时报错ERROR 3546。解决方式是目标库执行RESET MASTER或者在备份时使用--set-gtid-purgedOFF这也是脚本里加这个参数的原因。第二类存储过程或函数创建失败。可能是log_bin_trust_function_creators参数设置为OFF导致没有SUPER权限的用户无法创建函数。排查报错信息是ERROR 1418时在目标实例执行SET GLOBAL log_bin_trust_function_creators 1;即可。第三类字符集问题。备份文件在导出时使用的是源实例的字符集导入到目标实例后中文乱码。备份时显式指定--default-character-setutf8mb4导入时也保持一致的字符集参数可以规避大部分乱码问题。第四类max_allowed_packet太小。备份文件中的INSERT语句如果包含大字段如BLOB、TEXT导入时会触发ERROR 1153或ERROR 2006。临时调大目标实例的max_allowed_packet到256M或512M后再导入。这些坑单独看不复杂但在深夜恢复的场景下每一个都能让恢复时间成倍增加。所以备份脚本里就把这些参数调整到位、建好文档比临场解决问题靠谱得多。6. 监控告警与备份运行状态的可观测性6.1 备份文件清单与大小趋势跟踪定时任务长期运行后最容易出现的隐患就是备份产物一直在生成但体积异常变小却没人发现。比如某天数据库实例发生大量数据删除表的数据量骤降当天备份的压缩包会比昨天小很多。如果没有人注意到这个体积变化可能等到数据真的需要恢复时才发现备份已经不完整。所以在备份目录下维护一个清单文件是很有价值的每次备份完成后追加一行记录{ echo $(date %Y-%m-%d %H:%M:%S) ${backup_file} $(du -h ${backup_file} | cut -f1) } ${BACKUP_BASE}/backup_manifest.txt这个清单文件可以直观地看到每一天的备份大小。平时瞄一眼如果发现某天的文件大小突然缩小到前几天的十分之一这就是一个强烈的信号要么数据本身被大量删除要么备份过程中跳过了某些表。配合上一节讲的抽样校验能更早发现问题。6.2 监控指标设计与告警阈值除了脚本层面的文件校验运维监控层面也应该覆盖备份任务的关键指标。需要关注的指标至少包括备份任务是否按时启动可通过检查备份文件的mtime来间接判断备份耗时是否在合理范围内备份产物大小是否正常备份磁盘剩余空间是否充足。告警阈值的设置不要拍脑袋。备份耗时和产物大小需要先观察两周的正常基线再在基线上下浮动20%到30%作为告警阈值。比如正常备份耗时40分钟那么单次备份超过60分钟就需要关注正常备份产物是5GB单次产物小于3GB或大于7GB都需要检查原因。磁盘空间的告警建议设置两个层级空间使用率达到80%时提醒达到90%时触发紧急告警。备份任务最怕磁盘写满写满时备份文件写入一半中断既浪费了带宽又产生了脏数据还可能影响数据库自身的binlog写入。6.3 备份审计谁在什么时间备份了什么这一点很多人忽略。多套环境、多人操作的场景下需要给备份任务建立审计日志。每次备份的发起时间、发起用户、备份范围、产物文件名、校验结果、清理了哪些过期备份这些信息全部记录在案。审计日志的价值体现在两个场景故障排查时能快速定位某个时间点是否存在备份覆盖合规审查时能向审计方证明数据备份体系是真实运转的而不是只写了文档没有执行。做法也简单前面的脚本日志已经包含了大部分信息只需要在脚本末尾额外追加一行审计记录包含备份耗时和结果状态。把这些日志集中收集到日志平台或单独保存就形成了完整的审计链路。7. 定时全量备份方案的经验复盘方案整体跑起来之后有几条从实际运行中总结出来的经验比脚本本身更值得记录。第一备份一定要有一个“生成-校验-同步-清理”的完整状态机而不是只有一个脚本。很多人的定时备份只做了“生成”这一步后续的校验、同步、清理要么没有要么散落在其他脚本里。结果是备份文件越堆越多空间告警时才想起清理或者等要恢复时才发现文件损坏。把整个链路串起来从入口到出口都跑到才算一套完整的备份方案。第二恢复演练的频率要跟上线变更的频率挂钩。每次数据库大版本升级、磁盘迁移、字符集调整这类变更之后都应该安排一次恢复演练验证备份体系在新的环境下依然可用。环境变化时备份脚本很容易出现隐性失效比如升级后socket路径变了、数据库账号权限变了、mysqldump版本行为变化了这些都是演练能提前暴露的问题。第三千万不要让备份任务依赖某一位同事的个人电脑或某个临时环境。备份链路里的所有组件都应该部署在标准化、有冗余的机器上并且配置了自动重启和监控。我在生产环境中遇到过备份脚本只存在于某台测试机上测试机被回收后整个备份计划直接停了一周没人发现。备份基础设施和数据库本身一样需要有正式的运维保障。第四全量备份和binlog是配合使用的。如果你已经开启了binlog那么全量备份的保留周期不需要太长30天足够覆盖大多数恢复场景。更精细的时间点恢复依赖binlog的持续保留而不是囤积更多的全量备份。相反如果你还没有开启binlog那这个全量备份几乎是唯一的救命稻草建议把保留周期适当延长并且至少追加一份异地备份。第五给自己的备份方案留一条后路。全量备份方案再完善也建议每季度把最新一份备份文件在完全不同的环境上验证一次恢复流程。比如线上的备份是MySQL 8.0就准备一个原生MySQL 8.0的全新实例做恢复测试而不是一直在有各种参数的旧环境上恢复。备份文件只有在“干净环境”里也能恢复才能说明它是真正可靠的。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进