ARTICLE · INTELLIGENCE

战地情报 · 详情页

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

3-2-1备份架构详解:从勒索病毒防护到异地容灾的落地实践

3-2-1备份架构详解:从勒索病毒防护到异地容灾的落地实践 1. 为什么运维人躲不开备份这道坎先聊聊删库跑路和勒索病毒干运维这行谁没在凌晨三点被电话叫醒过。但真正让人后背发凉的电话不是服务器宕机不是机房断电而是那一声“数据库没了。”这些年“删库跑路”从段子变成了行业梗可梗背后都是真金白银的教训。有人手滑在生产库上执行了不带 WHERE 的 DELETE有人离职交接时把唯一一份NAS里的备份一起格式化还有人辛苦搭建的备份目录被勒索病毒加密得干干净净——连恢复的念想都断了。勒索病毒这东西最狠的地方在于它不删你的数据它先渗透进内网潜伏几个月把你所有的备份副本摸清楚然后在一个深夜同时加密生产环境和备份存储。等你发现时连回滚的余地都没有。所以我不止一次跟团队说备份不是买块硬盘拷一拷备份是运维体系里最后一道防线是你在“删库跑路”和勒索病毒面前唯一拿得出手的底牌。而这道防线的核心骨架就是今天要展开聊的3-2-1 备份架构。这套架构的目标很朴素让数据同时具备“可恢复”“抗损坏”“防灾难”三种能力。它适合谁适合任何手里握着生产数据的人——不管你是管着几百台服务器的运维工程师还是自己跑着几个小项目的独立开发甚至只是帮家里整理照片的数码达人这套思路都能用得上。区别只是工具规模和预算不一样。我这几年在各种环境里落地过不同规模的备份方案从单机脚本到跨地域容灾都碰过。把其中的架构思路、工具选型、坑点教训整理成文希望对正在做备份规划或者准备重构备份体系的同行有点参考价值。2. 3-2-1备份架构拆解三份副本、两种介质、一份异地2.1 三份副本为什么一份完整备份还不够3-2-1 的第一条规则是数据至少要保留三份副本一份生产数据两份备份数据。很多人第一反应是我每天都在做备份历史版本好几个肯定超过三份了。但注意这里说的三份是“完整可用的副本”不是“三个不同的时间点”。举个例子你用 rsync 做镜像同步每天把生产目录同步到备份盘虽然历史上有七个日期的目录但本质上都是同一份数据的实时拷贝——一旦生产数据被篡改或加密第二天同步会把“坏数据”原封不动地搬到备份盘上。这种备份在勒索病毒面前等于没有备份。所以三份副本的正确理解是至少有一个副本是“离线”或“快照式”的和正在变化的生产数据不做实时同步。生产库一份实时备一份再加上一个按天或按周生成的独立快照这样即使生产数据和实时备都被污染你还有第三个干净起点可以恢复。实操中我习惯把三份副本拆成这样的角色副本A生产环境本身例如主数据库或主文件服务器副本B同机房/同可用区的实时备份用于快速恢复副本C独立于前两者的历史快照保存最近N天的版本按策略自动轮转2.2 两种介质别把所有鸡蛋放在同一个篮子里第二条规则副本要存放在两种不同介质上。这里的“介质”不是指硬盘品牌不同而是指存储原理和故障域不同。常见组合包括本地磁盘 磁带库本地磁盘 对象存储如云端的OSS/S3本地磁盘 光盘/蓝光归档不同厂商的磁盘阵列 独立NAS为什么这么较真因为同一种介质往往有同样的“死法”。两块同一批次采购的硬盘可能因为同一批固件缺陷在相近时间故障同一台NAS里的磁盘阵列可能因为RAID卡故障或电压浪涌全部挂掉。如果你把三份副本都放在同一台机器上那RAID卡烧毁、勒索病毒加密、机房进水这些事件会一次性带走你所有的底牌。我在实际项目里最常用的组合是一份放本机或同机房的独立磁盘阵列一份放远端机房或云对象存储。这样既覆盖了“硬盘坏了我要快速恢复”的场景也覆盖了“整栋楼没了我也要有数据”的场景。2.3 一份异地真正防御“灾难级”风险的关键第三条规则至少要有一份副本放在异地。很多中小团队疏忽的就是这一条。他们觉得本地有两份拷贝已经够稳了反正公司机房又不是纸糊的。但“异地”防的不是硬盘故障而是区域性灾难和场地级事故——火灾、水淹、入室盗窃甚至只是某个运维同事一时手滑误删了整个共享存储目录。这些事件发生时本地的所有副本一起完蛋这时候唯一能救你的就是放到几百公里外的那份数据。异地副本不一定非要上云。如果你的公司有多个办公地点两个楼宇之间的机房互备也可以如果是个人项目放一台异地朋友家的NAS甚至加密后的移动硬盘定期轮换都算异地。异地不代表必须是“高可用双活”先把“数据在外面有一个家”这件事做到就已经赢过了多数团队。2.4 3-2-1 的进阶版 3-2-1-1-0 是什么回事这几年行业内还流行一个扩展版本3-2-1-1-0。多出来的两个数字含义是第二个“1”额外保留一份离线、不可变Immutable的副本专门用来对抗勒索病毒和误操作“0”指备份完成后要做“零错误校验”即每次备份都验证数据完整性而不是备份任务显示“成功”就算完事不可变副本的意思是这份数据在被锁定的保留期内不仅普通用户改不了连管理员、甚至是备份系统本身都无法修改和删除。这样即使勒索病毒拿到备份系统的权限也无法把备份加密或删除。云对象存储厂商提供的 Object Lock 功能或者本地存储的 WORM一次写入多次读取特性都可以实现这个效果。我的建议是物理条件允许的话直接把 3-2-1-1-0 作为落地标准而不是只满足于 3-2-1。因为从勒索病毒防护角度讲“不可变副本离线隔离”这两招才是真正的杀手锏。3. 技术选型与落地实操从需求分析到工具链搭建3.1 先把 RPO 和 RTO 想清楚再做方案聊工具之前必须先聊两个指标否则方案做得再漂亮也没法验收。RPO恢复点目标数据最多可以丢多久。比如 RPO24小时意味着允许丢一整天的数据。RTO恢复时间目标故障发生后业务最多可以中断多久。比如 RTO2小时意味着从故障发生到恢复可用必须在2小时内完成。这两个数字决定了备份频率、备份方式、恢复流程和技术栈选型。预算再多、工具再好如果需求方说不清楚 RPO 和 RTO那备份方案注定是要返工的。我个人的经验是把需求拆成三个区间对不同区间的数据区别对待数据类别典型示例建议RPO建议RTO备份策略核心交易类订单库、用户库、支付记录5分钟以内30分钟以内数据库实时归档 每日快照 异地副本业务运营类CMS内容、配置文件1小时左右4小时以内每小时增量 每日全量 本地异地低优先级日志、临时数据24小时24小时以上每日一次全量保留短周期没有这个拆分你大概率会在“每天凌晨备份一次”的粗暴策略里翻车——要么核心数据丢了承受不起要么为日志这种不重要的数据浪费大量存储成本。3.2 工具选型从开源三件套到商业套件备份工具没有银弹只有适不适合。这里列一下我在不同规模环境里用过而且觉得靠谱的方案。开源/免费方案rsync crontab最经典的文件同步方案适合小规模文件备份。优点是简单直接缺点是做不了增量快照、没有统一的恢复界面、对数据库这种需要一致性快照的负载支持较弱。BorgBackup自带去重、压缩和加密的开源备份工具适合个人或小团队备份目录也能通过borgmatic这类封装实现策略管理。去重能力对同机多版本备份非常友好。Restic同样支持加密和去重而且支持多种后端本地目录、SFTP、S3、OpenStack Swift等命令风格比较现代。我比较喜欢它的forget保留策略语法能优雅地控制快照数量。Proxmox Backup Server (PBS)如果虚拟化平台用的是 Proxmox VEPBS 的增量备份和去重能力非常惊艳而且有 Web 界面。Bareos社区版的备份套件基于原先的 Bacula适合中大型环境支持目录/文件/数据库备份学习曲线偏陡但功能真的很全面。商业/企业方案Veeam Backup Replication社区版免费企业版付费对虚拟化环境VMware、Hyper-V、Proxmox等的支持非常完善支持应用一致性快照、瞬时恢复、不可变备份仓库等功能是我在做虚拟机备份时的首选。Commvault、NetBackup老牌企业级套件功能全面但授权成本高、部署复杂一般大公司会引入。如果你问我最通用的推荐中小团队从 Restic 云对象存储 定时任务 起步是性价比最高的路径等规模变大、需要图形化管理和合规审计时再切换商业套件这样不会一上来就背上沉重的运维成本。3.3 一个可直接入手的落地示例Restic 本地磁盘 云对象存储下面给一个我常用的“准生产”方案骨架它同时满足 3-2-1 的要求本地一份、异地云存储一份、外加历史快照保留。环境假设一台 Linux 服务器CentOS/Rocky/Ubuntu都可以需要备份/data/mysql数据目录、/opt/app/config配置目录、/var/www/html网站目录。第一步安装 restic# Ubuntu / Debian apt update apt install -y restic # CentOS / Rocky / RHEL 8 dnf install -y restic第二步初始化两个仓库一个本地仓库一个云对象存储仓库。# 创建仓库密码文件生产环境建议用密码管理器或密钥服务 echo your-strong-backup-passphrase /root/restic-pass.txt chmod 700 /root/restic-pass.txt # 初始化本地仓库 restic init --repo /backup/restic-repo --password-file /root/restic-pass.txt # 初始化云仓库以兼容S3为例实际按云厂商参数调整 export AWS_ACCESS_KEY_IDyour-access-key export AWS_SECRET_ACCESS_KEYyour-secret-key restic init --repo s3:s3.region.amazonaws.com/bucket-name/restic-repo --password-file /root/restic-pass.txt这里提一个新手容易掉的坑备份仓库的密码一旦丢失数据也基本等于没了因为 restic 的加密是客户端加密服务端拿不到明文密钥。所以密码文件一定要独立存放最好是放到公司内部的密码管理平台而不是和仓库在同一个目录下。第三步编写备份脚本/usr/local/bin/backup-job.sh#!/bin/bash set -euo pipefail # 严格模式任何一步失败都退出并触发告警 export RESTIC_PASSWORD_FILE/root/restic-pass.txt LOG_FILE/var/log/backup/backup-$(date %Y%m%d%H%M%S).log SLACK_WEBHOOK_URLhttps://hooks.slack.com/services/xxxxx # 按实际改成你的通知渠道 exec (tee -a $LOG_FILE) 21 echo 备份开始于 $(date %F %T) # 1. 使用 mysqldump 导出数据库为一致性的逻辑备份文件 /usr/bin/mysqldump --single-transaction --quick --all-databases /data/backup-staging/mysql_all.sql # 2. 备份到本地 restic 仓库同时保留最近7天的快照 restic backup /data/mysql /opt/app/config /var/www/html /data/backup-staging/mysql_all.sql \ --repo /backup/restic-repo \ --tag nightly --verbose # 3. 执行保留策略每日保留7份每周保留4份每月保留3份 restic forget --repo /backup/restic-repo \ --keep-daily 7 --keep-weekly 4 --keep-monthly 3 \ --prune # 4. 备份到云对象存储仓库异地副本策略同步为每日3份 restic backup /data/mysql /opt/app/config /var/www/html /data/backup-staging/mysql_all.sql \ --repo s3:s3.region.amazonaws.com/bucket-name/restic-repo \ --tag nightly-remote --verbose restic forget --repo s3:s3.region.amazonaws.com/bucket-name/restic-repo \ --keep-daily 3 --keep-weekly 2 --keep-monthly 1 \ --prune # 5. 验证最近一个快照 LATEST_SNAPSHOT$(restic snapshots --repo /backup/restic-repo --latest 1 --json | python3 -c import sys,json; print(json.load(sys.stdin)[0][id])) restic check --repo /backup/restic-repo --read-data-subset 5% --latest ${LATEST_SNAPSHOT} echo 备份完成于 $(date %F %T) # 6. 发送成功通知失败时因为 set -e 已经退出并走 trap这里不用额外处理 curl -s -X POST -H Content-type: application/json \ --data {text:✅ 备份任务执行成功} $SLACK_WEBHOOK_URL || true第四步加入 crontab# 每天凌晨 2:30 执行备份 30 2 * * * /usr/local/bin/backup-job.sh这套方案有几个好处restic 自带加密和去重传输到云端的是加过密的快照不用担心第三方偷看本地仓库用于快速恢复云端仓库用于灾难恢复和勒索病毒场景下的异地兜底forget策略让存储成本可控不会无限膨胀。3.4 数据库备份的两个特殊姿势逻辑备份与物理备份文件类数据用上面这种文件级备份没问题但数据库要稍微多花点心思。数据库有两类备份方式各有利弊逻辑备份如 mysqldump、pg_dump导出的是 SQL 语句或表格数据可读性强、可选择性恢复某张表但数据量大时备份和恢复都很慢占用的存储空间也比在线数据大。适合中小库、配置库、报表库。物理备份如 Percona XtraBackup、pg_basebackup直接拷贝底层数据文件备份和恢复速度快很多适合大库TB级别以上但版本兼容性要求高只能恢复到同大版本的数据库实例上。生产环境最稳的做法是“两条腿走路”每天跑一次物理备份用于快速恢复每周跑一次逻辑备份用于复杂场景下的细粒度恢复。双份叠加互相兜底。另外无论用哪种方式数据库备份前最好先做一次“一致性检查”。不少团队配置文件备份因为没加--single-transaction或--lock-all-tables备份出来的数据处于事务中间状态恢复时一堆外键冲突或半截数据。这个问题在 MySQL 的 MyISAM 引擎和 PostgreSQL 的某些备份姿势下尤其常见。4. 常见问题与排查技巧实录备份系统最常见的六个坑4.1 备份任务显示“成功”文件却是坏的这是备份系统最常见、最隐蔽的坑。备份脚本返回码为 0日志显示所有文件已同步但等真要恢复时才发现文件损坏、目录缺失、或者备份的是挂载点而不是实际数据。我排查过的一个真实案例某团队用 rsync 备份 NFS 挂载目录但由于网络抖动NFS 挂载在备份期间“假死”rsync 没报错把空目录当成了源数据同步过去把原本好的备份都覆盖了。恢复时打开备份目录里面空空如也。要避免这类问题至少要做到两点备份必须带校验。rsync 加--checksum参数做整文件校验restic 本身会验证数据完整性数据库备份后至少做一次source 导入到临时库的冒烟测试。备份结束要有“哨兵文件”。在备份完成后写入一个包含文件数量、总体积、校验和的文件日常巡检时对比这个哨兵文件如果文件量或体积异常说明备份链路可能出了问题。4.2 勒索病毒把备份盘也加密了隔离和不可变是硬道理勒索病毒不是只会感染生产服务器它扫描的是整个内网。很多备份方案的崩溃点都在这里备份盘挂载在生产机器上或者使用同一个域账号的共享目录病毒一旦拿到管理员权限会把备份目录一并加密。这个问题的解法在 3-2-1-1-0 里已经说了一部分这里再展开讲几个落地命令和思路异地副本必须和生产内网隔离。最理想的是走独立的备份网络/VLAN生产网被攻破时备份网不受影响云对象存储开启 Object Lock / 合规保留策略。在 AWS S3 上可以使用aws s3api put-object-lock-configuration或者在控制台上为一整个 bucket 开启“合规模式”的保留策略这样即使拿到备份密钥也无法在保留期内覆盖或删除对象本地备份仓库选择不可变存储或离线存储。如果用的是 Veeam可以配置 Hardened Repository加固仓库底层的 Linux 仓库禁用了 SSH 登录并支持不可变文件锁定如果自己搭最朴素的方案就是备份完成后自动将备份盘卸载umount只在需要追加备份时再挂载这里必须强调一个反直觉的现实备份密钥和备份数据不要放在一起管理。如果你把 restic 密码文件放在服务器上勒索病毒祸害服务器时连仓库密码一起拿走那加密备份也照样能被解密后再加密等于白搭。密钥必须放在独立安全的地方。4.3 备份越堆越多存储成本失控备份不像日志你不能无脑留着所有版本。有些团队为图省事把备份策略设成“永远保留”几个月后发现存储见底然后手动删除一批结果又把唯一有效的那份删掉了。正确的做法是设定分层保留策略每日备份保留最近 7 份用于最近的回滚每周备份保留最近 4 份用于近一个月内的恢复每月备份保留最近 3 份用于中长期归档每年备份可作为归档长期保留但建议放到更廉价的对象存储冷归档层restic forget命令前面的示例就是按这个思路做的。商业备份工具也基本都有类似的 retention 设置。关键是这个策略必须是自动化的、可预期的而不是出了问题再“手动瘦身”。4.4 恢复演练一直没做过真出事的时候手忙脚乱很多团队备份系统搭建完、监控告警都正常就以为万事大吉。直到某天真要恢复才发现备份软件版本升级过、数据格式不兼容恢复时需要手动编译旧版本工具或者数据库备份文件早已损坏玩了一个下午也没能恢复出可用的库。备份系统的验收标准不是“备份成功”而是“恢复成功”。所以至少每个季度要做一次全流程恢复演练随机挑一个快照在测试环境完整恢复然后跑一遍业务冒烟脚本确认数据可用。这事听起来麻烦但一次完整演练比看一百篇备份最佳实践文章都管用。我甚至建议团队把“恢复演练”列入 OKR 或 KPI让恢复这件事变成一个可量化的指标RTO 达标率、恢复成功率、演练覆盖率都比“备份完成率”更能衡量备份体系的真实健康度。4.5 配置文件漏备份比丢数据更隐蔽的生产事故这里有一个特别容易被忽略的点很多团队只盯着数据库和文件服务却忘了备份配置文件、环境变量、桶策略、定时任务、SSL证书等“软资产”。这些文件平时不起眼但一旦集群需要重建缺少它们可能花掉你几个通宵。我的习惯是把所有配置单独建一个目录做集中备份同时用版本控制来管理# 将关键配置拷贝到集中目录 mkdir -p /srv/backup-src/etc-snapshot cp -a /etc/nginx /srv/backup-src/etc-snapshot/ cp -a /etc/ssl /srv/backup-src/etc-snapshot/ cp -a /etc/systemd/system /srv/backup-src/etc-snapshot/ crondump /srv/backup-src/etc-snapshot/crontab-$(hostname).txt # 也可以考虑直接纳入 Git 管理但注意不要把密钥塞进仓库配置文件的备份频率不用像数据库那么高一天一次即可但一定要纳入备份体系别把它们排除在备份范围之外。4.6 云厂商自己的备份和3-2-1冲突吗如何整合现在很多业务直接跑在云上云厂商提供了 RDS 自动备份、云硬盘快照等能力。这些算不算 3-2-1我的看法是算一份但不能算全部。云快照和云数据库备份本质上还是在同一个云账号、同一个地域内。如果账号被盗、云厂商出现大面积故障罕见但非零概率、或者区级故障导致整个可用区不可用这些副本同样会遭殃。所以保险的做法是云上快照 副本B本地快速恢复再定期把核心数据导出到另一朵云或自建机房的独立存储 副本C异地也就是说不要因为用了云就忽略 3-2-1 里的“异地”和“多介质”。云只是一个存放数据的容器不是架构的全部。5. 把备份体系做成“活系统”监控、告警与自动化巡检5.1 没有监控的备份等于没有备份备份必须纳入监控体系不能只靠日志文件。连续三天备份失败而没人发现等灾难来临时再补救无异于裸奔。我常用的监控方式有以下几种备份时间戳监控使用 Prometheus Blackbox Exporter 或自定义脚本采集每个备份任务最近的完成时间如果超过 26 小时假设是每日备份没有更新就触发告警备份体积监控对比最近N次备份的文件数、总体积如果出现明显下降比如某个仓库的体积突然减少 50%说明可能有数据被意外清理或备份链路故障恢复演练自动触发可以在测试环境设置每周自动恢复最近一次备份到临时库利用 CI/CD 平台如GitLab CI或Jenkins跑一条恢复流水线把恢复演练做成自动化任务5.2 告警要有“分级”别让所有人对告警麻木备份告警最忌讳“一刀切”。如果每天凌晨的备份失败告警半夜把整个运维组都吵醒几周后所有人就会把告警静音真正出大问题时反而没人看到通知。我建议把告警分成两级级别触发条件通知对象处理时限警告单次备份失败、备份耗时超过基线50%值班运维次日上班前确认严重连续两次备份失败、备份仓库损坏、恢复演练失败运维组长值班运维立即处理“连续失败两次”这个规则很关键它过滤了偶发性的网络抖动、磁盘临时满等脏数据只上报真正值得行动的问题。5.3 自动化巡检脚本的一个骨架参考手头没有商业化堡垒机或监控平台时可以先用一个简单的 shell 脚本把巡检自动化#!/bin/bash # 检查本地 restic 仓库最新快照是否在今天 set -euo pipefail LATEST$(restic snapshots --repo /backup/restic-repo --latest 1 --json \ | python3 -c import sys,json; djson.load(sys.stdin)[0]; print(d.get(time,1970-01-01T00:00:00))) TODAY$(date %F) if [[ $LATEST ! $TODAY* ]]; then echo ERROR: 最近快照时间 $LATEST不在今天需要人工介入 exit 2 fi echo OK: 备份已在今天执行把这个脚本丢到 cron 里每分钟跑一次也可以配 systemd timer输出非零就由监控平台拉取状态并触发告警。如果你的监控平台支持自定义 exporter比如 node_exporter 的 textfile collector也可以把状态写入指定文件让 Prometheus 自动抓取展示趋势。5.4 备份容量的规划与成本控制备份存储的容量规划经常被忽略等到磁盘满了才临时加盘结果备份任务在凌晨 3 点失败运维在第二天早上才知道。我的经验是按照“源数据量 × 增长率 × 保留周期 × 去重率估算”来做预算。假设源数据 2TB月增 5%保留 7 天每日增量 4 周每周全量 3 月每月全量开启去重后实际存储容量大概是基础全量副本2TB每日增量7份2TB × 0.05 × 7 ≈ 0.7TB每周全量4份2TB × 4 8TB但去重后可能只有 1.5~2TB 的新增块每月全量3份去重后通常增加 1~2TB粗算下来一个 10TB 左右的备份存储池可以支撑约半年的运行后续每月扩容 3%~5% 左右就够用。当然这只是经验值具体要靠实际去重率来校准。重要的是不要把备份容量规划成“一次性买断”要有周期性复审机制每季度看一次实际消耗速度和剩余天数决定是否需要扩容或调整保留策略。6. 写在最后的运维心得备份是设计出来的不是买出来的做了这些年运维见过太多从零搭建备份体系的项目也见过太多在灾难面前无能为力的团队。如果让我总结一句最想说的话那就是备份是一个需要持续设计和验证的系统工程不是装个软件、买块硬盘就完事的。3-2-1 架构本身并不神秘它的三个数字背后对应的是三种不同维度的安全感三份副本对抗误操作和软件故障两种介质对抗硬件故障和存储环境风险一份异地对抗场地级灾难。真正决定备份体系成败的不是用了多贵的商业软件而是你有没有把 RPO/RTO 想清楚、恢复流程有没有演练过、监控告警有没有覆盖到、勒索病毒来了备份是否真正“坚不可摧”。我在实际项目中特别看重“不可变副本”和“恢复演练”这两件事。前者是面对勒索病毒时的定海神针后者是验证整个体系是否值得信任的唯一标准。如果你现在的备份方案还没具备这两点哪怕其他部分做得再完美我建议你把这两项排在下一个迭代的最高优先级。最后再分享一个小技巧备份的日志和文档别只存在运维自己的笔记里。把备份策略、恢复手册、密钥存放位置、演练记录整理成一个团队共享的 Runbook每年做一次全员 review。因为你永远不知道下一次执行灾难恢复的人是半年后刚入职的新同事还是凌晨三点被叫起来的你自己。为了那时候能多一份从容现在把备份这事做扎实一点绝对值。
RELATED READING

延伸阅读

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