Предыдущая версия справа и слева
Предыдущая версия
Следующая версия
|
Предыдущая версия
|
linux:zfs:deep_info [2023/10/28 08:53] admin |
linux:zfs:deep_info [2023/11/04 17:06] (текущий) admin [Производительность] |
Zettabyte File System - ФС с деревом Меркла, от Sun Microsystems, создана в 2004-2005 гг для Solaris.\\ | Zettabyte File System - ФС с деревом Меркла, от Sun Microsystems, создана в 2004-2005 гг для Solaris.\\ |
Поддерживает большие объемы данных, объединяет концепции файловой системы, массивов RAID, менеджера логических томов, принципы легковесных файловых систем, представляет простое управление томами хранения данных\\ | Поддерживает большие объемы данных, объединяет концепции файловой системы, массивов RAID, менеджера логических томов, принципы легковесных файловых систем, представляет простое управление томами хранения данных\\ |
| |
| <details> |
| <summary>:!: Подробнее</summary> |
На момент создания была новаторской, есть открытая реализация "OpenZFS"\\ | На момент создания была новаторской, есть открытая реализация "OpenZFS"\\ |
Обеспечивает полный контроль над физическими носителями и логическими томами и постоянное поддержание консистентности ФС.\\ | Обеспечивает полный контроль над физическими носителями и логическими томами и постоянное поддержание консистентности ФС.\\ |
Собсна в открытом доступе есть именно "OpenZFS", он появился сразу после закрытия исходников первого, основан основателями ZFS\\ | Собсна в открытом доступе есть именно "OpenZFS", он появился сразу после закрытия исходников первого, основан основателями ZFS\\ |
По сути из-за формальностей, OpenZFS распространяется под лицензией "CDDL" из за чего не может быть включена в ядро Linux по умолчанию, поэтому есть танцы с ее установкой, но в целом у каждой собаки есть инструкция как на нее поставить ZFS\\ | По сути из-за формальностей, OpenZFS распространяется под лицензией "CDDL" из за чего не может быть включена в ядро Linux по умолчанию, поэтому есть танцы с ее установкой, но в целом у каждой собаки есть инструкция как на нее поставить ZFS\\ |
| |
<details> | |
<summary>:!: Подробнее</summary> | |
Основные преимущества:\\ | Основные преимущества:\\ |
* объединенное хранилище | * объединенное хранилище |
В рамках пула, каждый уникальный блок данных будет хранится только на одном Vdev\\ | В рамках пула, каждый уникальный блок данных будет хранится только на одном Vdev\\ |
{{:linux:zfs:2023-10-28_14-13.png?direct&400|}}\\ | {{:linux:zfs:2023-10-28_14-13.png?direct&400|}}\\ |
| {{:linux:zfs:2023-11-03_21-47.png?direct&400|}}\\ |
| |
<details> | <details> |
ZFS в продакшене чаще применяют для крупных инсталляций хранилища данных. Архитектура подразумевает эффективную утилизацию большого кол-ва HDD, SSD, RAM, CPU\\ | ZFS в продакшене чаще применяют для крупных инсталляций хранилища данных. Архитектура подразумевает эффективную утилизацию большого кол-ва HDD, SSD, RAM, CPU\\ |
| |
| <details> |
| <summary>:!: Использование</summary> |
| Блоки типа ARC,ZIL и тд это не диски, которые мы можем использовать, это понятия виртуальные, они всегда есть в ZFS. Есть возможность вынести их на более быстрые носители\\ |
| |
| ZIL можно вынести на т.н. Slog, которому не нужно быть большим, т.к. синхронная запись обычно идет мелким блоком и быстро сбрасывается на основное хранилище. Т.е. важно как можно быстрее записать конкретный блок и отрапортовать клиенту об успешной записи, а не записать как можно больше данных.\\ |
| Slog нужен для чтения только при сбое питания\\ |
| |
**** | ARC можно дополнить одним или более SSD и выгружать на него определенный вид данных, например, кэшировать только метаданные или данные, которые последовательно или случайно прочитались с основного хранилища\\ |
| </details> |
| |
**** | |
| |
| |
| ===== Паттерны использования ===== |
| ZFS это локальное хранилище, по умолчанию подразумевается хранилище в рамках одного хоста\\ |
| |
| <details> |
| <summary>:!: </summary> |
| * Подходит для домашнего использования, где не самое дорогое оборудование и не быстрые диски но можно использовать процессор на доп вычисления (полагаю подразумевается сжатие, чтобы уменьшить объем записи) |
| * NFS хранилище, где больше дисков, начинаем думать о синхронной записи, кэше и тд |
| * Так же в качестве крупного хранилища, когда в рамках одного пула более ста дисков, где важно восстановление при сбое |
| |
| Можно оптимизировать любой профиль нагрузки, начиная от размера блока\\ |
| Например когда хотим оптимизировать copy-on-write то можем писать бОльшим блоком чем в классических ФС, для ZFS по умолчанию принят объем в 128КБайт на блок\\ |
| </details> |
| |
| |
| ===== Сравнение с аппаратными решениями ===== |
| Плюс аппаратных решений в том что на них можно перенести вычислительную нагрузку и с (в случае поддерживания) вопрос синхронной записи\\ |
| Тут же следом и минусы, выч мощность может превышать возможности, апгрейдить судя по всему только заменой, большой минус в том что в случае выхода из строя нужно искать полный аналог\\ |
| |
| Главный плюс в том что ZFS может очень гибко подстраиваться под систему/задачи, оч важный момент\\ |
| |
| <details> |
| <summary>:!: </summary> |
| Во первых это то что метаданные пишутся в начале каждого диска, в случае с переездом достаточно просто подключить диск в другой сервер, главное чтобы версия ZFS была совместимая, ненадо даже соблюдать никакой порядок, система сама все обнаружит и соберет\\ |
| |
| Второй момент, в случае аппаратного решения, настройка размеров блока, страйпов и пр делается единожды и не меняется\\ |
| |
| В ZFS же, **в рамках одного пула можно создавать несколько датасетов и каждый настраивается персонально**\\ |
| **Датасет** - отдельная ФС со своими настройками. К примеру, для СУБД можно создать отдельное пространство под основные данные с размером блока 8КБайт и отдельный датасет, оптимизированный для WAL-лог с размером 16КБайт.\\ |
| Хочется сжимать данные ? - "**zfs set compression=on**", другие данные читаются очень редко и могут вымывать ARC ? - "**zfs set primarycache=metadata**"\\ |
| |
| Имея один пул, можно настраивать под конкретную операцию хоть каждый датасет, мы максимально подстраиваемся под приложения\\ |
| </details> |
| |
| |
| ===== Особенности работы ZFS ===== |
| |
| **Фрагментация данных**\\ |
| В copy-on-write системе постоянно появляются новые блоки, а старые не всегда пригодны к удалению\\ |
| <details> |
| <summary>:!: </summary> |
| ZFS пространство разрезано на т.н. **metaslabs**, которые ведут трекинг того, какие сектора свободны, а какие заняты. Это происходит на уровне SPA слоя, который работает с дисками\\ |
| |
| В рамках этих пространств мы при каждом аллоцировании ищем наиболее подходящее\\ |
| Когда места в пуле много, то выбираем пространство с самым большим объемом свободного места, куда будет лучше записаться с точки зрения дальнейшей фрагментации. Например у нас 1МБайт данных, мы ищем свободный блок в 1МБайт и можем цельно записаться\\ |
| |
| Когда места становится мало, включается другой режим, дороже по производительности и только усиливает фрагментацию, ищется первое попавшееся подходящее место\\ |
| В худшем случае, когда места уже нет, он будет разбиваться и записывать кусками\\ |
| |
| По умолчанию на каждый Vdev создается ~200 meta-slabs. Это чем то похоже на WAL-лог БД\\ |
| </details> |
| |
| |
| **Запись данных**\\ |
| По умолчанию чтение данных в ZFS практически всегда является случайным, но т.к. мы пишем каждый раз в новое место, то можем превращать случайную запись в практически последовательную\\ |
| Если нужна система хранения под запись и редкое чтение, то любая copy-on-write система будет отличным решением\\ |
| Данные пишутся группами транзакций (tgx, transaction groups), можно агрегировать информацию в рамках этих групп\\ |
| |
| <details> |
| <summary>:!: </summary> |
| Существует **Write Throttling** мы можем использовать неограниченное кол-во оперативной памяти для подготовки **tgx-группы** и за счет этого переживать резкие скачки записи, буферизируя все в оперативную память.\\ |
| Ес-но речь про асинхронную запись, когда мы можем себе это позволить, так можно последовательно и очень эффективно сложить данные на диск\\ |
| |
| Если синхронная запись и ее целостность не важна, например, у вас не большая и дорогостоящая PostgreSQL, а сервер на одного пользователя, то синхронную запись можно отключить командой "**zfs set sync=disabled**"\\ |
| |
| Т.о. собрав пул из HDD, можно ими пользоваться как дешевыми SSD с точки зрения IOPS\\ |
| Сколько IOPS даст оперативная память, столько и будет. При этом целостность ZFS обеспечивает в любом случае - при потере питания произойдет откат на последнюю целую транзакцию\\ |
| В худшем случае теряется последние несколько сек записи, то что настроено в "**tgx_timeout**", по умолчанию до 5 сек и плюс на заданный размер\\ |
| </details> |
| |
| |
| |
| ===== ARC ===== |
| Adaptive Replacement Cache (Кэш адаптивной замены)\\ |
| |
| <details> |
| <summary>:!: Некоторая статистика</summary> |
| [[https://utcc.utoronto.ca/~cks/space/blog/linux/ZFSOnLinuxARCMemoryStatistics|Doc]]\\ |
| |
| ZFS сообщает некоторую информацию об ARC в **/proc/spl/kstat/arcstats**\\ |
| Параметром размера является "**arc_c**". Который ARC считает целевым размером\\ |
| |
| Есть три метрики ОЗУ "**memory_all_bytes**", "**memory_free_bytes**" и "**memory_available_bytes**", общий, доступный и доступный для расширения ZFS объем оперативы, по мнению ZFS конечно же\\ |
| Доступный ей объем может быть отрицательным, тогда ARC сжимается\\ |
| "**memory_availabe**" это "**memory_free**" минус "**arc_sys_free**" (параметр, сколько ОЗУ нужно оставлять системе, по умолчанию 1/32, хотя говорится 1/64 от общего объема)\\ |
| |
| Может ли ARC расти в данный момент, показано в "**arc_no_grow**", равен 1 когда нет. Как правило включается и остается включенным если "**memory_available**" меньше 1/32 от "**arc_c**"\\ |
| При приближении к этому значению ARC значительно замедляет рост, вроде как\\ |
| |
| Если "**arc_need_free**" не равно нулю, значит ZFS пытается (по крайней мере на это значение) уменьшить ARC. Тут просто раскрывается некоторая информация поэтому необязательно отображает всю освобождаемую память\\ |
| </details> |
| |
| |
| <details> |
| <summary>:!: Управление памятью</summary> |
| В контуре управления памятью ядра Linux есть т.н. "сжиматели" (наверняка есть лучше перевод), (функции обратного вызова) которые вызываются подсистемами (например ZFS) для уменьшения используемой памяти\\ |
| Работает в два этапа, сначала ядро спрашивает подсистему сколько памяти она может вернуть, затем просит ее сделать это\\ |
| |
| Базовый объем памяти который ARC может вернуть, представляет собой сумму "**evictable**" (mru,mfu,data,metadata) (фактически механизм более сложный) [[https://github.com/openzfs/zfs/blob/master/module/os/linux/zfs/arc_os.c#L135|GH]], разовый объем ограничивается [[https://openzfs.github.io/openzfs-docs/man/master/4/zfs.4.html#zfs_arc_shrinker_limit|zfs_arc_shrinker_limit]] (160Mb ?)\\ |
| |
| При каждом сжатии, ARC уменьшается на запрошенную ядром величину, "**arc_no_grow** устанавливается в true" - ???.\\ |
| Если сжатие происходит с помощью "**kswapd_Linux**", то это косвенный механизм, увеличивается метрика "**memory_indirect_count**", если же процесс пытается выделить память а ее нет и напрямую запускает процесс освобождения, это прямой механизм, растет "**memory_direct_count**"\\ |
| Собсна прямое освобождение указывает на проблему и является плохим состоянием\\ |
| |
| ARC имеет ограничения на объем хранимых метаданных (как общие **arc_meta_used** так и для "dnode" **dnode_size**). Когда ARC сжимает метаданные, ему может потребоваться обрезать себя, заставив ФС освободить "dnodes" и другие вещи которые в данный момент удерживаются. В эти моменты увеличивается **arc_prune** (мнение что по одному на каждую смонтированную ФС)\\ |
| |
| Когда ARC удаляет данные, он может увеличивать две статистики, "**evic_skip**" и "**evic_not_enough**". Последняя выражает кол-во случаев когда при выселении не удалось выселить достаточно чтобы достичь целевой суммы.\\ |
| Первое - "кол-во буферов, пропущенных из-за того что в них выполняется ввод-вывод, являются буферами косвенной предварительной выборки, которые просуществовали недостаточно долго или не принадлежат SPA, из которого пытаемся выселить"\\ |
| |
| "**Anon**" буферы которые не связаны с DVA, буферы в которых хранятся "грязные" (предварительные, полагаю) копии блоков, прежде чем они будут записаны в стабильное хранилище. Они считаются частью "**arc_mru**" которую нельзя освободить. Они получают DVA по мере их записи и мигрируют в "arc_mru"\\ |
| В "Anon" хоть и есть статистика "**evictable**", она всегда равна нулю, т.к. эти данные не подлежат удалению\\ |
| |
| Некоторая часть подсчитанного здесь пространства может быть "отдана в аренду", отображается в метрике "**arc_loaned_bytes**"\\ |
| |
| В рамках настройки записи ZFS временно резервирует для них пространство ARC, о текущем резервировании сказано в "**arc_tempreserve**".\\ |
| Общий объем "грязных" данных в ARC равен "**arc_tempreserve**" + "**anon_size**" - "**arc_loaned_bytes**"\\ |
| |
| Если ZFS решает ограничить выделение новой памяти для записи, увеличивается метрика "**memory_throttle_count**", что является редкостью видимо\\ |
| </details> |
| |
| |
| <details> |
| <summary>:!: Еще про сокращения памяти</summary> |
| [[https://utcc.utoronto.ca/~cks/space/blog/linux/ZFSOnLinuxARCTargetSizeChanges|Doc]]\\ |
| |
| Целевой и фактический размеры ARC здесь различаются, фактический обычно быстро вырастает до целевого\\ |
| |
| Сокращение может быть вызвано т.н. "жатвой" ("**Reaping**"), это общая ф-я ZFS, при которой выделенный поток ядра просыпается по крайней мере раз в секунду и проверяет не стала ли "**memory_availabel_bytes**" отрицательной\\ |
| Если так то ZFS ставит "**arc_no_grow**" и запускает процесс освобождения памяти, уменьшая целевой размер ARC на |
<code bash> | <code bash> |
| ((arc_c - arc_c_min) / 128) - memory_available_bytes |
| </code> |
| Процесс может быть вызван и немедленно при считывании очередного блока в память ZFS, после проверки "**memory_available_bytes**" на отрицательность\\ |
| |
| Путь "**сжатия**" вызывается с помощью общей функции управления памятью ядра Linux, это другой процесс освобождения ARC\\ |
| |
| При "жатве" часто немного уменьшается целевой размер ARC (300/400mb)\\ |
| При каждом сжатии растет статистика "**memory_direct_count**" либо "**memory_indirect_count**", при "**жатве**" никакая статистика не увеличивается\\ |
| |
| </details> |
| |
| |
| |
| <details> |
| <summary>:!: Про размеры </summary> |
| [[https://utcc.utoronto.ca/~cks/space/blog/solaris/ZFSARCItsVariousSizes|Doc]]\\ |
| |
| Текущий общий размер указан в "**arc_size**". ARC и содержит "**MRU**" i "**MFU**", у которых так же есть метрики "**size**", но общий размер это не только сумма этих двух\\ |
| В общем то содержит в себе "**data_size**", "**metadate_size**", "**bonus_size**", "**dnode_size**", "**dbuf_size**", "**hdr_size**", "**l2_hdr_size**", "**adb_chuck_waste_size**" (adb - сокращение от буферизированные данные)\\ |
| |
| Основу составляют "**data_size**" и "**metadata_size**"\\ |
| "**arc_meta_used**" объединяет все (кроме data_size и adb_chuck_waste_size), которое по сути является метаданными в некотором смысле, это объединение важно поскольку регулируется "**arc_meta_limit**"\\ |
| |
| Даже если вы не включили сжатие для данных, ZFS может использовать его для метаданных. Для отражения этого есть метрики "**compressed_size**" и "**uncompressed_size**", второе показывает сколько данные весили бы если бы все было без сжатия\\ |
| |
| "**overhead_size**" данные хранящиеся во всех "**arc_buf_t**", классифицируется как накладные расходы т.к. они будут очищены как только на них перестанут ссылаться, если специально не задано иное\\ |
| |
| "**arc_p**" (сокращение от раздел) является целевым размером для "**MRU**".\\ |
| Целевой размер "**MFU**" равен "c - p" и не указывается явно\\ |
| |
| <code bash> |
| c -> Is the total cache size (MRU + MFU) |
| p -> represents the limit of MRU |
| (c - p) -> represents the limit of MFU |
| c_max, c_min -> hard limits |
| size -> Total amount consumed by ARC |
</code> | </code> |
| </details> |
| |
| |
| ==== L2ARC ==== |
| Является вторым кэшем чтения, перехватывает выпадающие из вашего ARC элементы\\ |
| При применении небольшого, быстрого диска, с большим резервом перезаписи для кэширования данных ARC, вы можете одновременно уменьшить нагрузку чтения в основном хранилище и увеличить производительность чтения\\ |
| |
<details> | <details> |
<summary>:!: </summary> | <summary>:!: </summary> |
| Хоть L2 и пишется на диск, данные на нем не выдерживают перезагрузку, т.к. индексы этих данных разрушены\\ |
| |
| Применение L2 становится существенным при наличии большого числа пользователей, приложений, вирт машин, имеющих доступ к одному и тому же набору данных\\ |
| Если ваш рабочий набор больше чем объем памяти, вашим вторым шансом будет L2\\ |
| |
| :!: Важный момент в том, что для обслуживания L2 так же используется память\\ |
| Раз L2 содержит целый набор кэшированых данных и метаданных, индекс этих данных находится в основном ARC\\ |
| Грубо говоря, **каждый гигабайт L2ARC стоит 25Mb ARC** (в частности зависит от размера секторов, св-ва recordsize и др. вещей), в реальности десятки гигов отнимает запросто\\ |
| |
| L2ARC **кэширует только выпадающие из ARC данные**, то чего не было в основном кэше сюда не попадет\\ |
| т.е. если в основном кэше запретить кэшировать метаданных то **и здесь их не будет**, даже если выставить соответствующий параметр\\ |
| |
| Кэширование потоковой передачей по умолчанию отключено (это когда большие файлы) т.к. основная задержка уходит на позиционирование головки, а после чтение происходить очень хорошо, поэтому смысла нет\\ |
| |
| При нормальной работе ZFS **пишет только 8Мб в секунду** в каждое устр-во L2ARC. Это позволяет избегать преждевременного "высасывания" SSD и т.н. "пробуксовки" кэша\\ |
| Параметр настраивается "vfs.zfs.l2arc_write_max"\\ |
</details> | </details> |
| |
| |
| |
==== ==== | <details> |
| <summary>:!: </summary> |
| |
| </details> |
| |
| |
| |
| ===== ZIL ===== |
| Кэш используется не только для чтения но и для записи, применяя т.н. "**Целевой журнал (ZIL, ZFS Intent Log)**"\\ |
| Каждый пул имеет свой собственный ZIL\\ |
| |
| <details> |
| <summary>:!: </summary> |
| ZFS накапливает данные в этом журнале в т.н. **группы транзакций (txgs, transaction groups)**, затем, при наполнении достаточного объема либо по таймауту, txgs записывается на диск\\ |
| |
| Группа транзакций может содержать порции данных от разных, не связанных процессов\\ |
| содержит "запросы на запись", порция данных и связанных с ФС метаданных\\ |
| |
| "ГТ" является списком "что делать", данные чувствительны к отказам системы пока они полностью не будут записаны на диск, в случае отказа ГП потеряется\\ |
| Уменьшение таймаута может уменьшить объем потенциальной потери но плохо скажется на производительности\\ |
| |
| Касательно использования диска ZIL и записывания ZIL на диск, тут есть момент с синхронной/асинхронной записью данных\\ |
| "Пул применяет ZIL только для синхронно- записываемых данных, асинхронные обычно сохраняются в оперативной памяти и фиксируются как часть регулярной группы транзакций"\\ |
| |
| </details> |
| |
| |
| <details> |
| <summary>:!: Выделение отдельного устр-ва</summary> |
| Отдельное устр-во называется "SLOG (Separate Intent Log)", перемещая ZIL на отдельное устр-во вы избегаете записи одних и тех же данных дважды на одного поставщика хранения (все таки ZIL похоже применяется, точнее пишется на диск, только в случае синхронной записи, это когда приложение ждет от ядра подтверждения записи данных, вот он и записывает их, ф-я подтверждения это стандартная ф-я, типа fsync(), полагаю разрабам пришлось сделать такой финт для поддержки этого функционала\\ |
| Однако есть момент, при монтировании ФС есть флаги запрещающие синхронную запись, тогда подтверждение будет ложным и мгновенным)\\ |
| |
| Дак вот, вынос на отдельное устр-во, если оно быстрее аппаратно, ну и запись единожды\\ |
| Второй момент, отдельное устр-во это только устр-во, ZIL как таковая служба продолжает работать, просто на этом устр-ве, "ZIL" работает на "SLOG", если "SLOG" выходит из строя, ZIL автоматом переключается на основной пул, снова\\ |
| |
| метрика "**dirty_data_max**" похоже связана с размером ZIL\\ |
| |
| |
| </details> |
| |
| |
| |
| ===== Производительность ===== |
| [[http://onreader.mdl.ru/AdvancedZFS/content/Ch08.html|Doc]]\\ |
| Обычно имеется четыре основных ресурса:\\ |
| * **В/В системы хранения** |
| * **Пропускная способность сети** |
| * **Оперативная память** |
| * **ЦП** |
| |
| Производительность системы всегда определяется самым ее медленным компонентом !!!\\ |
| |
| <details> |
| <summary>:!: </summary> |
| Например сжатие ZFS уменьшает объем записываемых и считываемых данных, за счет процессорного времени, если оно в избытке конечно же, это частая возможность бустанутся\\ |
| |
| |
| |
| |
| </details> |
| |
| |
| |
| <details> |
| <summary>:!: </summary> |
| |
| |
| </details> |
| |
| |
| |
| |
| |
| |
| |
| |
| |
===== ===== | |
| |
<details> | <details> |
</code> | </code> |
</details> | </details> |
| |
| |
| |
</code> | </code> |
</details> | </details> |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |