在Solaris 11.3上启动ZFS L2ARCcaching

在Solaris 11.3上安装ZFS L2ARCcaching是否有一个好方法?

L2ARC旨在忽略从文件中顺序读取的块。 这对于正在进行的操作是有意义的,但是使初始预热或基准testing中的高速caching变得困难。

另外,高度分散的文件可能会因在L2ARC中caching的连续读取而受益匪浅(因为磁盘上是随机读取的),但是就目前的启发式而言,即使L2ARC仅占满10%,这些文件也永远不会被caching。

在以前的Solaris 10和11发行版中,我成功地在每个文件上连续使用了dd两次。 第一个dd将文件读入ARC,第二个dd似乎让缓冲区发痒,所以他们有资格进行L2ARCcaching。 相同的技术在Solaris 11.3中似乎不起作用。

我已经证实,有问题的文件有一个8Klogging, 我试过设置zfs_prefetch_disable但这对L2ARC行为没有影响 更新: zfs_prefetch_disable结果是重要的,请参阅下面的答案。

如果没有好的办法做,我会考虑使用一个工具,产生100%的文件随机读取。 考虑到高速caching现在保持在11.3,这可能是值得的。 像这样的工具存在吗?

通过一些实验,我发现了四种可能的解决scheme。

使用每种方法,您都需要执行这些步骤,然后继续读取更多数据以填充ZFS ARCcaching并触发从ARC到L2ARC的提要。 请注意,如果数据已经caching在内存中,或者每个块的磁盘上的压缩大小大于32kB,这些方法通常不会做任何事情。

1.设置logging的内核标志zfs_prefetch_disable

默认情况下,L2ARC拒绝caching已被自动预取的数据。 我们可以通过禁用ZFS预取function来绕过这一点。 无论如何,这个标志通常是数据库工作负载的好主意。

 echo "zfs_prefetch_disable/W0t1" | mdb -kw 

或者将其设置为permananently,将以下内容添加到/etc/system

 set zfs:zfs_prefetch_disable = 1 

现在,当使用dd读取文件时,他们仍然有资格获得L2ARC。

在操作上,这种改变也改善了我testing中读取的行为。 通常,当ZFS检测到顺序读取时,它会平衡数据vdevs和cachingvdevs之间的吞吐量,而不是仅从caching中读取数据 – 但是,如果caching设备的延迟或吞吐量要比数据设备低得多,则会损害性能。

2.重新写入数据

当数据被写入ZFS文件系统时,它被caching在ARC中,并且(如果它符合块大小标准)可以被馈送到L2ARC中。 重写数据并不容易,但是一些应用程序和数据库可以通过应用程序级文件镜像或移动数据文件来实时生效。

问题:

  • 并不总是可能取决于应用程序。
  • 如果有快照正在使用,则占用额外的空间。
  • (但好的一面是,生成的文件经过了碎片整理。)

3.取消未logging的内核标志l2arc_noprefetch

这是基于阅读OpenSolaris源代码,毫无疑问完全不受支持。 使用风险自负。

  1. 禁用l2arc_noprefetch标志:

     echo "l2arc_noprefetch/W0" | mdb -kw 

    当该标志被禁用时,读入ARC的数据即使是顺序读取(只要磁盘上的块最多为32k),也将符合L2ARC的条件。

  2. 从磁盘读取文件:

     dd if=filename.bin of=/dev/null bs=1024k 
  3. 重新启用l2arc_noprefetch标志:

     echo "l2arc_noprefetch/W1" | mdb -kw 

4.随机读取数据

我写了一个Perl脚本,以伪随机方式读取8kB块中的文件(基于Perl哈希的sorting)。 它也可能与更大的块,但我还没有testing。

 #!/usr/bin/perl -W my $BLOCK_SIZE = 8*2**10; my $MAX_ERRS = 5; foreach my $file (@ARGV) { print "Reading $file...\n"; my $size; unless($size = (stat($file))[7]) {print STDERR "Unable to stat file $file.\n"; next; } unless(open(FILE, "<$file")) {print STDERR "Unable to open file $file.\n"; next; } my $buf; my %blocks; for(my $i=0;$i<$size/$BLOCK_SIZE;$i++) { $blocks{"$i"} = 0; } my $errs = 0; foreach my $block (keys %blocks) { unless(sysseek(FILE, $block*$BLOCK_SIZE, 0) && sysread(FILE, $buf, $BLOCK_SIZE)) { print STDERR "Error reading $BLOCK_SIZE bytes from offset " . $block * $BLOCK_SIZE . "\n"; if(++$errs == $MAX_ERRS) { print STDERR "Giving up on this file.\n"; last; } next; } } close(FILE); } 

问题:

  • 这需要很长时间,并且会在磁盘上造成沉重的工作量。

剩余的问题

  • 上述方法将把数据存入主内存,有资格进入L2ARC,但是它们不会触发feed。 我知道触发写入L2ARC的唯一方法就是继续读取数据,向ARC施加压力。
  • 在具有SRU 1.3.9.4.0的Solaris 11.3上,L2ARC很less增长预期的全部数量。 即使SSD设备没有压力, evict_l2_eligible kstat也会增加,表示数据正在丢失。 未caching的数据剩余量对性能有不成比例的影响。

我build议使用真正的工作负载,并用arcstat监视结果。

就像是:

 arcstat.py -f "time,read,l2read,hit%,hits,miss%,miss,l2hit%,l2miss%,arcsz,c,l2size" 1 

我不认为有什么需要“启动”caching。 如果你拥有的工作量不能自然地填充caching,那么这不是一个有代表性的基准工作量,对吧?

也许你有一个特殊的用例(你的数据集大小,ARC大小和工作集大小是多less?) ,但总的来说,L2ARC的重点是过分强调。