开发 OcuPilot 时我学到的经验:macOS 会悄悄删除保存在 /tmp 目录中的 IRIS 数据库

在开发 OcuPilot(https://openexchange.intersystems.com/package/OcuPilot)——一款用于 IRIS 管理门户的人工智能副驾驶——的过程中,我为测试运行了大量短暂存在的 IRIS 容器。 这些容器将数据保存在我 Mac 上的 /tmp 目录下的文件夹中,因为那里是临时文件的存放位置。三天后,其中一个容器开始出现莫名其妙的故障:一个仍显示为已挂载的临时数据库背后实际上没有对应的文件,且向其写入数据时会失败。
我起初怀疑是 IRIS 的问题,随后又怀疑是自己的代码出了问题。但事实并非如此。这其实是 macOS 完全按照其设计原理在正常运行。
macOS 的工作原理
每天午夜,macOS 会运行一个小型清理任务,删除 /tmp 目录下超过三天无人触碰的文件。 这是 macOS 自身的一部分,对于临时文件夹来说也是合情合理的。它只检查 /tmp(实际上是 /private/tmp),且不关心文件的具体内容。
为什么 IRIS 数据库特别容易受到影响
IRIS 将您使用的数据保存在内存中,仅在发生变更时才写入数据库文件。我对此进行了测试:读取数据库(即使是全部读取),文件的时间戳也完全保持不变。 因此,对于仅被读取或完全未使用的数据库,清理任务会将其视为未被触及,三天后该文件便会消失。
临时数据库最先被清理,因为 IRIS 几乎从不将它们写入磁盘。但任何数据库只要三天内未发生变更,都会被纳入清理范围。
接下来会发生什么
这一步让我感到惊讶。我特意使用一个全新的容器和一个测试数据库重现了这一现象:
- 起初,一切看起来都很正常。**IRIS 仍然保持着该文件的打开状态,因此它会持续读取您的数据,并报告数据库已挂载。
- 当数据库需要扩展时,写入操作开始失败。**一项小规模的更改成功通过;而一项大规模的更改则中途失败。
- 下次重启时,IRIS 拒绝启动。**它有待写入的更改,但目标文件已不存在,因此它选择停止运行而非进行猜测。该实例一直处于停机状态,直到有人介入处理,而该数据库中的数据已丢失。
- 容器仍显示为运行中。**Docker 始终报告该容器处于运行状态,尽管其中的 IRIS 并未启动。
如果您是通过搜索来到这里的,这些就是我看到的日志信息。路径是我测试数据库的,您的数据库会有自己的名称。当 IRIS 仍在运行时,messages.log 记录如下:
Error opening volume to write block 652 of /durable/iris/mgr/userdb/
而在下次启动时,IRIS 停止运行并显示:
Failed to open /durable/iris/mgr/userdb/IRIS.DAT: errno=2
We failed to fully restore the WIJ.
** Startup aborted **
Recovery failure. Startup aborted.
要恢复正常,需要从备份中还原数据库。IRIS 确实提供了一种强制启动的方式,但会警告说,如果采用此方法,其他数据库可能会受损。
哪些用户会受到影响
这与容器无关。关键在于文件在您的 Mac 上的存储位置:
- IRIS 以原生方式安装在常规位置(例如您的用户目录或
/opt之下) 否 - 原生安装,或者仅有一个数据库、日志或其他数据文件夹位于
/tmp之下是 - 数据位于
/tmp下的文件夹中的容器(例如-v /tmp/iris:/durable) 是 - 使用命名 Docker 卷或位于
/tmp之外的文件夹的容器 否
/tmp 是进行快速实验的理想位置,而三天的时间足够短,足以让你发现那个本打算在周五删除、却一直忘记直到周一才想起的容器。
如何检查
在 /tmp 目录下查找数据库文件:
find /private/tmp -name IRIS.DAT 2>/dev/null
如果输出内容中有您关心的信息,请在今晚之前将其转移。对于容器,请检查每个容器将数据存储在何处:
docker inspect --format '{{.Name}} {{range .Mounts}}{{.Source}} {{end}}' $(docker ps -q)
任何以 /tmp 或 /private/tmp 开头的源路径都存在风险。
如何避免此问题
- 请勿将 IRIS 数据存放在
/tmp中。您可以将其存放在用户主目录下的文件夹中,或者使用命名的 Docker 卷。 - 若确实需要使用
/tmp进行快速测试,请将该容器视为一次性容器,并在其运行未满三天时重新创建。 - 不要依赖容器的“运行中”状态。请确认 IRIS 本身是否已启动,例如在容器内执行
iris qlist命令。
我的经验总结
- 当实例出现异常时,在归咎于数据库之前,请先查看其文件所在的位置。
- 一个运行时间超过计划的测试容器,就不再是“一次性”容器了。
- “正在运行”不等于“正常工作”。
我正在将 OcuPilot 自身的测试容器从 /tmp 移出。如果你在 Mac 上运行 IRIS,今天请花一分钟检查一下你的情况。
我使用人工智能协助起草和编辑了这篇文章;其中的观点、决策和最终审阅均由我本人负责。