diff --git a/_sass/content.scss b/_sass/content.scss index 728ac69b16..d8793b78be 100644 --- a/_sass/content.scss +++ b/_sass/content.scss @@ -141,3 +141,13 @@ li p { dd { font-size: 1em; } + +.footnote { + &::before { + content: "["; + } + + &::after { + content: "]"; + } +} diff --git a/pages/_planet/2024-12-09-ustc-mirrors-zfs-rebuild.md b/pages/_planet/2024-12-09-ustc-mirrors-zfs-rebuild.md index 7cd219288b..a19831d76a 100644 --- a/pages/_planet/2024-12-09-ustc-mirrors-zfs-rebuild.md +++ b/pages/_planet/2024-12-09-ustc-mirrors-zfs-rebuild.md @@ -110,21 +110,21 @@ Rsync 服务器的流量较少,但磁盘使用率较为极端,加上我们 - 首先,考虑到镜像站上一半的文件都不到 10 KiB(注意我们的磁盘的物理扇区大小是 4 KiB),RAID-Z3 的开销过高,因此我们决定将其重建为 RAID-Z2 并且拆成两组 vdev。这样做还有一个额外的好处,即期望情况下我们还可以在这个 ZFS pool 中获得两倍的 IOPS,毕竟文件的每个“块”只存储在一个 vdev 上。 - 然后我们仔细研究了如何为镜像站场景调优 ZFS dataset 参数: - - `recordsize=1M`:尽可能优化顺序读写性能,同时减少碎片化 - - `compression=zstd`:开点压缩来试试能节约多少磁盘空间 + - `recordsize=1M`:尽可能优化顺序读写性能,同时减少碎片化。 + - `compression=zstd`:开点压缩来试试能节约多少磁盘空间。 - OpenZFS 2.2 开始将 early-abort 机制引入了 Zstd 压缩算法(Zstd-3 以上的等级)。该机制会首先尝试使用 LZ4 和 Zstd-1 来压缩数据以便评估数据的可压缩性,如果数据不可压缩(熵太大),则不再尝试用设定的 Zstd 等级压缩,而是直接原样写入磁盘上,避免在不可压缩的数据上浪费 CPU。 我们已知镜像站上的大部分内容都是已经压缩过的,因此 early-abort 算是给我们兜了个底,让我们可以放心地开 Zstd。 - - `xattr=off`:镜像站上的文件不需要扩展属性 - - `atime=off`:镜像站上的文件不需要记录,也不需要更新 atime,可以省掉不少写入 - - `setuid=off`、`exec=off`、`devices=off` 也是我们不需要的挂载选项(也是一个更安全的做法) + - `xattr=off`:镜像站上的文件不需要扩展属性。 + - `atime=off`:镜像站上的文件不需要记录,也不需要更新 atime,可以省掉不少写入。 + - `setuid=off`、`exec=off`、`devices=off` 也是我们不需要的挂载选项(也是一个更安全的做法)。 - `secondarycache=metadata` 让 L2ARC 仅缓存 ZFS 内部的元数据。这是因为 Rsync 服务器上的文件访问模式更加均匀,而不像面向终端用户的 HTTP 服务器上冷热分明,因此仅缓存元数据可以节约 SSD 寿命。 - 以及一些可能有潜在(但我们认为我们可以容忍的)风险的选项: - - `sync=disabled`:禁用同步写入语义(`open(O_SYNC)`、`sync()` 和 `fsync()` 等)以让 ZFS 能够充分发挥写缓冲区的意义,如降低碎片率等 + - `sync=disabled`:禁用同步写入语义(`open(O_SYNC)`、`sync()` 和 `fsync()` 等)以让 ZFS 能够充分发挥写缓冲区的意义,如降低碎片率等。 - `redundant_metadata=some`:(OpenZFS 2.2)减少元数据的冗余度来获得更好的写入性能。 我们认为这两个选项符合我们对镜像站仓库内容的数据安全和完整性需求的理解,它们在其他场景下不一定“安全”。 @@ -198,7 +198,7 @@ Rsync 服务器的流量较少,但磁盘使用率较为极端,加上我们 - 我们最初分配了 1.5 TB 的 SSD 缓存,但 LVMcache 又建议我们不要超过 100 万个 chunk,我们当时也没有足够的精力和知识水平去研究这个建议背后的技术细节,因此我们最终只分配了 1 TiB(1 MiB chunk size \* 1 Mi chunks)的 SSD 缓存。 - SSD 缓存策略不可调,多年以后我们翻了 kernel 源码才发现它是一个 64 级的 LRU。 - 配好 cache 之后 GRUB 立刻挂了(难绷),我们调查发现原因是 GRUB 有一套自己的解析 LVM metadata 的代码,它并没有正确处理(或者说根本没处理)VG 中有 cache volume 的情况,我们不得不自己 [patch](https://github.com/taoky/grub/commit/85b260baec91aa4f7db85d7592f6be92d549a0ae) 了 GRUB 才能正常开机。 -- 由于我们对 LVMcache 的 chunk 不够了解,我们的 SSD 在不到 2 年的时间里就严重超过了写入寿命,我们被迫申请换新。 +- 由于我们对 LVMcache 的 chunk 不够了解,我们的 SSD 在不到 2 年的时间里就严重超过了标称的写入寿命,我们被迫申请换新。 在 SSD 换新之后,即使我们认为我们对 LVMcache 做出了稍微合理一点的调参,坚持忽略警告采用 128 KiB 的 chunk size 和 800 万个 chunk 之后,它的性能(命中率)也并不可观: @@ -217,7 +217,7 @@ Rsync 服务器的流量较少,但磁盘使用率较为极端,加上我们 - 考虑到这台服务器直接向用户提供 HTTP 服务,磁盘的访问模式会比 Rsync 服务器更加冷热分明,因此我们保持了 `secondarycache=all` 的设置(采用默认值,不动)。 - 这台新服务器的 CPU 更新更好,因此我们把压缩等级提高到了 `zstd-8` 来试试能否获得更好的压缩比。 - 我们在 Rsync 服务器上已经有了一个完整的、经过 ZFS 优化过的仓库,因此我们可以直接用 `zfs send -Lcp` 把数据倒过来。我们最终只花了 36 小时就把超过 50 TiB 的数据都倒回来了。 -- 由于两台服务器上存储的镜像仓库有所不同,HTTP 服务器上的压缩比略低一些,为 1 + 3.93%(压掉了 2.42 TiB / 2.20 TiB)。 +- 由于两台服务器上存储的镜像仓库有所不同,HTTP 服务器上的压缩比略低一些,为 1 + 3.93%(压掉了 2.42 TB / 2.20 TiB)。 我们把两台服务器的 I/O 负载放在一张图里对比: @@ -398,4 +398,4 @@ ZFS 解决了我们镜像站上的一大堆问题,并且有了此次调参经 虽然我们的 ZFS 配置看起来非常高效,但我们也知道 ZFS 在长期运行中可能会因为碎片化而导致性能下降的问题。 我们会持续关注我们的服务器,监控长期的性能变化。 -[^as-of]: 指本文所述的重建工程之前 +[^as-of]: 指本文所述的重建工程之前,即 2024 年 6 月中旬。