Вопрос или проблема
Я думал о правильных 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
. Эти функции требуют наличия доступной памяти в системе, и при её исчерпании могут приводить к проблемам, особенно в условиях предельной нагрузки на память.
Известные драйверы и их поведение
-
dm-crypt: Этот драйвер использует динамическое выделение памяти для обработки шифрования/дешифрования. В ситуациях с высокой нагрузкой может потребовать достаточно объёмные ресурсы.
-
dm-verity: Как и в случае с
dm-crypt
, здесь также происходят динамические выделения памяти для верификации целостности данных. -
dm-linear: Обычно выделяет не так много памяти в I/O-пути, что делает его более пригодным для использования в качестве swap.
-
Loop устройствам:
- Loop + ext4/fat32: Подходят с использованием
--direct-io
, однако, это может происходить с использованием динамической памяти при работе с файловыми системами. - Loop + nfs/fuse: Выделение памяти может быть значительным, что может вызвать ситуации с недостатком доступной памяти.
- Loop + btrfs/zfs/bcachefs: Эти файловые системы могут также требовать значительных ресурсов, особенно при выполнении операций с метаданными и при выполнении проверки целостности.
- Loop + ext4/fat32: Подходят с использованием
Рекомендации по настройке надёжного swap
-
Увеличение swappiness: Настройка увеличенного значения
swappiness
может позволить системе чаще использовать swap, но это не всегда даст желаемый результат, если драйверы требуют значительных динамических ресурсов. -
Настройка min_free_kbytes: Увеличение этого параметра может помочь предотвратить ситуации, когда система оказывается в состоянии, близком к краху из-за недостатка памяти.
-
Избегать сильной вложенности устройств: Использование нескольких уровней наслоённых устройств может увеличивать шанс возникновения ситуации с исчерпанием памяти. Несмотря на теоретическую возможность создания многослойных структур устройств, на практике это может привести к проблемам.
-
Тестирование конфигураций: Рекомендуется проводить обширные тесты различных конфигураций с реальными сценариями нагрузки, чтобы оценить устойчивость системы.
Заключение
В заключение, выбор надёжного swap-устройства в контексте динамического выделения памяти блоковыми драйверами требует тщательного анализа. Важно учитывать, какие драйверы используют более тяжелое динамическое выделение памяти, а также возможности и ограничения различных комбинаций. Эффективная конфигурация swap-дисков и правильное использование параметров управления памятью могут значительно снизить риски, связанные с нехваткой памяти и замедленной обработкой ввода-вывода.