Глава 7. Кэширование

Как и любая другая файловая система, ZFS применяет кэширование в памяти для увеличения производительности. Однако, в отличие от большинства остальных файловых систем, системные администраторы могут выполнять тонкую настройку этих кэшей для регулирования поведения системы. ZFS кэширует список системных пулов в файле zpool.cache. Она может применять устройства кэширования для чтения и записи. Однако, находящимся на самом виду кэшем является кэш адаптивной замены (ARC).

 Кэш адаптивной замены

Вызов данных из оперативной памяти намного быстрее доступа к файлу с диска. Unix- подобные операционные системы обычно хранят копии файлов с наиболее частыми обращениями в буферном кэше в ОЗУ. ZFS использует наиболее искушённый и наиболее эффективный тип кэширования, кэш адаптивной замены, или ARC (Adaptive Replacement Cache). Понимание ARC начинается с осознание кэширующего буфера.

  Традиционный буферирующий кэш

Буферирующий кэш выбирает для кэширования данные на основе алгоритма вытеснения давно неиспользуемых данных, или LRU (Least Recently Used). LRU является списком, хранящимся по последнему времени доступа к порции данных. При каждом применении объекта он перемещается в вершину списка. По мере заполнения списка система отбрасывает элементы из нижней части этого списка до тех пор, пока не получит достаточное пространство для вставки новых элементов в вершину списка.

Буферирующий кэш работает достаточно хорошо для обеспечения выгод производительности, однако, при определённых условиях метод LRU вызывает нежелательное поведение.

Рассмотрим ночное резервное копирование. Программа резервного копирования сканирует весь жёсткий диск для поиска файлов, модифицированных с момента последнего резервного копирования. Выполнение такого сканирования добавляет такой файл в системе в вершину нашего списка, позволяя только что отсканированным файлам опускаться вниз списка. По окончанию резервного копирования буферирующий кэш наполнен данными, которые никого не беспокоят. Тем временем, критически важные базы данных были полностью удалены на диск. Это называется замусориванием кэша (cache thrashing).

ARC позволяет избегать подобных проблем.

  Проектирование ARC

ARC также кэширует файлы, которые только что были прочитаны с диска. Вместо одиночного списка ARC имеет два парных списка. Один является самым последним использованным, или MRU (Most Recently Used), списком, отслеживающим блоки файловой системы во многом аналогично буферирующему кэшу, а второй является списком наиболее часто используемых блоков MFU (Most Frequently Used), отслеживающим регулярно используемые блоки файловой системы.

Добавление списка MFU уменьшает воздействие процессов замусоривания кэша, подобных гипотетическим заданиям резервного копирования. Хотя сканирование всех файлов очищает список MRU, оно не воздействует на список MFU. Разовое сканирование блоков для целей резервного копирования на является "частым". Наиболее часто применяемые файлы остаются кэшированными в оперативной памяти. Выполнение вашего резервного копирования всё же влияет на дисковый ввод/ вывод, уменьшая производительность записи, однако система обслуживает наиболее популярные файлы из кэшированной в оперативной памяти копии.

Каждый список работает в паре с теневым (ghost) списком, который содержит информацию о блоках, которые были выселены из этого списка. Когда списки MRU или MFU заполняются, блоки из нижней части этих списков отбрасываются. Отслеживая такие удаляемые из кэшей блоки, ARC предотвращает постоянное циклическое занесение в кэш и удаление из него. В случае, когда блок используется достаточно часто, ARC также может принимать решение для обеспечения ему места в списке MFU.

Почти во всех случаях ARC является само-регулируемым, а ручное вмешательство системных администраторов может только ухудшить производительность. Может оказаться, что ваше конкретное приложение потребует специальной обработки. Однако, прежде чем начать возиться с ним, осознайте как ARC ведёт себя.

  Использование памяти ARC

ARC спроектирован и для жадных, и для щедрых. Если система имеет свободную оперативную память, а ARC предполагает, что, возможно, может извлечь из этого преимущества, ARC захватывает память. При всяком чтении с диска ARC кэширует файл в оперативной памяти. ARC продолжает кэшировать файлы до тех пор, пока система не использует всю свою оперативную память.

FreBSD резервирует 1ГБ оперативной памяти для ядра и прикладных программ. Вся оставшаяся оперативная память является предметом для справедливой игры ARC. В продолжительно работающих системах с большим объёмом систем хранения и не очень большим объёмом оперативной памяти не будет сюрпризом увидеть, что ваша ARC потребляет основную часть системной памяти.

Однако, ARC имеет очень низкий приоритет для запросов к памяи. Если приложение запрашивает оперативную память, а система не имеет достаточно свободной памяти, ядро усекает ARC, предоставляя приложению запрошенную им память. Процесс возвращения оперативной памяти ARC в вашу систему для свободного применения не является мгновенным; он может занять несколько секунд.

Таким образом: если память свободна, ARC будет её использовать. Если что-то испытывает потребность в этой памяти, ARC возвращает её назад. Современные сервера имеют в наличии много оперативной памяти. Они могли бы применять её для чего- то полезного. Старая поговорка "Свободная память- потерянная память" всё ещё является верной.

Наиболее простой способ проверки размера ARC состоит в применении top(1). Приведём часть вывода top для сервера с 32ГБ ОЗУ и 20ТБ дискового пространства.


…
Mem: 168M Active, 116M Inact, 24G Wired, 1168K Cache, 449M Buf, 7052M Free
ARC: 23G Total, 15G MFU, 7398M MRU, 18K Anon, 412M Header, 88M Other
…
 	   

Строка Mem, появляется в верхней части вывода почти всех Unix- подобных систем и она предлагает подробности того, как много оперативной памяти системы используется для различных типов задач. Хотя ARC является поднабором закреплённой памяти, ARC выводится отдельно, поэтому она может предложить дополнительные подробности.

Первый элемент, Total, отображает общую используемую ARC память.

Файлы, имеющие частый доступ к ним, отображены в пространстве MFU. У нас отображено 15ГБ данных MFU в ARC.

Записи MRU показывают 7 398МБ, применяемых для хранения файлов, к кторым был осуществлён самый последний доступ.

Данные, перемещаемые из одной очереди в другую, а также операции асинхронной записи ожидающие сброса на диск отображаются в пространстве Anon. Приводимая в списке Header память используется для метаданных самой ARC. Данные 23ГБ ARC требуют 412МБ метаданных. Other включает вещи наподобие метаданных исключительно для времени исполнения, применяемых для помощи поиска ARC содержимого в своём кэше. Строго говоря, эта память не является частью кэша самого по себе, однако она поддерживает инфраструктуру.

Хотя ARC является жадной по отношению к оперативной памяти, заметим, что продолжительно работающие системы всё же имеют несколько гигабайт свободной памяти. Диски являются чрезвычайно заполненными, однако необходимый реальным пользователям объём данных относительно невелик. Всякий, кто управляет файловыми серверами узнаёт такую модель - каждое подразделение деловых учётных записей имеет одну главную таблицу плюс 15 миллиардов слегка отличающихся копий этой таблицы для различных дат, причём все они жизненно необходимы и должны быть сохранены для потомков навечно. Если ARC использует большую часть вашей системной памяти, то это происходит по той причине, что процессы осуществляют доступ к файлам. ARC не охотится за оправданиями для высасывания ОЗУ.

  Zfs-stats

ZFS раскрывает производительность, настройки и системы показателей ZFS множеством sysctls в vfs.zfs и kstat.zfs. Сами по себе эти значения обычно означают очень мало чего, однако они становятся понятными при их сравнении друг с другом. Вместо того, чтобы разбирать эти значения напрямую мы настоятельно рекомендуем для исследования ARC применять пакет zfs-stats .

Для получения основной информации о вашем ARC, например, текущим размером и длиной каждой очереди внутри ARC, воспользуйтесь zfs-stats -A. Приведём интересный фрагмент отчёта zfs-stats из системы Лукаса.


# zfs-stats -A
…
ARC Summary: (HEALTHY)
    Memory Throttle Count:      0
…
 	   

Memory Throttle Count (количество дросселирований памяти) сообщает сколько раз ваш ARC сокращался возвращая память своему ядру для её применения другим процессом. Если значение Memory Throttle Count высокое, вы можете рассмотреть уменьшение предела для размера ARC для гарантирования достаточного объёма свободной памяти для ваших других процессов. Сжатие памяти ARC не означает что система должна иметь больше памяти, тем не менее, дополнительная память будет иметь именно такой эффект.


…
ARC Size:                       36.22% 10.89 GiB
  Target Size: (Adaptive)      100.00% 30.07 GiB
  Min Size (Hard Limit):        12.50%  3.76 GiB
  Max Size (High Water):           8:1 30.07 GiB
…
 	   

Данный конкретный ARC составляет 36.22% своего максимального размера, или 10.89ГБ. Он настроен на максимальный размер 30.07ГБ. Минимум составляет 3.76ГБ.


…
ARC Size Breakdown:
  Recently Used Cache Size:    50.00%  15.03   GiB
  Frequently Used Cache Size:  50.00%  15.03   GiB
…
 	   

ARC поровну делит выделение памяти для кэшей MRU и MFU.

По сравнению с общим отчётом, отчёт об эффективности ARC, получаемый посредством zfs-stats -E представляет больший интерес. Приведём наиболее интересные фрагменты вывода другого сервера.


# zfs-stats -E
…
ARC Efficiency:               78.40m
  Cache Hit Ratio:    97.76%  76.65m
  Cache Miss Ratio:    2.24%   1.75m
  Actual Hit Ratio:   97.76%  76.65m
 	   

ZFS выделяет большие объёмы памяти для кэширования файловой системы. Верхние строки данного отчёта показывают как много преимуществ мы из этого получаем. Cache Hit Ratio (число попаданий в кэш) показывает, какое число дисковых запросов обслуживалось из ARC вместо того, чтобы обращаться к диску. В данном случае, 97.76% всех запросов чтения для данной машины было обслужено из оперативной памяти. Следующее после процентов значение является простым количеством запросов. Данный хост обслужил 76.65 миллионов дисковых запросов из ARC.

Далее, zfs-stats из какого именно кэша получались кэшированные файлы.


CACHE HITS BY CACHE LIST:
  Most Recently Used:            3.35%   2.57m
  Most Frequently Used:         96.65%  74.08m
  Most Recently Used Ghost:      0.04%  28.81k
  Most Frequently Used Ghost:    0.08%  63.26k
 	   

Кэш MRU, который имеет сходство с традиционным кэширующим буфером, обслуживает 3.35% всех полученных из ARC файлов. 96.65% всех файлов поступают из кэша MFU. Несомненно, существует некое перекрытие между этими очередями - в отсутствие кэша MFU некоторые файлы с частым доступом должны появляться в кэше MRU. Однако это прекрасная иллюстрация того, почему ARC применяет кэш MFU.

Теневые кэши (ghost) содержат списки данных, которые были недавно кэшированы, однако были отброшены из-за давления памяти или прочих ограничений. Стоит ли добавить больше памяти и увеличить размер ARC чтобы улучшить соотношение попаданий в кэш? При 0.04% и 0.08% попаданиях в теневой список добавление дополнительной памяти не должно серьёзно улучшить кэширование. ARC данного хоста заполнен только на 36%, следовательно элементы не были отселены. Эти незначительные проценты могут быть десятками тысяч запросов, однако в сравнении с миллионами запросов, обслуживаемыми кэшем, это почти ничто. Дополнительная память может усилить прочие процессы, но не ARC.

Далее мы рассмотрим типы данных, получаемых из нашего ARC.


CACHE HITS BY DATA TYPE:
  Demand Data:      97.15% 74.46m
  Prefetch Data:     0.00%      0
  Demand Metadata:   2.85%  2.19m
  Prefetch Metadata: 0.00%      0
 	   

Собственно данные являются содержимым файлов, в то время как метаданные это всё об этих файлах. Мы обсуждаем упреждающую выборку в Главе 8, однако какой бы ни была предварительная выборка, ясно, что здесь она не вступает в игру.

С обратной стороны монеты мы увидим какого сорта данные не кэшируются.


CACHE MISSES BY DATA TYPE:
  Demand Data:       31.72%  556.25k
  Prefetch Data:      0.00%        0
  Demand Metadata:   68.28%    1.20m
  Prefetch Metadata:  0.00%       19
 	   

Сколько запросов системы должно обслуживаться ARC? Это полностью зависит от рабочей нагрузки. Веб- сервер, который обслуживает одни и те же данные снова и снова ожидает высокого соотношения попадания в кэш. Ожидайте более низкого уровня соотношения попадания в кэш на серверах, на которых клиенты осуществляют доступ к большому числу различных файлов. Если ваш пул имеет терабайты данных в миллионах файлов, однако клиенты никогда не осуществляют доступ к одним и тем же файлам данных дважды, кэширование файлов в памяти не поднимет производительность.

 Модификации ARC

ARC ZFS управляет сам собой в несметном большинстве случаев. В большинстве вариантов, при которых ARC не может сам себя настроить, проблемы наилучшим образом решаются путём добавления аппаратных средств. Однако, порой регулировка памяти или производительности ZFS может потребовать от вас времени пока вы не получите и не установите оборудование. Зачастую регулировка вашего ARC является соответсвующим ответом для определённого приложения.

Вы можете тонко настраивать свой ARC установкой верхних и нижних границ используемой им памяти, а также управляя тем что, где и зачем ARC должен кэшировать.

  Ограничение размера ARC

Установка FreeBSD убирает в сторону 1ГБ оперативной памяти для ядра и работающих программ, делая возможным для ZFS поглощать всё остальное в ARC если того запросит производительность системы. Вы можете изменить это резервируя минимальный объём памяти для ARC и/или устанавливая жёсткий предел тому, как много памяти может получить ARC.

Все установки ARC задаются в байтах. Н текущий день мы управляем памятью в гигабайтах. Для установки значения для ZFS умножьте необходимое для ZFS значение гигабайт на 10243.

ARC с готовностью уступает память по запросам, однако освобождение памяти не происходит моментально. Освобождение памяти из-под ARC и её выделение другому процессу бесспорно отнимет больше времени, чем выделение свободной памяти тому же самому процессу. В хосте с очень большим ARC, сброс гигабайтов объектов из кэша может занять значительную часть секунды.

Вы можете решить ограничить объем оперативной памяти который может использовать ARC, высвобождая память для приложений. Чтобы установить это, воспользуйтесь настройкой времени загрузки vfs.zfs.arc_max. По умолчанию FreeBSD устанавливает это значение к общему объёму оперативной памяти минус 1ГБ. А мы здесь установим верхний предел в 20ГБ в boot/loader.conf.


vfs.zfs.arc_max="21474836480"
 	   

Максимальный размер ARC не является жёстким пределом, но всё- таки нечто большим чем маркер наивысшего уровня воды. Когда ARC достигает этого размера, ZFS начинает поспешно уменьшает размер своего кэша. Самые последние важные элементы добавляются к теневой (ghost) очереди и сбрасываются. Если вы будете наблюдать за размером ARC, вы сможете наблюдать использование памяти, колеблющееся вокруг vfs.zfs.arc_max при воздействии сжатия памяти на систему.

Также возможно что приложение может воспользоваться великодушием ARC против него и сжимать её наличие. Минимальный размер ARC по умолчанию составляет одну восьмую от её максимального размера. (Строго говоря, минимальный размер ARC составляет половину максимального объёма используемой в ARC метаданными памяти, который составляет четверть от максимального объёма ARC.) Для установки минимального размера ARC воспользуйтесь настройкой времени загрузки vfs.zfs.arc_min. Как и максимальный размер, минимальный размер выражается в байтах. В нашем примере я устанавливаю минимум размера ARC на размер 4ГБ в boot/loader.conf.


vfs.zfs.arc_min="4294967296"
 	   

Лукас обычно устанавливает верхние и нижние пределы размера ARC только когда он собирается объяснять как работает ARC управленцам без технического образования. "Да, PostgreSQL может применять много памяти. ARC использует оперативную память. Однако ARC только кэширует наполнение, которое вызывается PostgreSQL и PostgreSQL должен быть запущен и сделать это, следовательно нет проблем" (если вы вновь вернётесь к этому разговору, постарайтесь не добавлять: "Чёрт, как вы сможете получить свой воздух сегодня?" это никогда не завершается хорошо.)

FreeBSD 10.2 и более поздние версии могут определять какой объём памяти ARC следует попытаться оставить свободным для его использования прочими процессами, применив sysctl vfs.zfs.arc_free_target. Это значение отличается от прочих в данном разделе, поскольку оно определяется в страницах, а не в байтах. Страница составляет 4096 байт оперативной памяти, поэтому значение в 2ГБ будет выражаться как 524288 (2 * 10243 / 4096). Когда значение свободной памяти падает ниже этого значения, начинает выполняться чистильщик (reper) ядра. Чистильщик выполняет две функции: он выравнивает размер ARC чтобы гарантировать что существует достаточно свободной памяти и, кроме того, он выполняет дефрагментацию KMEM Arena. В то время когда ZFS быстро выделяет и освобождает небольшие участки памяти по мере перемещения файлов в- и из- ARC, он замусоривает ими различные участки памяти ядра. Эта память не возвращается в свободное применение поке не освободятся все выделения в arena. Это выявляет само по себе, что объём закреплённой (wired) памяти является более значимым, чем весь размер ARC плюс ожидаемые прочие закреплённые страницы, такие как ваш стек сетевой среды. В отличие от предыдущих параметров настройки, vfs.zfs.arc_free_target может выравниваться в работающей системе и иметь немедленное воздействие.

  Метаданные и ARC

Метаданные файловой системы содержат все материалы о файлах за исключением самих файлов: каталоги, полномочия, владельцев, размер, свойства и тому подобное. ARC кэширует всю эту информацию в точности как он кэширует содержимое файла. В конце концов, доступ к содержимому файла требует доступа к метаданным этого файла.

По умолчанию ARC применяет четверть максимального размера своего кэша для кэширования таких метаданных. Хотя этого почти всегда достаточно, если система имеет целую кучу мелких файлов, вам может понадобиться расширить данный предел. Настройка времени загрузки vfs.zfs.arc_meta_limit позволит вам установить особенный предел для метаданных, который может быть как больше, так и меньше заданного по умолчанию. Вот жёсткий код кэширования метаданных вашего ARC 8ГБ в boot/loader.conf


vfs.zfs.arc_meta_limit="8589934592"
 	   

Если zfs-stats -E показывает, что вы вытаскиваете из ARC намного больше данных чем метаданных, вы можете рассмотреть возможность увеличения предела метаданных и понаблюдать не улучшит ли это производительность. Помните, что по умолчанию минимальный размер ARC составляет половину от объёма, который может использоваться метаданными. К тому же, кэшированные метаданные не могут использовать пространства больше, чем весь объём ARC.

  Наборы данных и ARC

Некоторые данные имеют регулярные шаблоны доступа, что делает ARC неподходящим - ко времени, когда к файлу будет осуществлён повторный доступ, он уже израсходует все пределы по длительности в списках и в MRU, и в MFU. Это обычно происходит только когда набор данных содержит миллионы файлов и когда вы легко можете предсказывать их применение. Сообщение вашей ARC не кэшировать эти файлы освободит память для кэширования файлов, которым это может быть полезно.

Свойство ZFS primarycache определяет какая часть информации набора данных должна поступать в ARC. Значение по умолчанию, all, означает кэшировать данные файла точно также, как и метаданные.

Установка primarycache в metadata сообщает ARC кэшировать только метаданные каждого файла, а не само содержание. Вы можете найти это удобным для каталогов, которые содержат большое число файлов. Без кэширования метаданных выполнение ls(1) в большом каталоге может потребовать нескольких минут, поскольку ZFS читает диски и собирает информацию. Кэширование только метаданных запрещает упреждающее чтение, что может приносить производительности больше вреда, чем помощи от кэширования метаданных.

Установка primarycache в значение none сообщает ARC не кэшировать ничего в этом наборе данных. Вы не можете выполнять предварительное чтение без кэширования, однако если набор данных не кэшируется, производительность явно не является проблемой.

Например, сервер Лукаса имеет набор данных с многими терабайтами бесчисленного количества файлов, созданных за последние 15 лет. При крайне редком случае доступа к этим файлам, они просматриваются по порядку. Сервер даже близко не имеет достаточно памяти для эффективного кэширования содержимого всех этих файлов. Сообщение для ARC кэшировать метаданных на этом наборе данных означает что ls(1) и тому подобное всё-таки будут работать шустро, но нам не нужна бесполезная суматоха ARC этой машины.

Чтобы свойство primarycache возымело эффект, вы должны размонтировать и смонтировать набор данных для этого.


# zfs set primarycache=metadata cdr/cdr
# zfs unmount cdr/cdr
# zfs mount cdr/cdr
 	   

ARC теперь свободен для полезной работы, например, для кэширования временных файлов, создаваемых при анализе этих данных.

Процедура размонтирования удаляет всю кэшированную информацию об этом наборе данных и из ARC, и из L2ARC.

 ARC 2 уровня

ARC постоянно подрезает себя для сохранения в пределах разрешённого ему размера. Файлы, к которым продолжительное время нет обращений, выпадают из списка MRU. Обычно выпадающие из ARC элементы улетучиваются - хотя они упоминаются в теневых (ghost) списках, поэтому MFU может распознать их если они вновь появляются, система полагается на дисковую копию этого файла.

ARC 2 уровня, или L2ARC, является вторым кэшем чтения. L2ARC перехватывает выпадающие из вашего ARC элементы. При применении небольшого, быстрого диска с большим резервом перезаписи для кэширования данных ARC, вы можете одновременно уменьшить нагрузку чтения в вашем основном хранилище системы и улучшить производительность чтения. Команда zpool(8) вызывает L2ARC, устройство кэша.

Хотя L2ARC и пишет на диск, данные на нём не выдерживают перезагрузку. Хотя всё здесь и сохранено, индексы этих данных разрушены. Даже если эти индексы были доступны, пул всё же мог быть изменён на другой машине до перезагрузки системы. ZFS не может доверять информации на устройстве кэширования.

По состоянию на начало 2016г существует почти завершённая реализация устойчивого L2ARC. При наличии устойчивого L2ARC система будет перезагружать предыдущий L2ARC и загружать всё назад в оперативную память. Хотя данная функциональность может никогда не получить широкого распространения, те пользователи, которые интенсивно используют L2ARC, смогут проверить её в недалёком будущем.

Применение L2ARC стоновится существенным при наличии большого числа пользователей, виртуальных машин и приложений, имеющих доступ к одному и тому же набору данных. Если ваш рабочий набор больше чем объём памяти, который вы можете себе позволить, вашим вторым шансом будет L2ARC на базе устройства SSD или NVMe. Для большинства приложений, например, типичный NAS для домашнего применения или для предприятия, L2ARC не увеличит производительность. L2ARC может даже приносить вред производительности, потребляя оперативную память.

  Использование памяти L2ARC

Раз L2ARC содержит целую группу кэшированных данных и метаданных, индекс этих данных располагается в пределах ARC. В качестве практического метода, каждый гигабайт L2ARC требует 25МБ ARC. (Значение зависит от размера сектора диска, свойства recordsize и других характеристик набора данных, что общепризнанно делает сложным вычисление действительного размера.) Достаточно здраво предполагать полностью используемого L2ARC проглотит 25ГБ ARC.

Большинство L2ARC не находятся рядом с тарабайтом - пока, по крайней мере. SSD с достаточным циклом перезаписей чтобы сделать его удобным для кэша чтения всё ещё достаточно дорогостоящи чтобы большинство из нас имело их про запас завалявшимися. Те, кто планирует объёмные массивы хранения, скажем, из 40 дисков, должны помнить о них. {Прим. пер.: На текущий момент достаточно дискусионно: в-- первых многие производители серверов и СХД уже предлагают eMLC по цене 15k/10k шпиндельных дисков того же объёма, во-вторых, никто не мешает вам менять бытовые SSD в качестве L2ARC как перчатки - SMART даёт достаточно хорошие прогнозы.}

  Кэширование L2ARC

L2ARC может кэшировать только выпадающие из ARC данные. Данные, которые никогда не попадали в ARC не могут появиться и в L2ARC.

Предположим, вы запретили кэширование ARC для всех наборов данных в определённом пуле установив значение primarycache в none. Добавление L2ARC к этому пулу не улучшит производительность ZFS. Не существует данных, вываливающихся в L2ARC.

Вы можете решить, что его будет существенно иметь в наборе данных, для которого ARC содержит метаданные, в то время как L2ARC кэширует реальные данные файла. Набор данных cdr/cdr Лукаса с многими терабайтами из предыдущего раздела может показаться великолепным кандидатом для этого. И, раз уж он установит primarycache в metadata, он непременно увидит, что произойдёт нечто подобное


# zfs get primarycache,secondarycache zroot/cdr
NAME       PROPERTY        VALUE     SOURCE
zroot/cdr  primarycache    metadata  local
zroot/cdr  secondarycache  all       default
 	   

Проблема состоит в том, что ARC кэширует только метаданные, поэтому единственный материал, который может выталкиваться в L2ARC, это метаданные. L2ARC может содержать только то, что есть в ARC, или подмножество этого.

По умолчанию ARC кэширует все системные доступы, поэтому L2ARC делает то же самое.

Вы можете управлять тем, как каждый набор данных использует L2ARC при помощи свойства secondarycache. как и в случае с secondarycache, primarycache может быть установлен в значения all, metadata или none. Значением по умолчанию является all, что означает, что данные коорые достаточно значимы для первичного ARC будут помещаться в L2ARC.

  Потоковая обработка файлов

Большая часть времени для чтения файла расходуется на перемещение головок диска в их позицию над пластиной. Будучи позиционированными, головки читают данные просто великолепно. Это называется потоковой передачей (streaming). В большинстве систем множество дисков основного пула быстрее чем один или два диска L2ARC, поэтому при обработке больших файлов, выходящих за размеры оперативной памяти, было бы более быстрым читать их с диска. В этом случае наличие L2ARC кэша потоковой обработки файлов не имеет смысла, поэтому по умолчанию отключается.

Если у вас имеется L2ARC, который быстрее основного пула, вы можете захотеть разрешить кэширование больших файлов. Настройка времени загрузки vfs.zfs.l2arc_noprefetch управляет кэшированием потоковой обработки файлов. Значение по умолчанию, 1 запрещает кэшировать потоковую обработку файлов. Установка его значение в 0 делает возможным кэширование, как в примере с /boot/loader.conf.


vfs.zfs.l2arc_noprefetch=0
 	   

Эта подстройка имеет эффект только при импорте пула. FreeBSD импортирует пулы перед просмотром /boot/loader.conf, поэтому это значение должно быть установлено при начальной загрузке.

  Скорость записи L2ARC

SSD не так надёжны, как шпиндельные диски. Даже если вы контактируете с подготовленным поставщиком (наподобие iX Systems {Прим. пер.: или mdl.ru}), который очень искушён в ZFS и точно знает какие диски лучше применять для L2ARC, вы можете набивать SSD только ограниченное число раз перед тем как он помрёт. Хотя ZFS великолепно управляет умирающим или уже погибшим L2ARC, постоянная утрата диска дорогостояща, временеёмка и раздражающа для системного администратора. ZFS реализует множество подстроек скорости записи в L2ARC для продления срока службы диска.

Как и большинство ARC, L2ARC при своей настройке применяет байты. Большинство настроек L2ARC имеет значение в мегабайтах. Умножайте нужные вам значения на 10242.

В процессе нормальной работы ZFS пишет только 8МБ в секунду в каждое устройство L2ARC. Это позволяет избегать высасывания устройства SSD, а также помогает избегать пробуксовки кэша (Cache thrashing- запись в кэш большого количество данных, при которой кэш просто заканчивается и перезаписывается новыми данными ещё до их применения). Если вам нужен L2ARC системы для обработки больших объёмов данных, вы можете поднять его значение при помощи vfs.zfs.l2arc_write_max. Не поднимайте его настолько высоко, что сделаете чтение медленным.

При первой загрузке системы L2ARC пуст. Пустой L2ARC это не очень хорошо. ZFS выполняет после загрузки системы фазу турбо прогрева (Turbo Warmup Phase), при которой она записывает дополнительные данные в L2ARC вдобавок к пределу, определяемому vfs.zfs.l2arc_write_max. Фаза турбо прогрева продолжается пока ARC не сбросит первый элемент в L2ARC. Продолжительность времени для этого целиком зависит от системы. По умолчанию, ZFS может записывать дополнительные 8МБ на каждое устройство L2ARC в процессе фазы турбо прогрева. Выделением дополнительной полосы пропускания управляет sysctl vfs.zfs.l2arc_write_boost.

Вы можете изменить этот sysctl в любой момент. Вот пример установки обоих на 16МБ.


# sysctl vfs.zfs.l2arc_write_max=16777216
vfs.zfs.l2arc_write_max: 8388608 -> 16777216
# sysctl vfs.zfs.l2arc_write_boost=16777216
vfs.zfs.l2arc_write_boost: 8388608 -> 16777216
 	   

Безусловно, программные установки не могут превышать ограничения оборудования.

SSD уже не настолько хрупки, как это когда то было. Современные SSD уровня центра обработки данных, например, 200ГБ Intel DC S3700 имеет скорость износа (Endurance Rating) "10 записей диска в день на протяжении 5 лет". Это транслируется в примерно 2000ГБ в день, или 23МБ/с. Вы можете постоянно писать 23МБ/с на этот диск и, согласно Intel, израсходуете его в течение 5 лет. Для высокопроизводительных серверов, регулировка этого дросселирования sysctl в сторону увеличения и добавление заметки заказать новое кэширующее устройство через 58 месяце будет иметь смысл. Поскольку ваш хост вероятно не выполняет запись в L2ARC на полном газу всё время, настройка этого параметра может иметь даже больше смысла. {Прим. пер.: При разнице в стоимости eMLC и бытовых SSD на порядок, может быть не лишённой смысла и стратегия храниеия "про запас" бытового SSD диска на случай износа его предшественника с последующей дозакупкой всё уменьшающихся в стоимости новых замен.}

 Целевой журнал ZFS

Кэш предназначен не только для чтения данных. ZFS применяет кэширование также и для записей, применяя целевой журнал ZFS (ZIL, ZFS Intent Log). ZFS сбрасывает записи в ZIL, а затем обрабатывает эти записи, добавляя их соответствующим образом в ZFS. Каждый пул имеет свой собственный ZIL. При обычном применении ZFS использует порции пространства каждого поставщика для соответствующего ZIL. По вашему желанию вы можете добавить дополнительное устройство для его применения в качестве ZIL. Строго говоря, ваш ZIL в точности не является кэшем записи. Однако, он является видом кэширования и поэтому мы обсудим его в данной главе.

Однако, ZIL не рабботает таким образом, как предполагает большинство люей. Чтобы понимать когда пулу требуется отделять журналирующее устройство, а когда нет, вы должны понимать как ZFS осуществляет запись данных.

  Синхронные и асинхронные транзакции

ZFS целиком посвящена целостности данных, которые достигают постоянного хранилища. Данные на диске всегда должны быть согласованы. Система может потерять данные в промежутке между программой и диском, но никакая файловая система не может защитить данные в полёте, расположенные только в оперативной памяти.

Чтобы обеспечить целостность на диске ZFS группирует запросы на запись в группы транзакции (txgs, transaction groups). Группа транзакций является порцией данных и связанных с файловой системой метаданных. Когда вы просите свою систему выполнить запись на диск, ZFS собирает такие запросы в группу транзакции. Одна группа транзакции может содержать подобные запросы на запись от многих несвязанных процессов. Когда группа собирает достаточно данных, или истекает установленный промежуток времени, эта группа транзакции записывается на соответствующий диск. Подобный предустановленный интервал времени может быть длительным и составлять 30 секунд, или быть короче, 5 секунд, в зависимости от того, какую редакцию FreeBSD вы выполняете.

Группа транзакции является списком что-делать. В точности как ваш список дел, если не случится ничего ужасного, продерётся сквозь волков. (Волки, конечно не интересуются бумажными списками. Чтобы эта метафора работала хорошо, мы представляем что вы пишите свои списки дел на жареных отбивных). Данные чувствительны к отказам системы пока они не записаны целиком на диск. В случае отказа системы или её кончины до выполнения записи группы транзакции на диск, эти данные будут утрачены. Уменьшение таймаута группы транзакции может уменьшить объём теряемых данных, но это также плохо влияет на производительность.

Так как вы- системный администратор, это именно ваша работа управлять риском потери данных. Давайте пройдёмся по записи данных на диск.

Программа передаёт ядру порцию данных и просит: "Пожалуйста, запиши это на диск." Программа не выполняется пока ядро не выдаст подтвердит приём данных. Если уж ядро скжет, "Я получило данные," программа продолжит своё выполнение. Ожидание программой этого отклика называется блокировкой по вводу/ выводу (blocking on I/O).

Важный вопрос стсотит в том, когда именно ядро подтвержает приём этих данных? Когда данные добавлены в группу транзакции, или когда они записаны на диск?

При нормальной работе ядро подтверждает данные, когда эти данные находятся в памяти как часть незавершённой группы транзакции. Эти данные не находятся на диске - ваше ядро просто берёт на себя ответственность за данные. Если бы ваша система была рестораном, обед сейчас должен был бы находится в руках официанта на пути к клиенту, однако официант ещё может идти. Варианты асинхронных операций являются распространёнными в современных файловых системах, например, в различных версиях etfs Linux и UFS BSD.

Кроме того, файловая система может работать в синхронном режиме, при котором подтверждение данных от ядра происходит только тогда, когда биты реально записываются на физический носитель хранения. Синхронное монтирование очень надёжное, однако также и чрезвычайно медленное. Записывающая данные программа будет блокирована ожиданием пока физическое оборудование не предоставит ответ на запрос записи ядром. Определённые програмы, например серверы баз данных, запрашивают синхронное подтверждение для определённых файлов применяя вызов системы fsync(2). Системный администратор может монтировать набор данных синхронным, таким образом система получит подтверждение только когда запись данных выполнена, или могут применять программу fsync(2) для сообщения системе о необходимости сброса всего на диск прямо сейчас.

  Целевой журнал ZFS

Когда ZFS записывает в синхронном режиме, она не выталкивает немедленно группу транзакции на диск. Вместо этог, такие записи сбрасываются в ZIL. Они не являются аккуратными запрошенными блоками наборов данных ZFS; вместо этого ни просто являются кучей блоков на вашем диске. Как только группа транзакций записана на диск, блоки в ZIL записываются на свои соответствующие местоположения.

Процесс импорта пула проверяет ZIL на наличие данных, которые ещё не достигли конечного дома. Если система находит блоки в полёте в импорте пула, она выполняет эти транзакции.

Обычно пул использует небольшие порции пространства на каждом поставщике в качестве ZIL. Да, это означает что каждая синхронная запись должна быть выполнена на физическом устройстве хранения дважды. Однако пул применяет ZIL только синхронно- записываемых данных. Обычно асинхронные записи сохраняются в оперативной памяти и фиксируются как часть регулярной группы транзакции.

Иногда вы можете улчшить производительность, помещая ZIL на выделенное, быстрое устройство, называемое отдельным целевым журналом (Separate Intent LOG).

  Отдельный целевой журнал ZFS

Вы можете выделить из пула применяя отдельный целевой журнал (Separate Intent Log), или SLOG. Перемещая ZIL на отдельное, выделенное оборудование, вы избегаете выполнение записи одних и тех же данных дважды на одного поставщика хранения. Если оборудование SLOG быстрее чем ваш пул, ядро может выдать подтверждение данных намного быстрее, улучшая производительность выполняющего запрос приложения.

Вопреки обычному применению, SLOG не является тем же предметом, что и ZIL. SLOG является аппаратными средствами. ZIL же функционирует либо в SLOG, либо на поставщике хранения. Вы можете запустить SLOG в окне, но ругать вы можете только ZIL.

Самым быстрым, наиболее надёжным, но и самым затратным SLOG является микросхема NVRAM. Наболее часто применяемыми являются SSD с большим количеством перезаписей {Прим. пер.: eMLC}. Вы даже можете применять очень быстрые диски SAS, однако они менее надёжные. {Прим. пер.: сомнительное утверждение. Более существенны действующие в настоящее время программы у многих производителей оборудования предложения этих типов устройств одного объёма по одной цене.}. Для каждого из таких устройств необходим собственный источник питания, например, батарея или суперконденсатор, чтобы позволить им завершить запись в случае отказа питания системы.

SLOG не должен быть очень большим sysctl vfs.zfs.dirty_data_max устанавливает максимально возможный объём данных на лету. Значением по умолчанию ZFS FreeBSD 10 состоит в применении ZIL с размером, равным одной десятой оперативной памяти системы. Вы можете применять одно устройство соотвествующего оборудования для поддержки поставщиков SLOG более чем для одного пула, однако это также расщепляет ввод/ вывод данного устройства между такими пулами. Одна из причин для применения SLOG состоит в том, чтиобы справиться с нехваткой ввода/ вывода.

Не все SSD или NVRAM создаются одинаковыми. Многие устройства маркируемые как "долгоиграющие" (high endurance), не являются достаточно надёжными для обработки всех записей даже в пулах среднего размера. Для приложений, для которых целостность данных жизненно необходима, авторы настоятельно рекомендуют вам консультироваться с поставщиком аппаратных средств, специализирующемся в ZFS, например, IX Systems (http://www.ixsystems.com) {Прим. пер.: или mdl.ru}. Надлежащим образом выбранный SLOG может чрезвычайно ускорить ваши программы, в то время как плохой выбор может разрушить ваш пул.

  Настройка целевого журнала по наборам данных

Вы не можете управлять тем, как (или если) набор данных применяет ZIL при установленном свойстве sync. Во много по аналогии с монтированием обычной файловой системы sync или async, свойство sync предписывает набору данных стоит ли набору данных воспринимать запросы fsync(2).

Установка по умолчанию, standard, сообщает набору данных применять ZIL для запросов синхронизации. Если программа использует fsync(2) для запроса, который ядро не подтвердит, пока данные не сохранятся на диске, данные записываются в ZIL. Все прочие данные записываются асинхронно как часть группы транзакции. Это значение по умолчанию.

Установка sync в значение always пересылает все значения в соответствующий ZIL. Никакие записи не являются асинхронными. Это самый надёжный способо управления данными, однако он имеет существенные отрицательные последствия в производительности. Вы можете выбрать установку этого свойства на наборе данных, выделенном для критически важных данных.

Установка sync в значение disabled полностью запрещает применение ZIL на этом наборе данных. Все записи являются асинхронными. Система врёт всем программам что применяет fsync(2). Никогда, никогда не запрещайте свои ZIL на каком- либо наборе данных, используемом для баз данных или NFS {Прим. пер.: а также Samba и прочих совместно используемых ресурсах!}. В действительности, единственная причина запретить ZIL на наборе данных состоит в том, чтобы проверить что ZIL не вызывает проблем с производительностью у вашего определённого приложения. Если запрет вашего ZIL устраняет проблему приложения, несомненно зарегистрируйте сообщение об ошибке или установите быстрое устройство SLOG.

Практически во всех случаях оставляйте sync в значение standard У вас может быть один или два набора данных которым нужен sync, установленный в значение always.

  Выполнение синхронных записей в стеке

ZFS в конечном итоге выступает в какчестве основы хранения данных для многих различных приложений, например, таких как Network File System (NFS) и iSCSI. Вы можете применять zvol для виртуальных дисков системы. Все эти различные уровни работают независимо. Хотя они и могут общаться друг с другом посредством общих системных вызовов и API, они не могут управлять друг другом. Каждый уровень стека приложений может (и занимается этим регулярно) врёт прочим уровням. И нигде более это не так очевидно и не так наиболее опасно, как в системном вызове fsync(2).

Предположим, у вас есть виртуальная машина, которая работает с неким диском iSCSI, в основе которого лежит zvol вашего сервера. Операционная система виртуальной машины запрашивает синхронную запись на диск. Стек iSCSI берёт этот запрос и передаёт его ZFS. Если вы установили sync в значение disabled на этом zvol, ZFS сдавленно хихикает, приговаривая "Синхронно? Конечно! Ты поимеешь это, дружище!", и продолжает делать что-нибудь до следующей txg.

Вы можете установить sync в значение always на этом zvol, принимая провал производительности во имя целостности данных. Однако если данный стек iSCSI запрещает выполнение синхронных записей, вы получите провал без каких бы то ни было преимуществ. Любой уровень сложного стека приложений может запретить выполнение синхронных записей.

Если целостность данных важна, убедитесь что синхронная запись работает во всём стеке приложений.

 zpool.cache

Теперь давайте обсудим кэш, о котором вы будете слышать, но который не влияет на ежедневное системное администрирование: файл /boot/zfs/zpool.cache.

Файл zpool.cache содержит описание текущего активного пула и его поставщиков. Когда вы загружаете систему ZFS, ядро проверяет в корне вашего пула файл zpool.cache для обнаружения того, какие системные пулы оно должно импортировать.

Файл zdb(8) использует информацию в файле кэша для отладки. Вы не можете использовать отладчик в пуле без кэша.

Вы можете управлять местоположением файла кэша при помощи свойства cachefile. Вот мы изменяем файл кэша для вашего пула work.


# zpool set cachefile=/work/zfs/work.zpool.cache work
 	   

Несмотря на большую давность и всё- таки устаревающую документацию, почти никогда нет причины изменять местоположение файла кэша современной ZFS в FreeBSD.

Теперь, когда вы приобрели навыки кэширования, мы можем обсуждать производительность.

l>