个人数据的 3-2-1 备份实践
备份的价值不在“有备份”,而在“能恢复”。这篇写我用 restic 和对象存储做 3-2-1 的具体配置,以及每季度一次的恢复演练是怎么做的。
3-2-1 到底指什么
- 3 份数据:一份在用的原件,加至少两份备份。
- 2 种介质:比如本机磁盘和移动硬盘,或者本地 NAS 与对象存储。
- 1 份异地:火灾、被盗、勒索软件都可能同时影响同一房间里的设备。
对个人站点来说,我的组合是:服务器本地磁盘、家里的 NAS、异地对象存储。三者使用同一套 restic 仓库格式,恢复命令完全一致。
为什么选 restic
它是一个单文件二进制,支持本地目录、SFTP、S3 兼容存储;备份是增量且去重的,仓库本身加密。相比直接 rsync,多出来的能力主要是快照历史和加密。
sudo apt install restic
restic version
初始化仓库
密码单独存放,不要和备份数据放在同一台机器上,也不要提交到代码仓库。
export RESTIC_REPOSITORY="s3:https://s3.example.com/backup"
export RESTIC_PASSWORD_FILE="/root/.config/restic/password"
sudo install -d -m 700 /root/.config/restic
sudo sh -c 'openssl rand -base64 32 > /root/.config/restic/password'
sudo chmod 600 /root/.config/restic/password
restic init
第一次备份
把配置、站点文件和数据库导出放在一起。日志和缓存目录排除掉,否则每次快照都会变大。
restic backup /srv/notes /etc/nginx /var/www \
--exclude-caches \
--exclude '*.log' \
--exclude '/var/www/*/cache' \
--tag daily
数据库不要直接拷数据目录,先用 pg_dump 或 mysqldump 导出一份一致的快照,再让 restic 备份导出文件。
保留策略
快照太多会拖慢 check,太少又不够回溯。forget 定义保留规则,prune 真正删除不再被引用的数据块。
restic forget \
--keep-daily 7 \
--keep-weekly 4 \
--keep-monthly 6 \
--prune
这套规则大约保留半年的历史,磁盘占用主要取决于数据变化量,而不是快照数量——去重让重复内容只存一份。
校验与恢复演练
只备份不校验,等于把问题推迟到需要恢复的那天。check 会验证仓库结构,加上 --read-data-subset 可以抽样读取数据块。
restic check
restic check --read-data-subset=5%
restic snapshots --compact
每季度做一次完整恢复,恢复到临时目录即可,不要覆盖线上文件:
restic restore latest \
--target /tmp/restore \
--include /srv/notes
diff -r /srv/notes /tmp/restore/srv/notes | head
演练时记录三件事:恢复耗时、缺失的文件、以及恢复后服务能否直接启动。第三点最重要,也最容易被忽略。
把备份做成定时任务
用 systemd timer 比 cron 更容易看到日志。unit 文件里设置 OnFailure= 可以在失败时触发告警,哪怕只是发一封邮件。
# /etc/systemd/system/restic-backup.service
[Unit]
Description=Restic backup to object storage
OnFailure=notify-admin@%n.service
[Service]
Type=oneshot
Environment=RESTIC_REPOSITORY=s3:https://s3.example.com/backup
Environment=RESTIC_PASSWORD_FILE=/root/.config/restic/password
ExecStart=/usr/local/bin/restic-backup.sh
# /etc/systemd/system/restic-backup.timer
[Unit]
Description=Run restic backup daily
[Timer]
OnCalendar=*-*-* 04:15:00
Persistent=true
RandomizedDelaySec=600
[Install]
WantedBy=timers.target
最后
备份系统不需要复杂,但需要三样东西同时成立:按计划运行、失败会告警、恢复被验证过。缺任何一项,都只是心理安慰。