李守中

ZFS ZIL(SLOG) 组件

ZIL 虽然用起来有写缓存的效果,但 ZIL 不是写缓存

ZIL 全称是 ZFS Intent Log,可以理解成是 ZFS 的写入日志,即使没有添加用于 ZIL 的独立设备,它也存在于 zpool 的内部。它唯一作用就是防止系统崩溃时丢失正在写入的数据: 数据会先被写入 ZIL 再被写入物理硬盘,写两遍。这就意味着,如果不出现系统突然挂掉之类的情况,ZIL 中的数据基本没用。

ZFS 的写入操作在 sync=always 的情况下,到达内存的数据必须先作为 ZIL 数据被写入到硬盘上,然后写操作才能返回成功。如果服务器挂掉,那么系统重启之后,ZFS 可以根据硬盘上的 ZIL 数据找到没有来得及写入 ZFS 的数据,重新写入 ZFS 文件系统,不会丢数据。

但如果是 sync=disabled 那么数据到达内存后,写操作就可以返回成功了,后台进程会在一段时间 (5s) 之后把内存中的数据写到物理硬盘上 (先向物理硬盘的 ZIL 写一次,再向文件系统写一次),所以如果这 5s 收到的数据如果还没来得及全部写到硬盘里机器就挂了,那么没来得及写入的数据就永久丢失了。

考虑到绝大多数情况下 zpool 都建立在机械硬盘上,所以 ZIL 也被放到机械硬盘组成的 zpool 里,但是 ZIL 写入操作全是 4K 写操作 ,而组成 zpool 的机械硬盘 4K 写性能太差了,所以 ZFS 搞出了一个 SLOG ( Separate intent LOG ) 组件, SLOG 组件必须是一个独立设备或分区,专门存放 ZIL 数据

后文用 SLOG 设备 指代 具有 ZIL 功能的独立设备或分区

根据 Oracle Solaris 关于 ZFS and Cache Flushing 的文档,在 uberblock 更新后,ZFS 大约每隔 5s 将缓存中所有未写入的数据写入到硬盘上 (每次程序请求同步写入,比如 O_DSYNC, fsync, NFS commit 等操作时,ZFS 也会刷新数据)。这里的将缓存写入硬盘是指 ZFS 将内存中保存的、已经在 ZIL 记录过的数据,写入到物理硬盘上。

注: uberblock 记录了整个 ZFS Pool 的信息,Pool 中的每个硬盘上都有 4 个 uberblock 的 copy。它的作用与 UFS 中的 superblock 类似。由于它记录了 ZFS Pool 的信息,所以当 ZFS 被更新时,它也会被更新。从代码结构上讲,它更像是一个指向 ZFS 树根节点的指针。

5s 这个数据意味着,当服务器作为 NAS 使用,ZIL 数据的规模并不大 (没必要用大容量 SSD):

注: 1 G = 1000 M, 1 M = 1000 K, 1 Gi = 1024 Mi, 1 Mi = 1024 Ki, 1 Byte = 8 bit

ZFS 收到数据之后:

  1. 先将数据写在内存中
  2. 再把内存中的数据写一份到 ZIL 中
  3. 最后把保存在内存中的、已被写入到 ZIL 的数据再写一份到 ZFS 文件系统 (写入物理硬盘)

数据在真正被写入文件系统 (物理硬盘) 之前共有两份,一份在内存中,另一份在 ZIL 中。

数据被处理的整个过程中会有三份,内存中、ZIL 中和文件系统 (物理硬盘) 中。

整个数据处理过程中,写硬盘的操作 串行 发生了两次,第一次是写 ZIL 数据 (4K 写),第二次的写操作是把数据存入硬盘上的文件系统 (4K 或顺序写)。

发生在 ZIL 的 4K 写操作就是性能下降的原因。

所以只要让所有的 ZIL 写操作都发生在 4K 性能好的 SSD 上,整个 zpool 的性能就上去了。这时候 SLOG 就派上了用场。

根据文档,SLOG 设备必须是一个独立设备,如果这个设备的 4K 同步写性能很好的话可以提升整体的 zpool 的同步写性能。所以之前会用 ZeusRAM 现在会用 Optane 来存储 ZIL 数据,因为这种设备写入能力很强。

给一个实机测试:

NFSv3 客户端下,写入 100G 文件的稳定速度可以由原来的 15 - 18 MB/s 提升到 45 - 50 MB/S (接近傲腾 M10 的 4K 写速率),性能瓶颈在傲腾的 4K 写入上。如果 SLOG 设备 4K 写性能更强,写入速度会更快。

作为 NAS 使用,单个 zpool 分 2 倍理论数据的规模已经足够。即,使用双万兆网卡负载均衡就给每个 zpool 分 23.4 GiB 大小的 SLOG 设备;使用双千兆网卡负载均衡就给每个 zpool 分 2.34 GiB 大小的 SLOG 设备。

注: FreeNAS 文档里提到,它们推荐的 SLOG 设备大小是 16 GiB。

如果用的是 905p/900p,那么在分出用做 SLOG 的空间后,剩下的可以都拿去做 L2ARC。千兆环境用 16GB 傲腾,万兆用 58GB 的 800p 已经足够做 SLOG 了。

除了每 5s 将缓存数据写入硬盘之外,当缓存的数据的大小达到 sysctl vfs.zfs.dirty_data_max_max 所指定的值时,也会触发写入事务。所以 SLOG 设备容量的最大值不应超过 vfs.zfs.dirty_data_max_max 定义的大小

因为当未被写入硬盘的数据的大小超过 vfs.zfs.dirty_data_max_max 时,ZFS 立即触发硬盘写入,每条数据被写入硬盘后,该条数据占用的 ZIL 空间会被释放。所以超出 vfs.zfs.dirty_data_max_max 大小的空间不会被 SLOG 使用,多余的空间没有意义。



Last Update: 2023-09-17 Sun 10:10

Contact: [email protected]     Generated by: Emacs 27.1 (Org mode 9.3)

若正文中无特殊说明,本站内容遵循: 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议