是时候停止一些无意义的操作了。
最近发觉家里的那台自建 NAS 的性能越来越差了,先是 FreshRSS 开始撞到网关超时,然后是 Gitea 也越跑越慢。虽然迁移到 PostgreSQL 能勉强续一秒,但这总归不是个好事。
直觉上是因为整个存储阵列要被塞满了,所以越来越多的读写负载会发生在那对容量最大的磁盘上;加上现在又有多个服务都会频繁产生写操作,尽管有 PostgreSQL 做缓存,机械硬盘也不能很好地接住这些频繁的随机写。
如果打开 kernel.task_delayacct[1] 并观察 iotop 的输出的话,会发现各个 PostgreSQL 产生的写入操作并不是很大,也并不是很频繁——虽然它们确实经常会出现 100.00 % 的 IO 等待时间,有时会卡住好几秒。
观察系统平均负载的话,容易看到按小时的涨落。有些大批量的硬盘写操作在周期性地发生。它也许是 FreshRSS 在大批量刷新订阅并写数据库;也许是系统中有一些维护任务在执行。但是 IOPS 却也随着写入的流量而一起涨落,而且经常摸到 1k 的数量级。如果是数据的写操作的话,它的 IOPS 应该更低一些才对。
这些模式指向了一个潜在的问题源:Mac mini 和 MacBook 的时间机器功能。只有这样一个玩意会每小时地产生大量读写操作,因为它需要比对旧数据、写入新的数据,又需要删除过时的数据。这自然会产生非常大的 IOPS. 我看着 iotop 上蹦出的几十行 smbd 的条目,觉得或许应该从这个方向排查一下。
时间机器是 macOS 系统自带的备份与还原功能,它可以连接到一个 SMB 共享文件夹,并展开一个特殊的文件夹结构 .sparsebundle. 它的内部结构模仿一个磁盘,里面由一些元数据和一个个「条带」组成。而每个「条带」……
dousha@dousha-box | ~ $ cd /mnt/volume/Backups
dousha@dousha-box | /mnt/volume/Backups $ cd TimeMachine
dousha@dousha-box | /mnt/volume/Backups/TimeMachine $ ls
dousha dousha-laptop-apple.sparsebundle dousha-mac-mini.sparsebundle
dousha@dousha-box | /mnt/volume/Backups/TimeMachine $ cd dousha-mac-mini.sparsebundle
dousha@dousha-box | /mnt/volume/Backups/TimeMachine/dousha-mac-mini.sparsebundle $ ls
bands com.apple.TimeMachine.MachineID.bckup com.apple.TimeMachine.MachineID.plist com.apple.TimeMachine.Results.plist com.apple.TimeMachine.SnapshotHistory.plist Info.bckup Info.plist lock mapped token
dousha@dousha-box | /mnt/volume/Backups/TimeMachine/dousha-mac-mini.sparsebundle $ cd bands
dousha@dousha-box | /mnt/volume/Backups/TimeMachine/dousha-mac-mini.sparsebundle/bands $ ls
0 114c 129a 13e8 1535 1683 17d1 191f 1a6d 1bbb 1d08 1e56 1fa4 20f4 2241 239 24de 262b 277b 28d 2a1e 2b6f 2cc 2e0d 2f62 30c0 3232 3381 34e8 3635 37a2 438 586 6d4 821 97 abe c12 d63 eb2
<300+ lines omitted>
114b 1299 13e7 1534 1682 17d0 191e 1a6c 1bba 1d07 1e55 1fa3 20f3 2240 238f 24dd 262a 277a 28cf 2a1d 2b6e 2cbf 2e0c 2f61 30c 3231 3380 34e7 3634 37a1 437 585 6d3 820 96f abd c11 d62 eb1
dousha@dousha-box | /mnt/volume/Backups/TimeMachine/dousha-mac-mini.sparsebundle/bands $ file 114
114: data
dousha@dousha-box | /mnt/volume/Backups/TimeMachine/dousha-mac-mini.sparsebundle/bands $
承载着不知道怎样格式的数据。也许是 HFS+ 或者 APFS 扇区数据之类的东西。
这意味着如果你没有一台跑着 macOS 的系统的话,想要从这坨二进制文件中提取出文件可能比打一枚能到月球的火箭还要难。
我突然觉得实际上我并不需要打开时间机器功能。
我在这些 Mac 上做的工作无外乎写写程序以及偶尔码一些不着边际的文字,多媒体的创作……我并没有足够的艺术细菌来支持,所以基本完全没有。而这些程序和文字自然已经是通过 git 良好组织了的。我没有任何理由去打开时间机器的恢复界面,因为 git checkout 来得更自然一些。
这些备份真的将永远不会用作恢复:Mac 的迁移过程可以在店里完成,所以压根用不到我的 NAS 上的一点内容;而如果我的 Mac 因为这样那样的原因炸掉,我又需要从备份里面调取文件的话,受限于果子的 .sparsebundle 格式,我必须再借一台 Mac 或者跑 macOS 虚拟机才能拿到我需要的东西。更不必提如果哪一天我决定离开果子的生态,那么这些数据就真的会变成一坨再也无法读取的毫无意义的二进制块。
配置时间机器是一个很头疼的事情。它没有 .timemachineignore 这样的文件,而且默认备份整个用户目录。虽然开箱即用很是方便,但这也使得各种开发环境产生的缓存文件和编译产物也会参与到备份当中,比如 .m2, .nuget, vcpkg/; 更不要说存在于各个工程目录里的 .venv, node_modules/, dist/, out/, cmake-build-debug/...
而即使我确实想要备份一些不适合扔到 git 里的东西,我也有另一个选择:UrBackup; 或者如果我需要可以从脚本中调用的工具的话: restic. 它们可以在本地文件有修改的情况下再执行备份过程,而不是每小时地产生一次维护动作;它们也可以动态地随着文件修改而立刻产生备份,而不需要等每小时一次的维护动作。
关闭时间机器的操作很简单,比我当初费劲调试 SMB 让它能开起来还要简单:在系统设置里删除 NAS 备份目标就可以了。当然,性能改善并非一劳永逸,我们还需要继续观察系统的运行情况。
sudo sysctl kernel.task_delayacct=1↩︎























