Сегодня я провел несколько тестов на 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 там, где это может быть действительно выгодно: для кэширования действительно используемых блоков для более высокой производительности случайных чтений.