Linux 上的 ZFS - L2ARC 未被读取

Linux 上的 ZFS - L2ARC 未被读取

今天,我使用 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=1024l2arc_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_distancezfetch_max_streamsl2arc_write_boostl2arc_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 磨损/使用:缓存真正使用的块以获得更快的随机读取性能。

相关内容