数据库与备份

postgres 里存了什么

Immich 的 postgres 数据库是整套系统里体积不大但价值密度最高的部分。照片文件丢了,你可以从备份盘、旧手机、云相册找回来;数据库一旦损坏,所有照片还在,但人脸分组、相册结构、修复历史、分享链接会一起消失——你得到一屋子照片和一个空白目录。

数据库里大致是这些东西:照片的元数据(拍摄时间、地点、设备型号)、人脸向量与人物分组、用户信息与账号设置、相册与分享记录。体量上,几万张照片的数据库通常在数百 MB 到 GB 级别,和照片本体相比微不足道。正因为它小,备份成本极低;也正因为它小,丢失的代价极高。

一个粗略的数字感:一万张照片对应的数据库体积大致在几十到上百 MB,两万张翻一倍也仍在可以轻松塞进网盘的量级。这决定了数据库备份可以每天做、甚至每天做几次都不心疼——和照片目录的备份频率完全不是一个概念。

数据类型 体积 丢失后果 可否从照片恢复
照片文件 大 全部没了 看备份情况
元数据索引 小 时间线混乱 可重建
人脸分组 小 人物分组归零 可重新识别
相册结构 小 整理白费 不可恢复
账号设置 小 需重新配置 不可恢复

备份的三个层次

备份不是复制一份那么简单。一个靠谱的方案要覆盖三个层次:文件级、快照级、异地级。文件级是把照片目录和数据库一起复制到另一块盘;快照级是定时对整个容器数据卷拍快照,能在出问题时整体回滚;异地级是把至少一份关键数据放到另一个物理位置。三个层次依次递进,预算有限时先保证前两个。

层次 防什么 成本 做法示例
文件级 误删、误改 一块盘 定时同步照片目录
快照级 升级翻车 存储空间 每周卷快照
异地级 灾难性事件 网盘或硬盘 数据库每日上传异地

备份方案的设计原则

设计备份方案时,有三条原则比具体工具更重要。第一是自动化:任何依赖你记得手动执行的备份,三个月后都会变成薛定谔的备份。第二是分层:照片目录和数据库的备份频率、保留策略都不一样,混在一起做肯定有一边吃亏。第三是可验证:备份完能恢复才算数,不能验证的备份和没备份只有一个错误的区别。三条原则听起来朴素,真正坚持的家用系统不多,区别就是出事的那一天。

一个常见的弯路是把云相册当成备份。云相册是备份的一种形态,但它同时是另一个厂商管理的服务——本书第一章讨论过它的风险。对自建用户而言更合理的结构是:NAS 本地是主存储,外置硬盘或另一台机器是近备份,核心数据再有一份异地。这个结构给得起,也不贵。

具体的工具组合可以很简单:系统自带的定时任务跑数据库导出,文件同步工具处理照片目录,每份脚本都把结果和上次对比,发现异常给自己发消息。工具不重要,流程能自己跑起来才重要。

备份的日常循环

原则 一句话 检验方法
自动化 不依赖记忆 关掉人肉提醒看它跑多久
分层 不同数据不同频率 每类数据单独一条定时任务
可验证 恢复成功才算数 季度演练

数据库备份的具体做法

postgres 的备份推荐用官方自带的导出工具而不是直接复制数据文件。直接复制文件在服务运行时有风险,写一半复制出来的数据文件未必能用。导出工具会保证一致性,而且导出的是文本格式的 SQL 语句,文件小、可读、跨版本兼容。

一个最低限度的方案长这样:每天凌晨自动导出数据库,保留最近七份;照片目录每周增量同步到备份盘,保留一两个月。两者都可以用系统自带的定时任务加几行脚本完成。关键不是脚本多精巧,而是它能不能在你忘记存在的时候自己跑起来。脚本第一次运行时在日志里确认一次输出,之后每个月扫一眼执行结果,这套流程就算落地了。

一个客观规律改不了:照片会一直长,备份也要一直跟着长。给备份盘留出和照片盘同量级的余量,是比脚本本身更前置的规划。

三个月最低备份方案

备份做完要验证。每个季度挑一份备份,在隔离环境里恢复一遍,能打开才算数。只备份不验证的方案,本质上是薛定谔的备份——出事前你永远不知道它能不能用。这一步请务必排进日历,别指望灵感。

恢复演练听起来隆重,做起来很轻:找一台不重要的机器或者容器,导入一份最近的备份,打开看一眼能不能正常登录、照片列表是否完整。五分钟能做完的事情,每个季度做一次,换来的底气是任何宣传都给不了你的。演练时顺手记录一下恢复耗时,出事你能立刻估算出要多久才能恢复正常。

还有一个细节容易被忘:备份的保留周期。每天都覆盖同一个备份文件,等于把鸡蛋放在昨天的篮子里——如果故障是昨天发生的,备份也跟着坏了。推荐七份轮转(保留最近七天)加每月一份留档,磁盘空间几乎不增加,却把误操作的发现窗口拉长到了一个月。轮转脚本随便找一个顺手的工具都行,核心逻辑就是备份新文件、删掉超期文件,几行搞定。

备份对象 频率 保留份数 位置
数据库 每天 七份轮转 本地与异地各一
照片目录 每周增量 一两个月 备份盘
配置文件 每次改动 最近三份 随数据库备份

备份放在哪里也是设计的一部分。本地份保证恢复速度快,异地份保证灾难下还有底。两份都在同一块盘上等于只有一份,两份都在同一个机房等于只有一份——这个朴素的道理套在家里就是:另一块盘一份、外置硬盘或网盘一份,双保险。

对多数家庭而言最现实的组合是:本地备份盘放每周的照片增量,网盘放每天的数据库导出。数据库体积小、上传快;照片体积大、上传慢,降低频率正合适。两者都在后台静默运行,你需要做的只是季度验证。

升级前的强制备份

Immich 版本迭代频繁,小版本可以随手追,大版本必须按流程来。官方文档对每个版本间的破坏性变更都有标注,升级前花五分钟读一遍发行说明,远比升级失败后哭着恢复数据库体面。

版本类型 备份要求 建议节奏
小版本 常规备份即可 随手更新
大版本 必须完整备份 延后两周追
数据库迁移版本 提前测试 等社区反馈

数据库迁移版本要单独强调一次。这类升级涉及 postgres 的结构变更,一旦失败回滚很麻烦,社区通常会在一两天内冒出大量反馈。观望两周再动手不是胆小,是效率最高的选择——别人踩过的坑,你不必再踩一遍。

升级前的四步

数据损坏的急救

万一真的遇到数据库起不来,先做一件事:不要重启整个机器,第一时间把现有数据库文件复制到安全位置。容器自动重启机制在你捣鼓的时候可能反复覆盖,第一时间冷冻现场比任何修复技巧都重要。

拿到现场副本之后,再去看日志、查社区。Immich 的数据库故障绝大多数能通过日志里的关键信息对照社区方案解决,最坏情况是重建数据库——照片还在、重新识别一遍,一天时间而已,不算灾难。重建数据库听着吓人,其实只是一次漫长的重新扫描,你的照片文件始终不动,这是自建架构给的底气。真正灾难性的操作是上来就删容器、删数据目录以为能重装解决,那才是把可救变成不可救。

一个 postgres 故障的案例值得分享。某用户大版本升级后数据库无法启动,慌乱之下直接删除容器和数据目录尝试重新部署,结果连旧的现场副本都失去了——一次本来可以恢复的事故变成了不可逆的数据丢失。正确的做法是第一时间停掉容器、把数据目录完整复制一份到安全位置,然后才动手操作。现场一旦被改动,修复的选项就只剩恢复和重建两种,而没有冷冻副本时,连恢复这条路也堵死了。

类似的还有一类故障来自存储而非数据库本身:盘位异常导致数据文件不完整、文件系统只读。启动日志里的信号是数据库报无法写入。这类故障先修存储层,别在应用层反复重启。

把这条流程写成一张卡片贴在机器边上并不夸张。出事的时刻通常是深夜或者升级到一半,人在慌乱中的第一反应恰恰是最危险的那几个操作。有一张写着顺序的卡片在眼前,比你当时在论坛里翻帖子快得多。

数据库故障的应急顺序

小结

数据库是 Immich 里体积最小、价值密度最高的部分:人脸分组、相册结构、修复历史都在这里,备份成本极低而丢失代价极高。三个层次的备份(文件、快照、异地)按预算推进;备份要定期验证;升级前按流程走完整备份。照片在硬盘上,安全感来自流程。

延伸阅读