Динамическое выделение памяти (kmalloc, vmalloc, …) в I/O-канале известных блочных драйверов

Вопрос или проблема

Я думал о правильных swap решениях для системы Linux, и возник очень важный вопрос касательно всех них. Как известно и подтверждено моим опытом, устройство для swap будет в конечном итоге доступно в ситуации крайнего давления на память. В таких случаях гипотетически близок OOM kill, но на самом деле, поскольку overcommit_memory=2 и достаточно места для swap все еще доступно в системе — путь OOM недоступен. Вместо этого происходит следующее: ядро считает, что может выгрузить память, когда это необходимо, но “когда это необходимо” уже слишком поздно. Запросы на I/O для swap отправляются драйверу блоков, когда пулы памяти уже абсолютно исчерпаны. Позвольте драйверу блоков попытаться выполнить любое выделение, превышающее некоторый абсолютный минимум, и система окажется в состоянии взаимной блокировки по памяти. К сожалению, это даже не обнаруживается, и путь паники Система заблокирована по памяти никогда не запускается. Вместо этого система зависает навсегда.

Я провел множество экспериментов, чтобы попытаться выяснить проблему. Я вставил код для печати трассировки стека в местах, где происходит блок I/O, чтобы выяснить, какие функции из семейства alloc находятся на пути для популярных устройств (dm-*, loop+nfs и другие конфигурации), и сколько они выделяют. Однако это мне не помогло.

Я сталкиваюсь с проблемами чаще всего на установках “loop dev+ какая-то ФС”, но в конечном итоге я также встречал это с dm-vdo (что является устройством дедупликации и сжатия), и еще с несколькими, когда использовал их для swap.

Я думал, что проблему можно решить, увеличив значения swappiness и min_free_kbytes в sysctl vm.*, но я все еще сталкивался с описанными проблемами. У меня была идея заменить все вызовы, похожие на alloc, выделениями в стеке в нужном коде пути I/O (поскольку у меня 128 КБ стеков ядра), но это казалось слишком неаккуратным решением (подумайте о разрешении конфликтов при вытягивании из upstream) и не применимо везде.

Мой вопрос: на какие из этих драйверов устройств полагаются (тяжелые?) динамические выделения памяти в пути I/O?
Которые известны как работающие хорошо в роли Swap?
Какие соображения следует учитывать при настройке надежного устройства swap? Могут ли эти устройства быть стековыми друг на друга сколько угодно?

  • dm-crypt
  • dm-verity
  • dm-linear
  • loop (--direct-io) + ext4/fat32/?
  • loop + nfs/fuse
  • loop (--direct-io) + btrfs/zfs/bcachefs/?

Вы можете упомянуть личный опыт, конечно.

Ответ или решение

Динамическое выделение памяти (например, kmalloc, vmalloc и т. д.) в контексте работы блоковых драйверов в Linux требует глубокого понимания взаимодействия системы управления памятью и блоковых устройств в условиях высокой нагрузки на память. При рассмотрении вопроса о надёжности систем подкачки (swap) в Linux необходимо принимать во внимание множество факторов.

Динамическое выделение памяти в контексте I/O

В процессе обмена данными с устройствами блоковой подсистемы Linux драйверы используют динамическое выделение памяти для разных целей, таких как буферизация, кэширование операций ввода-вывода и обработка запросов. В частности, в рамках таких драйверов, как dm-crypt, dm-verity и других, используются функции kmalloc и vmalloc. Эти функции требуют наличия доступной памяти в системе, и при её исчерпании могут приводить к проблемам, особенно в условиях предельной нагрузки на память.

Известные драйверы и их поведение

  1. dm-crypt: Этот драйвер использует динамическое выделение памяти для обработки шифрования/дешифрования. В ситуациях с высокой нагрузкой может потребовать достаточно объёмные ресурсы.

  2. dm-verity: Как и в случае с dm-crypt, здесь также происходят динамические выделения памяти для верификации целостности данных.

  3. dm-linear: Обычно выделяет не так много памяти в I/O-пути, что делает его более пригодным для использования в качестве swap.

  4. Loop устройствам:

    • Loop + ext4/fat32: Подходят с использованием --direct-io, однако, это может происходить с использованием динамической памяти при работе с файловыми системами.
    • Loop + nfs/fuse: Выделение памяти может быть значительным, что может вызвать ситуации с недостатком доступной памяти.
    • Loop + btrfs/zfs/bcachefs: Эти файловые системы могут также требовать значительных ресурсов, особенно при выполнении операций с метаданными и при выполнении проверки целостности.

Рекомендации по настройке надёжного swap

  1. Увеличение swappiness: Настройка увеличенного значения swappiness может позволить системе чаще использовать swap, но это не всегда даст желаемый результат, если драйверы требуют значительных динамических ресурсов.

  2. Настройка min_free_kbytes: Увеличение этого параметра может помочь предотвратить ситуации, когда система оказывается в состоянии, близком к краху из-за недостатка памяти.

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

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

Заключение

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

Оцените материал
Добавить комментарий

Капча загружается...