今天,我使用 Linux 0.7.10 上的最新 ZFS 对 L2ARC 进行了一些测试。我发现 L2ARC 中充满了数据,但使用默认模块设置时,驻留在 L2ARC 缓存中的数据永远不会被触及。相反,数据是从主池的 vdev 中读取的。我在 0.7.9 中也看到了这种行为,我不确定这是否是预期的行为。
即使这是预期的行为,我认为用从未读取的数据破坏 L2ARC 是很奇怪的事情。
测试安装是虚拟机:
- CentOS 7.5 已安装最新补丁
- Linux 0.7.10 上的 ZFS
- 2GB 内存
我做了一些 ZFS 设置:
l2arc_headroom=1024
并l2arc_headroom=1024
加速 L2ARC 的普及
以下是池的创建方式和布局。我知道这对于真实世界的设置来说很奇怪,但这仅用于 L2ARC 测试。
[root@host ~]# zpool create tank raidz2 /dev/sda /dev/sdb /dev/sdc cache sdd -f
[root@host ~]# zpool list -v
NAME SIZE ALLOC FREE EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT
tank 2.95G 333K 2.95G - 0% 0% 1.00x ONLINE -
raidz2 2.95G 333K 2.95G - 0% 0%
sda - - - - - -
sdb - - - - - -
sdc - - - - - -
cache - - - - - -
sdd 1010M 512 1009M - 0% 0%
现在将一些数据写入文件并查看设备使用情况。
[root@host ~]# dd if=/dev/urandom of=/tank/testfile bs=1M count=512
512+0 records in
512+0 records out
536870912 bytes (537 MB) copied, 9.03607 s, 59.4 MB/s
[root@host ~]# zpool list -v
NAME SIZE ALLOC FREE EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT
tank 2.95G 1.50G 1.45G - 10% 50% 1.00x ONLINE -
raidz2 2.95G 1.50G 1.45G - 10% 50%
sda - - - - - -
sdb - - - - - -
sdc - - - - - -
cache - - - - - -
sdd 1010M 208M 801M - 0% 20%
好的,部分数据已移至 L2ARC,但不是全部。因此,请多读几遍,使其完全进入 L2ARC。
[root@host ~]# dd if=/tank/testfile of=/dev/null bs=512 # until L2ARC is populated with the 512MB testfile
[root@host ~]# zpool list -v
NAME SIZE ALLOC FREE EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT
tank 2.95G 1.50G 1.45G - 11% 50% 1.00x ONLINE -
raidz2 2.95G 1.50G 1.45G - 11% 50%
sda - - - - - -
sdb - - - - - -
sdc - - - - - -
cache - - - - - -
sdd 1010M 512M 498M - 0% 50%
好的,L2ARC 已填充并准备读取。但首先需要删除 L1ARC。我做了以下操作,似乎有效。
[root@host ~]# echo $((64*1024*1024)) > /sys/module/zfs/parameters/zfs_arc_max; sleep 5s; echo $((1024*1024*1024)) > /sys/module/zfs/parameters/zfs_arc_max; sleep 5s; arc_summary.py -p1
------------------------------------------------------------------------
ZFS Subsystem Report Sun Sep 09 17:03:55 2018
ARC Summary: (HEALTHY)
Memory Throttle Count: 0
ARC Misc:
Deleted: 20
Mutex Misses: 0
Evict Skips: 1
ARC Size: 0.17% 1.75 MiB
Target Size: (Adaptive) 100.00% 1.00 GiB
Min Size (Hard Limit): 6.10% 62.48 MiB
Max Size (High Water): 16:1 1.00 GiB
ARC Size Breakdown:
Recently Used Cache Size: 96.06% 1.32 MiB
Frequently Used Cache Size: 3.94% 55.50 KiB
ARC Hash Breakdown:
Elements Max: 48
Elements Current: 100.00% 48
Collisions: 0
Chain Max: 0
Chains: 0
好了,现在我们可以从 L2ARC 读取了(抱歉前言太长,但我认为这很重要)。
因此再次运行命令,我在第二个终端中dd if=/tank/testfile of=/dev/null bs=512
观察。zpool iostat -v 5
令我惊讶的是,虽然文件位于 L2ARC 中,但它是从普通 vdev 而不是 L2ARC 读取的。这是文件系统中唯一的文件,在我的测试期间没有其他活动。
capacity operations bandwidth
pool alloc free read write read write
---------- ----- ----- ----- ----- ----- -----
tank 1.50G 1.45G 736 55 91.9M 96.0K
raidz2 1.50G 1.45G 736 55 91.9M 96.0K
sda - - 247 18 30.9M 32.0K
sdb - - 238 18 29.8M 32.0K
sdc - - 250 18 31.2M 32.0K
cache - - - - - -
sdd 512M 498M 0 1 85.2K 1.10K
---------- ----- ----- ----- ----- ----- -----
然后我调整了一些设置,例如,,,zfetch_array_rd_sz
和,将它们设置为奇数。但什么都没有改变。 zfetch_max_distance
zfetch_max_streams
l2arc_write_boost
l2arc_write_max
改变后
l2arc_noprefetch=0
(默认为1
)- 或
zfs_prefetch_disable=1
(默认为0
) - 切换默认设置
读取由 L2ARC 提供。再次在第二个终端中运行dd if=/tank/testfile of=/dev/null bs=512
并观察zpool iostat -v 5
,然后删除 L1ARC。
[root@host ~]# echo 0 > /sys/module/zfs/parameters/l2arc_noprefetch
[root@host ~]# echo $((64*1024*1024)) > /sys/module/zfs/parameters/zfs_arc_max; sleep 5s; echo $((1024*1024*1024)) > /sys/module/zfs/parameters/zfs_arc_max; sleep 5s; arc_summary.py -p1
...
[root@host ~]# dd if=/tank/testfile of=/dev/null bs=512
结果如下:
capacity operations bandwidth
pool alloc free read write read write
---------- ----- ----- ----- ----- ----- -----
tank 1.50G 1.45G 0 57 921 102K
raidz2 1.50G 1.45G 0 57 921 102K
sda - - 0 18 0 34.1K
sdb - - 0 18 0 34.1K
sdc - - 0 19 921 34.1K
cache - - - - - -
sdd 512M 497M 736 0 91.9M 1023
---------- ----- ----- ----- ----- ----- -----
现在从 L2ARC 读取数据,但只有在切换上面提到的模块参数后才能读取。
我还读到过 L2ARC 的大小可能过大。但是我发现有关该主题的帖子都提到了性能问题或 L2ARC 的空间图破坏了 L1ARC。
性能不是我的问题,而且据我所知,L2ARC 的空间图也没有那么大。
[root@host ~]# grep hdr /proc/spl/kstat/zfs/arcstats
hdr_size 4 279712
l2_hdr_size 4 319488
正如前面提到的,我不确定这是否是预期的行为或者我是否遗漏了什么。
答案1
所以在读完这个话题之后,主要这个帖子,看来这是 ZFS 的默认行为。
实际情况是,文件在读取后进入 L1ARC,由于块被访问,因此被视为放入 L2ARC。
现在,在第二次读取文件时,ZFS 正在对文件进行预取,这会绕过 L2ARC,尽管文件的块存储在 L2ARC 中。
通过使用 完全禁用预取zfs_prefetch_disable=1
或使用 告诉 ZFS 在 L2ARC 上进行预取l2arc_noprefetch=0
,读取将利用驻留在 L2ARC 中的文件块。
如果您的 L2ARC 与正在读取的文件大小相比足够大,这可能是理想的选择。
但您可能只想使用 将metadata
其放入 L2ARC zfs set secondarycache=metadata tank
。这可以防止大文件最终进入 L2ARC 并且永远不会被读取。因为这将破坏L2ARC 可能会驱逐未被预取的较小文件块和元数据,而您希望将其保留在 L2ARC 中。
我还没有找到一种方法来告诉 ZFS仅限小文件进入 L2ARC,而不是将预取候选合并到 L2ARC。因此,目前,必须根据文件大小和 L2ARC 大小进行权衡。ZoL
0.8.0 版本中似乎提供了一种不同的方法,可以使用不同的分配类别并且可以将元数据放在快速 SSD 上,同时将数据块留在慢的旋转磁盘。这仍然会留下争用小文件对阵大文件对于 L2ARC,但将解决元数据的快速访问问题。
答案2
在这种情况下,ZFS 试图为随机/非流式读取保留 L2ARC 带宽,而访问物理磁盘将严重破坏性能。流式读取在机械硬盘上表现相当不错,任何具有 6/8 个以上磁盘的池在顺序读取方面可能都优于任何 SATA L2ARC 设备。任何中等规模的 zpool(即:24/48 个以上磁盘)都将提供充足连续实际带宽。
正如您所发现的,您可以修改 L2ARC,使其行为更类似于受害者缓存(即:存储从 ARC 中逐出的任何内容;如果在 L2ARC 上发现一个块,甚至不要尝试访问主池)。在某些特定设置中,这可能是一件好事;但是,ZFS 的架构(正确)是为了在真正有利的情况下保留 L2ARC 磨损/使用:缓存真正使用的块以获得更快的随机读取性能。