ZFS на Linux - L2ARC не читается

ZFS на Linux - L2ARC не читается

Сегодня я провел несколько тестов на L2ARC, используя последнюю версию ZFS на Linux 0.7.10. Я видел, что L2ARC заполняется данными, но с настройками модуля по умолчанию данные, находящиеся в кэше L2ARC, никогда не трогаются. Вместо этого данные считываются из vdev основного пула. Я также видел такое поведение в 0.7.9, и я не уверен, является ли это ожидаемым поведением.
Даже если это ожидаемое поведение, я думаю, что странно портить L2ARC данными, которые никогда не считываются.


Тестовая установка представляет собой виртуальную машину:

  • CentOS 7.5 с последними патчами
  • ZFS на Linux 0.7.10
  • 2 ГБ ОЗУ

Я сделал некоторые настройки 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во втором терминале.

К моему удивлению, файл был прочитан из обычных vdevs вместо L2ARC, хотя файл находится в 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 и не объединять кандидатов prefetch в L2ARC. Так что на данный момент, в зависимости от размеров файлов и размера L2ARC, приходится идти на компромисс.
Другой подход, похоже, доступен в релизе ZoL 0.8.0, где можно использовать разныеКлассы распределенияи должно позволить, например, разместить ваши метаданные на быстрых SSD-дисках, оставляя блоки данных намедленныйвращающиеся диски. Это все равно оставит спормаленькие файлыпротив.большие файлыдля L2ARC, но решит проблему быстрого доступа к метаданным.

решение2

В этом случае ZFS пытается сохранить полосу пропускания L2ARC для случайных/не потоковых чтений, где попадание на физические диски нанесет ущерб производительности. Потоковые чтения обслуживаются достаточно хорошо с механических HDD, и любой пул с 6/8+ дисками, вероятно, превзойдет любое устройство SATA L2ARC для последовательных чтений. И любой zpool среднего размера (т. е.: 24/48+ дисков) дастмножествопоследовательной реальной пропускной способности.

Как вы обнаружили, вы можете изменить L2ARC, чтобы он вел себя более похоже на кэш жертвы (т. е.: хранить все, что вытеснено из ARC; если блок найден в L2ARC, даже не пытаться получить доступ к основному пулу). В некоторых конкретных настройках это может быть хорошо; однако ZFS была (правильно) спроектирована так, чтобы сохранять износ/использование L2ARC там, где это может быть действительно выгодно: для кэширования действительно используемых блоков для более высокой производительности случайных чтений.

Связанный контент