Глава 8. Производительность

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

FreeBSD содержит инструментальные средства для проверки производительности и обычных дисков и файловой системы, а также специальные инструменты ZFS. Подробную информацию вы можете получить в sysctl(8), vmstat(8) и связанных с ними командами, однако мы настоятельно рекомендуем установить дополнительный пакет zfs-stats для разбора и обработки информации надлежащим образом.

Когда вы разберётесь как оценивать производительность системы, мы обсудим некоторые свойства производительности ZFS и то, когда они могут быть полезны.

Перед погружением в оценку производительности ZFS давайте немного поговорим о производительности в общем.

 Что такое производительность?

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

Системный администратор в основном заботится об улучшении производительности. Это означает обнаружение и удаление узких мест. Среднестатистический компьютер имеет четыре основных ресурса: ввод/ вывод системы хранения, пропускная способность сетевой среды, оперативная память и ЦПУ. Если вы наваливаете работу в систему до тех пор, когда она уже не может справляться, первое то что вы в действительности делаете, это определение того, какой именно из этих четырёх ресурсов отказывает первым. Этот ресурс является бутылочным горлышком.

Увеличение производительности требует идентификации и перемещения этого узкого места. И вы всегда сталкиваетесь со следующим узким местом. Если ваш процессор является текущим бутылочным горлышком и вы добавили вычислительную мощность, скорость вычислений растёт, пока не происходит насыщения дискового ввода/ вывода, или памяти, или сети. Вы улучшили производительность, да ... до пределов разрешённых новым узким местом.

Причём различные рабочие нагрузки могут иметь совершенно различные узкие места.

Многим системным администраторам необходима замена одного из этих ресурсов на другой. Именно поэтому Лукас всегда называет "настройку системы" "перенастройкой узких мест". (Лукас многие вещи называет перестановкой бутылочных горлышек. Он решает проблему "грязной одежды" личным временем и моющими средствами. Пока вы читаете это, он почти наверняка страдает от узкого места с мороженным.)

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

Чем сложнее ваша система хранения, тем больше возможностей у вас для регулировки и смещения узких мест. Ваш сервер имеет шесть дисковых контроллеров, но весь ввод/ вывод приходит только на один из них? Перегруппируйте ваши наборы данных чтобы разделить нагрузку между множеством контроллеров. Может быть определённый диск перенасыщен? Разделите эту нагрузку. Возможно, ваш пул перегружен операциями записи, или чтения, или и тем и другим. Добавление настроенных надлежащим образом SLOG и L2ARC помогут.

Перед тем как выполнить изменения, однако, исследуйте где находится узкое место. Приобретение более быстрого диска для системы не поможет вашим конкретным системным ограничениям ЦПУ или памяти. Добавление быстрого SSD для ZIL не улучшит производительность если дисковые чтения дросселируют производительность сервера.

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

Если производительность не отвечает вашим ожиданиям, помните, что ваша система хранения работает настолько хорошо, как это ей позволяет самый её медленный компонент. {Прим. пер.: см. 1-ый Закон Амдала: "Производительность вычислительной системы, состоящей из связанных между собой устройств, в общем случае определяется самым непроизводительным её устройством", В.В.Воеводин "Вычислительная математика и структура алгоритмов.", МГУ, 2006, ISBN 5-211-05310-9} У вас может быть на самом деле быстрый контроллер SAS и самый новый, высокоскоростной жёсткий диск, но при этом ужасная производительность из- за поганых дисковых кабелей. Умножитель SATA портов разрубает производительность пропорционально числу подключённых дисков. Просто потому, что вы можете соединить определённые компоненты вместе, не означает что это следует делать.

 ZFS и производительность

Основная часть рекомендаций по настройке производительности хранения относится к ZFS, как это обычно и бывает с любой другой файловой системой. Если у вас нет потребности в знании последнего доступа к файлу, запретите запись времени доступа в свойстве atime.

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

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

Если консультация обычного системного администратора по улучшению производительности файловой системы не помогает решить ваши проблемы, вы должны углубиться в неё и найти почему ваша система ведёт себя плохо. Каждая операционная система содержит инструменты для измерения производительности. vmstat(8) может быстро определить то, что вашей системе требуется процессор, дисковое пространство или оперативная память.

Для более подробного наблюдения за производительностью ваших пулов применяйте zpool iostat.

 zpool iostat

Компонента zpool, iostat, предоставляет снимок того какова производительность ваших пулов в определённый момент времени. Для просмотра средней активности ваших пулов с момента загрузки системы выполните zpool iostat.


# zpool iostat
          capacity     operations bandwidth
pool   alloc   free   read  write   read  write
-----  -----  -----  -----  -----  -----  -----
work   2.21G  1.81T      2    402  36.2K  24.0M
zroot  15.5G   905G    275      0  7.34M      0
 	   

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

Данный пример показывает два пула, work и zroot. Пул zroot имеет выделенными 15.5ГБ и 905ГБ свободными. Пул выполняет 275 операций чтения в секунду или 7.34МБ в секунду и никаких операций записи. Это означает, что каждая операция чтения в среднем составляет 27кБ (7.34МБ / 275 = 27кБ).

Пул work более интересен. У нас имеется два запроса на чтение в секунду при 402 записях в секунду с общими 24МБ/с. Чтения незначительны, однако каждая запись в среднем составляет 60кБ. Вся реальная работа происходит здесь.

Что это означает для вашего пула? Само по себе не очень много. Это активность пула в определённый момент времени. Это может быть средним значением во времени, или может быть высоким или низким в определённый период. Для принятия существенных решений вам нужен непрерывный обзор деятельности пула.

Для наблюдения за активностью отдельного пула определите имя пула.


# zpool iostat work
 	   

Это прекратит весь вывод за исключением вывода данных для определённого пула.

Имейте в виду, это средние значения с момента загрузки. Они не отражают текущее значение.

  Текущая и продолжительная активность пула

Чтобы увидеть как ведёт себя пул в определённый момент времени, и как активность меняется со временем, заставьте zpool iostat выводить новые данные статистики каждые несколько секунд. Определите число секунд в конце командной строки. В нашем примере мы выполняем обновления каждые две секунды. Для выхода нажмите CTRL-C.


# zpool iostat 2
          capacity     operations      bandwidth
pool   alloc   free   read  write    read  write
-----  -----  -----  -----  -----   -----  -----
work   3.37G  1.81T     14    107    146K   900K
zroot  15.5G   905G      3      2   32.9K  12.7K
-----  -----  -----  -----  -----   -----  -----
work   3.37G  1.81T      0      0       0      0
zroot  15.5G   905G      0      0       0      0
-----  -----  -----  -----  -----   -----  -----
 	   

Первая запись является средним значением активности с момента загрузки, в точности, как это было при выполнении zpool iostat без интервала. Вторая и последующие записи выдают ткущие значения.

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

Если вы определите отдельный пул, zpool iostat отбросит разделители. Приведём то, что мы видим для пула work.


# zpool iostat work 2
          capacity     operations      bandwidth
pool   alloc   free   read  write    read  write
-----  -----  -----  -----  -----   -----  -----
work   3.35G  1.81T     15    104    148K   897K
work   3.35G  1.81T      0    616   2.25K  3.74M
work   3.35G  1.81T      1    553   5.74K  2.78M
work   3.36G  1.81T      1    607   21.0K  2.57M
 	   

Данный пул в среднем выполняет 104 операции записи в секунду, однако в данный момент он выполняет более 600 операций в секунду. Он выполняет реальную работу!

  Активность виртуального устройства

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

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

Для обзора активности по VDEV для каждого пула добавьте флаг -v после iostat.

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


# zpool iostat -v work
               capacity     operations      bandwidth
pool        alloc   free   read  write    read  write
----------  -----  -----  -----  -----   -----  -----
work        2.13G  1.81T     10     87    100K   715K
 mirror     1.06G   927G      5     43   50.9K   359K
  gpt/zfs0      -      -      2      8   26.4K   360K
  gpt/zfs1      -      -      2      8   26.6K   360K
 mirror     1.07G   927G      4     43   49.6K   356K
  gpt/zfs2      -      -      2      8   25.0K   357K
  gpt/zfs3      -      -      2      8   26.4K   357K
----------  -----  -----  -----  -----   -----  -----
 	   

Вы получаете значения итого для всего пула, итого для каждого VDEV в этом пуле, и число для каждого поставщика в этом пуле. Взглянем на значения операций записи в секунду для данного пула. Пул в целом в среднем имеет 10 операций чтения в секунду с момента загрузки системы. Первое зеркальное устройство отвечает за пять из них, а второе за четыре. Каждый диск внутри каждого виртуального устройства обрабатывает по два чтения в секунду. (Это усреднённые значения, поэтому пусть факт, что ZFS полагает что 2 + 2 = 5, не смущает вас. Функции контрольных сумм ZFS выполняют математические операции более корректно.)

Работа записи с очевидностью выглядит странно. Начальные данные ZFS показывают, что этот пул ZFS в среднем выполняет 87 запросов на запись в секунду, причём на каждый пул приходится по 43. Это неплохо - однако, значения из расчёта на диск отображают, что каждый диск в среднем выполняет восемь запросов на запись в секунду. Вне зависимости от того насколько абсурдно вы округляете эти значения, они даже рядом не ложатся.

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

Как и в случае с zpool iostat без детализации, для просмотра текущих значений вы должны определить интервал в конце своей командной строки. В примере мы отображаем активность по устройствам в нашем пуле work, обновляемую каждые две секунды.


# zpool iostat -v work 2
               capacity     operations      bandwidth
pool        alloc   free   read  write    read  write
----------  -----  -----  -----  -----   -----  -----
work        2.13G  1.81T      0     69       0   147K
 mirror     1.15G   927G      0     40       0  93.6K
  gpt/zfs0      -      -      0     10       0  94.9K
  gpt/zfs1      -      -      0     10       0  94.9K
 mirror     1.16G   927G      0     28       0  53.3K
  gpt/zfs2      -      -      0      6       0  54.6K
  gpt/zfs3      -      -      0      6       0  54.6K
----------  -----  -----  -----  -----   -----  -----
 	   

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

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

 Упреждающая выборка ZFS

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

  Упреждающая выборка на основе VDEV

Большую часть потребления времени при получении данных со шпиндельных дисков составляет позиционирование головок над дорожками, содержащими данные. Это аналогично приготовлению сандвича - плюхнуть арахисовое масло между двумя ломтиками хлеба занимает пару минут, а поход в магазин для покупки хлеба и арахисового масла может занять час. Когда оборудование физически настроилось, чтение полной дорожки данных диска раскрученного на 5000 или 10000 оборотом в минуту занимает микросекунды.

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

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

Предварительно выбранные блоки на основе VDEV поступают в простой карусельный кэш с замещением наиболее давно использованных данных (Least Recently Used cache), не в ARC. Если блоки никогда не вызываются, они быстро высвобождаются. Размер кэша VDEV равен числу поставщиков в VDEV, умноженному на настраиваемый vfs.zfs.vdev.cache.size. FreeBSD устанавливает этот параметр по умолчанию в значение 0, поэтому кэш не используется. Сделайте кэширование доступным, установив эти настраиваемые на необходимое значение в /boot/loader.conf. Обычное значение равно 10МБ


vfs.zfs.vdev.cache.size="10M"
 	   

После перезагрузки у вас имеется работающий кэш предварительной выборки на основе VDEV.

sysctl kstat.zfs.misc.vdev_cache_stats.misses показывает сколько раз ZFS проверял кэш на основе VDEV на наличие метаданных и не находил их. Аналогично sysctl kstat.zfs.misc.vdev_cache_stats.hits показывает как часто ZFS находил что- то в этом кэше.

Проверьте вашу рабочую нагрузку с упреждающим кэшированием и без него и посмотрите на её поведение.

Насколько упреждающее чтение на основе VDEV приоритезирует кэш? sysctl vfs.zfs.vdev.cache.max даёт минимальный размер чтения из VDEV. Это значение по умолчанию равно 16384, или 16кБ. Если программа запрашивает чтение меньше этого размера, вносится предварительная выборка на основе VDEV.

Однако, чтение не просто расширяется до 16кБ. sysctl vfs.zfs.vdev.cache.bshift даёт объём для данных предварительной выборки и искомых метаданных. Оно слегка смещает значение, поэтому значение по умолчанию 16 означает 64кБ.

Таким образом, если программы запрашивают чтение менее 16кБ, ZFS читает вместо этого 64кБ. Если программа запрашивает на чтение, скажем, 20кБ, не происходит предварительной выборки на основе VDEV.

Хотя изменение значений предварительной выборки помогало производительности в некоторых старых версиях ZFS, в современной ZFS вам следует почти всегда оставлять всё как есть. Авторы не встречали никаких ситуаций, в которых изменение этих значений помогало, но мы знаем много случаев, когда изменение этих значений приносило страдание.

  Пофайловая упреждающая выборка

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

Упреждающая пофайловая выборка увеличивает размер ARC. FreeBSD автоматически запрещает предварительную выборку в хостах с оперативной памятью менее 4ГБ и автоматически делает её доступной в хостах с 4ГБ или более. Вы можете переопределить эту установку переключив vfs.zfs.prefetch_disable в значение 1 в /boot/loader.conf.

Упреждающая выборка может вызывать проблемы в системах, которые размещают сотни тысяч (или более) мелких файлов, например, в 64кБ и менее. Для таких хостов вы можете захотеть запретить предварительную выборку на уровне файлов. Подобные системы, однако, крайне редки.

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

 Настройка групп транзакций

Вы можете настраивать производительность выравнивая группы транзакций и ваших расписаний ввода/ вывода. Мы намеренно охватываем настройки FreeBSD 10 и более поздних версий. Механизмы для настройки OpenZFS описываемые в более ранних версиях были значительно более причудливы.

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

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

  Времена txg

Если ничто больше не переключает запись txg на диск, ZFS выполняет запись каждые несколько секунд, как это определено в sysctl vfs.zfs.txg.timeout. Хотя значение этого параметра крутится вокруг слегка более ранних версий OpenZFS, текущий стандарт состоит в пяти секундах. В худшем случае сброс данных осуществляется на диск каждые пять секунд.

Для большинства систем запись каждые пять секунд является достаточной. Программа навроде top(1) может показать всплеск активности ЦПУ каждые пять секунд при осуществлении сжатия ожидающей разрешения группы транзакций. Вам редко требуется уменьшать ваш таймаут до менее чем пяти секунд.

Увеличение этого значения, однако, может быть ощутимым для некоторых систем. Если вы выполняете ZFS на низконагруженной виртуальной машине, вы можете завести таймаут txg вверх на 15 или более. Лукас часто исполняет хосты в качестве зеркал LDAP и заслуживающих доверия серверов DNS на виртуальных машинах, и подобные виды хостов редко имеют высокие уровни запроса к дисковому вводу/ выводу. Уменьшение частоты записей транзакций не улучшит производительность такой определённой виртуальной машины, однако улучшит доступ к оборудованию для остальных ВМ, работающих с этим гипервизором. Задание всем виртуальным машинам на таком хосте аналогичных низких установок улучшит производительность для виртуальных машин по всему совету, однако отдельная самолюбивая или высокозагруженная ВМ может съесть большую часть такой выгоды. (Однако, это может быть в точности тем, что вы хотите получить.)

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

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

Установка таймаута группы транзакций в значение менее пяти секунд столкнётся с проблемой вашего расписания ввода/ вывода и ограничит вашу запись. Для большинства из нас пять секунд являются минимально ощутимым значением.

  Размер txg

Достаточно быстро растущая txg получает фиксацию на диск до истечения таймаута. FreeBSD автоматически настраивает максимальный размер группы транзакции во время загрузки на основе объёма памяти в вашем хосте и настраиваемого vfs.zfs.dirty_data_max_percent. Значение по умолчанию 10 (вы можете изменить vfs.zfs.dirty_data_max_percent после загрузки, это не будет иметь последствий для производительности, но вы можете изменить это значение), устанавливает максимум до 4 ГБ и управляется vfs.zfs.dirty_data_max_max. Если группа транзакции использует 10 процентов оперативной памяти системы, она записывается на диск.

Вы можете изменить максимальный размер группы транзакции после загрузки при помощи vfs.zfs.dirty_data_max_max. Это значение задаётся в байтах, поэтому умножайте нужное вам число гигабайт на 10243 для получения надлежащего значения sysctl.

Трудный вопрос: должны ли вы менять размер группы транзакции? Сколько времени потребуется вашей системе записывать 10 процентов оперативной памяти на диск и как часто это будет происходить? Большинство хостов имеет намного больше оперативной памяти, чем у них имеется пропускной способности ввода/ вывода. Попытка записать на диск одну десятую от объёма оперативной памяти за пять секунд может повлечь катастрофу. Пробный хост Лукаса имеет несколько жёстких дисков в одном пуле и 32ГБ оперативной памяти. Запись 3.2ГБ на диск требует более 20 секунд. Если такой хост вырабатывает 3.2ГБ дисковой активности в промежуток времени менее чем стандартный пятисекундный таймаут txg, машина быстро свалится в штопор недоступности.

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

В процессе таких "циклов записи", большинство чтений с диска временно приостанавливается. Это делает возможным завершать запись настолько быстро, насколько это возможно. Чтение возобновляется по завершению записи. Подобное "перекрытие" рабочей нагрузки обычно увеличивает производительность. Используя знания о вашей рабочей нагрузке, вы можете принять решение о том, что лучшим подходом будет менее частый сброс более крупных групп транзакции более частый менее крупных. При массовом копировании данных внутри одного и того же пула Джуд увеличивает размер своей txg до 25 ГБ, а таймаут до 30 секунд, и получает прирост производительности в 25 процентов.

  Длительность и содержание txg

Если вы пытаетесь настраивать размер и периодичность своих групп транзакции, это делает существенным вопрос насколько велики ваши группы транзакции и как долго осуществляется их фиксация на диск. Адам Левинталь создал некий сценарий DTrace, полезный для замеров обоих показателей, доступны по ссылке http://dtrace.org/blogs/ahl/2014/08/31/openzfs-tuning/ или на http://zfsbook.com. Мы обсудим оба.

Чтобы измерять объём данных каждой txg, воспользуйтесь сценарием Левенталя dirty.d (&Грязные данные& - Dirty data- находятся в оперативной памяти, ожидая записи на диск.)


txg-syncing
{
this->dp = (dsl_pool_t *)arg0;
}
txg-syncing
/this->dp->dp_spa->spa_name == $$1/
{
printf("%4dMB of %4dMB used", this->dp->dp_dirty_total / 1024 / 1024, `zfs_dirty_data_max / 1024 / 1024);
}
 	   

Выполните этот сценарий задав своё имя пула в качестве аргумента.


# dtrace -s dirty.d zroot
dtrace: script ‘dirty.d’ matched 2 probes
CPU     ID  FUNCTION:NAME
  3  61042   :txg-syncing  2MB of 6539MB used
  1  61042   :txg-syncing  7MB of 6539MB used
  4  61042   :txg-syncing  5MB of 6539MB used
…
 	   

DTrace выводит размер каждой txg, а также размер вашего ARC при каждой записи ZFS вашей txg на диск. Если вы измените интервал между группами транзакции при помощи vfs.zfs.txg.timeout sysctl, вы увидите изменение размера ваших групп транзакции.

duration.d Левенталя показывает сколько времени выполняется каждая группа транзакции.


txg-syncing
/((dsl_pool_t *)arg0)->dp_spa->spa_name == $$1/
{
start = timestamp;
}
txg-synced
/start && ((dsl_pool_t *)arg0)->dp_spa->spa_name == $$1/
{
this->d = timestamp - start;
printf("sync took %d.%02d seconds", this->d / 1000000000,
this->d / 10000000 % 100);
}
 	   

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


# dtrace -s duration.d zroot
dtrace: script ‘duration.d’ matched 2 probes
CPU     ID  FUNCTION:NAME
  1  61043    :txg-synced sync took 0.11 seconds
  2  61043    :txg-synced sync took 0.24 seconds
  4  61043    :txg-synced sync took 0.22 seconds
  2  61043    :txg-synced sync took 0.31 seconds
 	   

Пренебрегая нашими усилиями, ZFS не работает очень напряжённо в данной системе.

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

Раз вы подвешиваете их, Джуд создал сценарий, который измеряет оба параметра одновременно.


#!/usr/sbin/dtrace -s
txg-syncing
/((dsl_pool_t *)arg0)>dp_spa>spa_name == $$1/
{
start = timestamp;
this->dp = (dsl_pool_t *)arg0;
d_total = this->dp->dp_dirty_total;
d_max = `zfs_dirty_data_max`;
}
txg-synced
/start && ((dsl_pool_t *)arg0)>dp_spa>spa_name == $$1/
{
this->d = timestamp - start;
printf("%4dMB of %4dMB synced in %d.%02d seconds",
d_total / 1024 / 1024,
d_max / 1024 / 1024, this->d / 1000000000,
this->d / 10000000 % 100);
}
 	   

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

  Ограничение записи

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

В более старых версиях ZFS ограничение записи приводило к очень неравномерной производительности. Алгоритм дросселирования в FreeBSD 10 и более новых версиях работает более гладко. Вы можете настраивать его посредством планировщика ввода/ вывода, обсуждаемого далее.

 Планирование ввода/вывода

Не всё оборудование создаётся одинаковым. Самый современный ноутбук Джуда имеет намного меньшую способность ввода/ вывода чем любой из его серверов сетевой среды предоставления контента. Установки по умолчанию FreeBSD достаточно общие. Хотя вам на самом деле не нужно настраивать их на ноутбуке, тем не менее, если у вас есть десятки или сотни дисков с очень особенными рабочими нагрузками, вы можете регулировать производительность посредством настройки своего планирования. Планирование ввода/ вывода позволяет вам выравнивать латентность и пропускную способность.

Пропускная способность является объёмом данных, которое может быть считано с- или записано на- устройство хранения. Когда вы говорите что SATA-3 может передавать данные со скоростью 6Гбит/c, вы имеете в виду пропускную способность.

Латентность является промежутком времени, который необходим системе для обработки таких запросов. Сложные системы хранения, с шинами Fiber Channel и большим числом полок во многих частях вашего здания, могут вызывать задержки по мере прохождения запроса в системе. Ваш ноутбук скорее всего будет иметь латентность хранилища при перегруженности вашего жёсткого диска одновременным копированием слишком большого количества файлов.

Несмотря на то, что жёсткие диски продаются с описанием того, сколько операций ввода/ вывода они могут выполнять в секунду (IOPS), это не является настолько полезной информацией, как вы можете предполагать. Способность выполнять 250 IOPS тщательно выбранных данных ничего не говорит о способности выполнять это с вашими данными.

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

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

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

Планирование ZFS строится вокруг очередей ввода/ вывода.

  Измерение латентности и пропускной способности

Как вы узнаете что изменение положительно влияет на производительность системы?

Вы измеряете её. Адам Левенталь написал сценарий DTrace измерения латентности и пропускной способности для illumos, но мы приведём изменённую версию для FreeBSD.


#pragma D option quiet
inline uint32_t BIO_READ = 1;
inline uint32_t BIO_WRITE = 2;
this uint64_t delta;
BEGIN
{
start = timestamp;
}
io:::start
/ args[0] /
{
ts[args[0]] = timestamp;
}
io:::done
/args[0] && ts[args[0]]/
{
this->delta = (timestamp - ts[args[0]]) / 1000;
this->name = (args[0]->bio_cmd & (BIO_READ | \
BIO_WRITE)) == BIO_READ ?
"read " : "write ";
@q[this->name] = quantize(this->delta);
@a[this->name] = avg(this->delta);
@v[this->name] = stddev(this->delta);
@i[this->name] = count();
@b[this->name] = sum(args[0]->bio_bcount);
ts[args[0]] = 0;
}
END
{
printa(@q);
normalize(@i, (timestamp - start) / 1000000000);
normalize(@b, (timestamp - start) / 1000000000 * 1024);
printf("%-30s %11s %11s %11s %11s\n", "", \
"avg latency", "stddev", "iops", "throughput");
printa("%-30s %@9uus %@9uus %@9u/s %@8uk/s\n", @a, \
@v, @i, @b);
}
 	   

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


# dtrace -s rw.d -c ‘sleep 30’
 	   

Команда sleep(1) сообщает вашему сценарию как долго продолжать сбор данных. Сценарий rw.d наблюдает за пропускной способностью и латентностью это количество секунд, а затем выводит две диаграммы производительности для чтения и записи. По окончанию вы получите примерно это:


…
      avg latency  stddev  iops  throughput
write      1362us  8378us  68/s     4620k/s
read       6943us  5839us   2/s       46k/s
 	   

Говоря в общем, цель настройки производительности состоит в улучшении значений, о которых вы заботитесь, и при этом не сделать остальные значения слишком большими. Поупражняйтесь с максимальным значением разрешённых чтений и записей каждого типа, увеличивайте их по 20-100 процентов между исполнениями теста. Убедитесь что вы не задрали эти значения настолько высоко, чо ваш VDEV выйдет за пределы ограничения на VDEV - или, наоборот, поупражняйтесь с их минимальными значениями.

Колонка stddev (стандартное отклонение, standard deviation) заслуживает особенного внимания. Вы можете получиь исключительную пропускную способность, однако оказаться с очень большим разбросом задержек. Будет ли допустимой массивная пропускная способность если некоторые чтения и записи потребуют для выполнения пяти секунд? Об этом знаете только вы.

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

Да, настройка и тестирование производительности утомительны. Это та причина, по которой большинство людей не заботятся о них. Однако хорошая новость состоит в том, что ZFS рабоатет достаточно неплохо с установками по умолчанию.

 Очереди ввода/вывода

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

Синхронные чтения происходят в случае, когда ваше приложение запрашивает свои данные прямо сейчас. Приложение, а возможно и его пользователь, находится в ожидании этих данных прежде чем сможет продолжить выполнение своей работы. Синхронные записи, аналогично, запрашивают, чтобы их данные были записаны немедленно. Базы данных - и прочие приложения, которые хотят иметь гарантию что они не выполнят "следующую вещь" пока эти данные не сохранились на ваш диск - запрашивают синхронные записи. В ZFS синхронные записи выполняются настолько быстро, насколько это возможно (ASAP, as soon as possible). Это то место, где в действие вступает SLOG, быстрое выделенное устройство, в котором могут временно сохраняться синхронные записи, причём более быстро чем они сохраняются обычно.

Асинхронные чтения менее важны и в основном состоят из функций упреждающего чтения ZFS, загрузки данных с диска в ожидании, что они вам понадобятся. Приложение не будет уведомляться о том, когда ZFS выполнит чтение этих данных и сделает их доступными вместо того чтобы в явном виде дожидаться их. Асинхронные записи работают аналогичным образом. Ваше приложение передаёт некие данные в ZFS и сообщает: "запиши их когда нибудь". ZFS хранит эти данные для асинхронной записи в памяти пока не завершится следующая txg, после чего сбрасывает их на свой диск. Группирование этих данных и их массовая запись улучшают производительность.

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

Синхронные чтения содержат запрашиваемые программой данные. Вызов файла вашим текстовым редактором является синхронным чтением. Управляйте им при помощи sysctls vfs.zfs.vdev.sync_read_max_active и vfs.zfs.vdev.sync_read_min_active. Каждое по умолчанию установлено в значение 10. Скорее всего пользователь может замечать при сихронных чтениях латентность. Если пользователь пытается открыть файл и это занимает несколько секунд вместо 50мс, пользователь скажет что система медленная.

Запросы упреждающего чтения являются асинхронными; пока ещё никто не запросил эти данные, однако ZFS предвидит, что такой запрос вскоре появится. Если программа читает первую порцию файла, у ZFS есть хорошие основания что вскоре поступит запрос на оставшуюся часть этого файла. Управляйте своим значением ожидающих обработки запросов асинхронного чтения при помощи ysctls vfs.zfs.vdev.async_read_max_active и vfs.zfs.vdev.async_read_min_active. Для них значения по умолчанию установлены в 3 для максимума и в 1 для минимума. Цель ограничения числа асинхронных операций состоит в обеспечении того, что новые синхронные операции не окажутся на задней линии позади менее важных чтений. Когда значение ожидающих операций к данному диску падает ниже своего минимума, ZFS добавляет в свою очередь дополнительные задания, причём более важные операции добавляются в эту очередь первыми. Порядок операций в очереди не изменяется.

Синхронные записи применяются в случае использования программой системного вызова fsync(2). Эти запросы поступают напрямую в ZIL, вне зависимости от того, поддерживает ли этот поставщик хранения данных отдельный SLOG. Такие записи являются наиболее ваной операцией, так как вызывающее приложение ожидает окончания данной операции прежде чем продолжить исполнение. Настройка этого значения слишком маленьким уменьшает пропускную способность и увеличивает латентность. Зпаиси в ZFS обычно собираются в пакет, с тем, чтобы получать преимущество от нахождения записывающих головок в правильном положении для того, чтобы записывать за раз столько данных, сколько возможно. Однако, если число операций для очереди слишком велико, синхронные чтения должны ожидать завершения уже помещённых в очередь записей, что отрицательно влияет на доступность системы. Значения sysctls vfs.zfs.vdev.sync_write_max_active и vfs.zfs.vdev.sync_write_min_active управляют тем, сколько таких запросов может ожидать рассмотрения поставщиком в некий момент времени. Оба занчения по умолчанию равны 10.

Асинхронные записи являются обычным обменом, который не передаётся в ZIL. Асинхронные записи находятся в txg, после чего массово фиксируются. Значения sysctls vfs.zfs.vdev.async_write_max_active и vfs.zfs.vdev.async_write_min_active управляют тем, сколько одновременных запросов асинхронной записи активны для одного поставщика хранения. Значение по умолчанию для максимума 10, а для минимума 1.

Процесс Очистки имеет свои собственные очереди, управляющие тем, сколько ожидающих обработки запросов ввода/ вывода могут быть активными в пуле одновременно. Значения sysctls vfs.zfs.vdev.scrub_max_active с величиной по умолчанию 2 и vfs.zfs.vdev.scrub_min_active установленное по умолчанию в 1, управляют данной очередью. Подстройка этих кнопок регулирует то как очистка влияет на загруженность системы. Более глубокие очереди делают выполнение вашей очистки более охотным, однако очереди прочих операций отодвигаются работами по очистке.

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

  Запросы по-VDEV

Чтобы знать как ZFS будет планировать активность, вы должны знать сколько запросов на ожидание может поступать каждому VDEV системы. Рассмотрим максимальное значение запросов для каждого типа на поставщика хранения (обычно диск), как они были определены sysctls в предыдущем разделе.

  • максимум синхронного чтения: 10

  • максимум асинхронных чтений: 3

  • максимум синхронной записи: 10

  • максимум асинхронных записей: 10

  • максимум очистки: 2

Диск с максимальным числом одновременных запросов возможно должен иметь 35 ожидающих запросов. VDEV из 10 дисков может иметь 350 одновременно ожидающих запросов, а VDEV из 29 дисков может иметь 1015 одновременно ожидающих запросов.

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

Изменение данных значений регулирует то, как ZFS распределяет запросы. Вы хотите чтобы ваша система была сбалансирована в сторону записи данных? Увеличьте максимальное значение асинхронных записей. Вам нужны более быстрые очистки? Поднимите потолок очистки.

Однако, вы не можете увеличить скорость своего оборудования крутя данные параметры. Существующие пределы могут быть больше чем простое насыщение жёсткого диска SATA 5400 RPM. При наличии у вас отдельного оборудования для чтения и записи устройства хранения более высокого уровня, скорее всего, смогут обрабатывать слегка большие значения. Даже с ними вы достигните вскоре максимума мощности.

Для твердотельных хранилищ, например SSD, у которых IOPS может быть намного выше чем у шпиндельных дисков, производительность может быть улучшена увеличением данных настроек. Чтобы получить наивысшую производительность, вашего устройства, вы должны дать ему достаточный объём работ чтобы оставлять его занятым, но в то же время не не так сильно, чтобы она не занимала слишком много времени для того, чтобы дать возможность важным запросам добавляться в конец их очереди. Применяйте представленный ранее в этой главе сценарий DTrace для измерения латентности под нагрузкой и выравнивать её по необходимости.

Однако, если у вас в наличии супер- пупер оборудование и повышены очень сильно пределы, вы столкнётесь со своими пределами на VDEV, изменяющими всё.

  Планирование больших VDEV

ZFS имеет две системы планирования: одна для применения когда ваша система допускает много ожидающих запросов ввода/ вывода, и другая для случая, когда система этого не допускает. Что такое много? Это зависит от ваших VDEV и вашего хоста.

Значение sysctl vfs.zfs.vdev.max_active определяет уровень флага, при котором ZFS изменяет алгоритмы управления. Значение по умолчанию для FreeBSD равно 1000. Для большинства хостов при настройках по умолчанию, это означает, что вы можете иметь в VDEV до 8 дисков до переключения алгоритмов. Если вы измените свои очереди ввода/ вывода, вы изменяете свою математику.

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

  • минимум синхронного чтения: 10

  • минимум асинхронных чтений: 3

  • минимум синхронной записи: 10

  • минимум асинхронных записей: 1

  • минимум очистки: 1

Это означает, что каждый диск получает по крайней мере 25 ожидающих запросов. Система может поддерживать по умолчанию до 1000 ожидающих запросов, поэтому любые дополнительные запросы назначаются в порядке приоритетов.

Если у вас более 40 поставщиков хранения в одном VDEV, даже минимумы превосходят общий разрешённый в системе предел. Либо измените vfs.zfs.vdev.max_active чтобы разрешить больше запросов, либо, что более предпочтительно, перенастройте свои VDEV, чтобы они содержали разумное число поставщиков хранения.

 Асинхронные записи и размеры групп транзакций

Выполнение асинхронных записей происходит слегка другим образом. Когда система практически не нагружена и не имеет много запросов на запись, система создаёт отдельный запрос асинхронной записи. (Технически, минимальное значение равно sysctl vfs.zfs.vdev.async_write_min_active, однако не существует действительной причины включать его выше 1.) Находящиеся в памяти и ожидающие записи на диск данные называются "грязными данными" ("dirty data"). По мере увеличения группы транзакции в размерах и частоты, расписания ZFS выполняют всё больше и больше записей. Когда система достигает максимального значения запросов на запись, что определено значением vfs.zfs.vdev.async_write_max_active sysctl, она начинает искусственно замедлять отклики запросам на запись.

Значения vfs.zfs.vdev.async_write_active_min_dirty_percent и vfs.zfs.vdev.async_write_active_max_dirty_percent управляют тем, как ZFS добавляет запросы на запись. Это процентные соотношения того, сколько в системе допускается грязных данных - максимальный размер txg или непосредственное значение параметра sysctl vfs.zfs.dirty_data_max. При минимальном процентном соотношении и ниже него система использует минимальное число запросов на запись, оставляя бОльшую полосу пропусканеия для чтений. При максимальном процентном соотношении и выше него система применяет максимальное значение запросов на запись, пытаясь удерживать объём данных, который необходимо записать. Между этим значениями число запросов масштабируется линейно.

По умолчанию минимальное процентное соотношение равно 30, а максимальное 60. Минимальное число запросов на асинхронную запись равно 1, а максимальное равно 10. Как они применяются?

Предположим, хост имеет значение vfs.zfs.dirty_data_max, установленное в 1ГБ, благодаря этому он легко справляется с вычислениями. Ондна txg может иметь размер только 1ГБ. Если хост имеет до 300МБ данных, готовых к записи (30 процентов от 1ГБ), он применяет один запрос на запись. Каждые 30МБ грязных данных свыше 300 добавляют другой запрос на запись. Если у хоста имеются готовых к записи 600МБ грязных данных (60 процентов от 1ГБ), он ставит в очередь 10 запросов на запись.

В идеальном мире, в котором ваша система обрабатывает нормальную нагрузку, размер txg должен изменяться где-то между минимальным и максимальным размером. Наш хост с vfs.zfs.dirty_data_max должен иметь объём грязных данных около 450МБ, плюс- минус 150.

Межет быть, ваши VDEV способны обрабатывать более чем 10 команд в очереди на ваш диск, поэтому вы хотите увеличить это vfs.zfs.vdev.async_write_max_active sysctl. Увеличение данного sysctl выше значения, которое может обрабатывать ваше оборудование, вызывает увеличившуюся латентность, поэтому проведите мониторинг влияния любых изменений при нормальной нагрузке. Изменение максимального значения ждущих в очереди запросов на запись воздействует на то как быстро ваша система создаёт запросы на запись, однако оно не влияет на процентное соотношение.

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


#pragma D option aggpack
#pragma D option quiet

fbt::vdev_queue_max_async_writes:entry
{
 self->spa = args[0];
}
fbt::vdev_queue_max_async_writes:return
/self->spa && self->spa->spa_name == $$1/
{
 @ = lquantize(args[1], 0, 30, 1);
}

tick-1s
{
 printa(@);
 clear(@);
}

fbt::vdev_queue_max_async_writes:return
/self->spa/
{
 self->spa = 0;
}
"
 	   

Выполните этот сценарий при помощи dtrace, предоставив имя пула в качестве параметра.


# dtrace -s q.d zroot
 	   

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

Если у вас изменчивые латентность и число операций, вы должны уменьшить vfs.zfs.vdev.async_write_active_min_dirty_percent, потому что данная система разводит дополнительные запросы на запись очень часто. Вы также можете увеличить максимальное процентное соотношение в vfs.zfs.vdev.async_write_active_min_dirty_percent или увеличить объём допустимых в системе грязных данных.

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

 Ограничение записи

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

В более общем случае, OpenZFS подтверждает получение данных как только эти находящиеся в группе транзакции данные готовы к записи на диск. Это работает хорошо - пока лежащее в основе оборудование не столкнётся с проблемой обработки запросов на запись. Хотя вы не можете регистрировать каждый пакет в насыщенной гигабитными линиями диске SATA-I, некоторые люди продолжают настаивать на этом.

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

Сценарий реального времени DTrace может определить что ваша система задерживает записи.


# dtrace -n fbt::dsl_pool_need_dirty_delay:return’{ @ [args[1] == 0 ? "no delay" : "delay"] = count(); }’
 	   

В случае возникновения проблемы с производительностью выполните этот сценарий. Пусть он собирает данные "некоторое время" - что- нибудь от нескольких секунд до пары минут. Для выхода нажмите CTRL-C. Вы получите значение числа искусственно задержанных записей и значение числа записей без задержек. Если задерживается только малая часть ваших записей, ваши проблемы с производительностью заключаются в чём- то другом.

FreeBSD содержит sysctls для настройки значений такой задержки или выравнивания латентности, что более последовательно, однако если ваше оборудование предназначено для резервного копирования, вы явно пытаетесь набивать слишком много данных через ваши устройства ввода/ вывода в системе хранения. Разделите ваши записи между большим числом устройств, добавьте оборудование или улучшите аппаратные средства.

 Производительность очистки и восстановления

Любой кто работал в большом предприятии, страдал от политик окон обслуживания, которые не очень хорошо соответствуют современным аппаратным средствам. Лукас не раз задерживался с заменой отказавшего жёсткого диска с горячей заменой в рабочие часы, так как корпоративная политика обслуживания устанавливала, что единственным возможным временем для проведения такого обслуживания является утро воскресенья. (Не то чтобы Лукас помнил каждую минуту потерянную на подобное безумие, или хранит список людей, чья политика стоила ему выходных, или ждёт официального ответа Kneecappers Inc. на его Официальный Запрос.) Если вы застряли в политике подобного вида, будет жизненно важно быстро завершать восстановление и очистку, чтобы вы могли начинать свой день.

Очистка и восстановление имеют встроенные ограничения для того, чтобы эти операции не вмешивались в обычную работу. Если любым другим процессам нужны ввод/ вывод, подобные операции сопровождения откладываются. Ускорение очистки и восстановления означают запрет такого ограничения скорости.

Ограничение скорости является sysctl, которое задаёт количество времени, помещаемое между каждыми обслуживающими их операциями ввода/ вывода. Такое ограничение скорости вышибает только когда диск не простаивает.

Задержка измеряется в тактах системы. Значение числа тактов в секунду управляется kern.hz sysctl. По умолчанию оно составляет 1000, хотя многие пользователи виртуальных машин и ноутбуков могут установить его в 100 в надежде улучшить производительность.

Что в точности означает "не простаивает"? Диск должен не иметь активности на протяжении числа тиков равного vfs.zfs.scan_idle sysctl.

Параметр sysctl vfs.zfs.resilver_delay управляет этим искусственным промежутком для восстановления, а vfs.zfs.scrub_delay обрабатывает очистку. По умолчанию очистки ждут четыре такта между операциями, а промежуток восстановления установлен в значение два. Если ZFS засыпает на четыре такта между каждым вводом/ выводом, максимальное IOPS, создаваемое очисткой для не простаивающего пула должно быть 250IOPS (1000 тактов в секунду делится на четыре такта для операции). Прочие процессы получают возможность выполнить ввод/ вывод в течение этих пауз. Выполнение таких операций ещё сдерживает ваши очистку или восстановление.

Прочие потребители OpenZFS, например illumos, часто применяют 100 тактов в секунду. Таким образом, задержки FreeBSD всего лишь одну десятую от большинства остальных операционных систем. Скорее всего, это был недосмотр, а не преднамеренное архитектурное решение.

Для ликвидации задержки очистки или восстановления установите их в значение 0, определяя вашему сопровождению тот же приоритет, что и всем прочим процессам. Помните, эти задержки включаются только если в вашем пуле существует некая другая активность.

Вы можете управлять тем, сколько данных отсылает очистка при планировании ввода/ вывода. Увеличение глубины такой очереди даёт вашему планировщику ввода/ вывода ZFS возможность работать более эффективно. Параметр sysctl vfs.zfs.top_maxinflight управляет глубиной очереди ввода/ вывода для очистки. Его значение по умолчанию равно 32, но некоторые люди увеличивают его до 2049. Такое большое увеличение будет расходовать оперативную память, поэтому как только вы настроите свои очистки, выполните мониторинг системы.

Каждый txg устанавливает минимальный промежуток времени, который он тратит на восстановление. По умолчанию txg тратит минимум 3000 миллисекунд на восстановление. Значение vfs.zfs.resilver_min_time_ms управляет тем, сколько времени данная группа транзакции выделяет на ввод/ вывод восстановления. Это значение игнорируется в случае отсутствия необходимости в восстановлении.

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