Добавить в корзинуПозвонить
Найти в Дзене
File Energy

Kdump и оптимизация памяти для crash dump без лишних компромиссов в Linux

Производственный сервер с 256 гигабайтами оперативной памяти резервирует 512 мегабайт под capture-ядро, которое никогда не запустится при нормальной работе. Это 512 мегабайт, которые система не может использовать ни для кэша, ни для приложений, ни для чего-либо полезного. На машинах с небольшим объёмом памяти эта цифра ощущается сразу. На серверах с несколькими терабайтами RAM она кажется незначительной, пока не начинаешь умножать на количество машин в кластере. Kdump работает по принципу двух ядер: основное ядро при загрузке резервирует фиксированный кусок физической памяти, в который заранее загружается capture-ядро. Когда происходит kernel panic, kexec мгновенно переключается на это второе ядро без перезагрузки через BIOS и без инициализации железа. Память основного ядра при этом остаётся нетронутой и доступна через /proc/vmcore в виде ELF-файла. Именно эта архитектура делает kdump надёжным: дамп снимается чистым незатронутым ядром, а не тем, которое только что упало. Но именно эта
Оглавление

Производственный сервер с 256 гигабайтами оперативной памяти резервирует 512 мегабайт под capture-ядро, которое никогда не запустится при нормальной работе. Это 512 мегабайт, которые система не может использовать ни для кэша, ни для приложений, ни для чего-либо полезного. На машинах с небольшим объёмом памяти эта цифра ощущается сразу. На серверах с несколькими терабайтами RAM она кажется незначительной, пока не начинаешь умножать на количество машин в кластере.

Kdump работает по принципу двух ядер: основное ядро при загрузке резервирует фиксированный кусок физической памяти, в который заранее загружается capture-ядро. Когда происходит kernel panic, kexec мгновенно переключается на это второе ядро без перезагрузки через BIOS и без инициализации железа. Память основного ядра при этом остаётся нетронутой и доступна через /proc/vmcore в виде ELF-файла. Именно эта архитектура делает kdump надёжным: дамп снимается чистым незатронутым ядром, а не тем, которое только что упало. Но именно эта же архитектура порождает вопрос оптимизации: сколько памяти действительно нужно capture-ядру, и как это правильно измерить.

Как вычислить минимально необходимый объём резервации

Стандартный совет "ставьте 256M или 512M" это ответ на вопрос, как сделать так, чтобы kdump скорее всего заработал. Это не ответ на вопрос, сколько памяти действительно нужно. Разница между "скорее всего достаточно" и "достаточно точно" может составлять сотни мегабайт на сервере с большим количеством устройств и загруженных драйверов.

Первый шаг, проверить, что kdump вообще инициализировался корректно и сколько памяти зарезервировано сейчас:

# Проверить что память зарезервирована
cat /proc/cmdline | grep crashkernel
cat /sys/kernel/kexec_crash_size

# Посмотреть где в физической памяти находится регион kdump
cat /sys/kernel/kexec_crash_loaded
dmesg | grep -i "crash kernel"

На RHEL 9 и Fedora 35 и новее правильный способ вычислить рекомендуемый размер:

# Определить рекомендуемый размер через kdumpctl
kdumpctl estimate

# Пример вывода:
# Minimum crashkernel: 192M
# Recommended crashkernel: 256M
# Current crashkernel: 512M (can be reduced)

На старых дистрибутивах оценка делается вручную. Базовая формула для x86_64: 160 MB плюс 2 бита на каждые 4 KB RAM. На сервере с 128 гигабайтами памяти это 160 MB плюс 64 MB, итого 224 MB только за счёт карты памяти. К этому прибавляются модули ядра, которые capture-ядро загружает для доступа к хранилищу: если сервер использует сложный RAID-контроллер или InfiniBand, capture-ядру нужно загрузить соответствующие драйверы, и каждый из них занимает свою долю зарезервированной памяти.

# Оценить потребность в памяти через kdumpctl на Fedora/RHEL 9+
kdumpctl reset-crashkernel --kernel=ALL

# На RHEL 8 и старше
kdumpctl estimate

# Проверить текущее использование памяти capture-ядром
# (запускается только если kdump уже загружен)
cat /sys/kernel/kexec_crash_size

Диапазонный синтаксис crashkernel позволяет задать разные значения для разных объёмов RAM в одной записи и является предпочтительным для гетерогенных кластеров:

# Диапазонный синтаксис для разных конфигураций RAM
# До 4GB: 128MB, от 4GB до 64GB: 256MB, свыше 64GB: 512MB
crashkernel=1G-4G:128M,4G-64G:256M,64G-:512M

# Применить через grubby (RHEL/Fedora)
grubby --update-kernel=ALL \
--args="crashkernel=1G-4G:128M,4G-64G:256M,64G-:512M"

# Или через grub на Debian/Ubuntu
# В /etc/default/grub:
GRUB_CMDLINE_LINUX="crashkernel=1G-4G:128M,4G-64G:256M,64G-:512M"
update-grub

Параметры capture-ядра и сокращение потребления памяти при загрузке

Capture-ядро загружается с набором параметров, которые передаются при загрузке kdump-сервисом. По умолчанию эти параметры скопированы из основного ядра, но многие из них для capture-ядра просто не нужны и только занимают память при инициализации подсистем.

Посмотреть текущие параметры загрузки capture-ядра:

# На RHEL/Fedora
cat /etc/sysconfig/kdump | grep KDUMP_COMMANDLINE

# На Debian/Ubuntu
cat /etc/default/kdump-tools | grep KDUMP_CMDLINE

Несколько параметров, которые напрямую снижают потребление памяти capture-ядром. Параметр nr_cpus=1 запрещает capture-ядру инициализировать все процессорные ядра кроме одного. SMP-инициализация требует памяти на структуры данных для каждого CPU. Если в системе 64 ядра, отключение 63 из них даёт заметную экономию. Параметр irqpoll включает режим опроса прерываний вместо стандартной архитектуры, что делает capture-ядро менее требовательным к инициализации APIC:

# Пример оптимизированных параметров capture-ядра в /etc/sysconfig/kdump
KDUMP_COMMANDLINE_APPEND="nr_cpus=1 irqpoll maxcpus=1 \
reset_devices numa=off udev.children-max=2 \
rd.udev.children-max=2 \
rd.driver.blacklist=nouveau,radeon,drm_kms_helper \
acpi_no_memhotplug cgroup_disable=memory \
nokaslr console=tty0"

Параметр cgroup_disable=memory отключает подсистему контрольных групп по памяти, которая в capture-ядре абсолютно не нужна, но при инициализации выделяет структуры данных. acpi_no_memhotplug отключает поддержку горячего подключения памяти, которая при инициализации занимает ресурсы. rd.driver.blacklist исключает загрузку графических драйверов, которые capture-ядру никогда не понадобятся, но initrd по умолчанию может попытаться их загрузить.

Параметр numa=off заслуживает отдельного упоминания. На NUMA-серверах с множеством узлов памяти инициализация NUMA-топологии требует выделения структур для каждого узла. Capture-ядро работает на единственном CPU и не нуждается в NUMA-aware аллокации, поэтому отключение NUMA в capture-ядре снижает потребление памяти при инициализации.

Минимальная сборка capture-ядра и отличие от production-ядра

Это самая радикальная оптимизация, но при этом самая эффективная. Production-ядро собирается с сотнями модулей: поддержка Bluetooth, Wi-Fi, USB-гаджеты, звуковые карты, графические подсистемы, десятки сетевых протоколов. Серверу, который сохраняет дамп на локальный диск, из всего этого нужны только драйвер хранилища и файловая система.

Минимальная конфигурация capture-ядра для x86_64. Ключевые флаги, без которых kdump работать не будет:

# Минимально необходимые опции для capture-ядра
CONFIG_CRASH_DUMP=y # Поддержка снятия дампа
CONFIG_RELOCATABLE=y # Перемещаемое ядро (обязательно)
CONFIG_PROC_VMCORE=y # Доступ к /proc/vmcore
CONFIG_KEXEC=y # Поддержка kexec

# Для доступа к хранилищу (пример для SATA)
CONFIG_ATA=y
CONFIG_ATA_PIIX=y
CONFIG_EXT4_FS=y

# Минимальная сеть (если дамп сохраняется по SSH)
CONFIG_ETHERNET=y
CONFIG_E1000E=y # Заменить на нужный драйвер NIC

# Явно отключить лишнее
CONFIG_SOUND=n
CONFIG_BT=n
CONFIG_USB_SUPPORT=n
CONFIG_WIRELESS=n
CONFIG_DRM=n
CONFIG_FB=n
CONFIG_INFINIBAND=n

Разница в размере между полным дистрибутивным ядром и минимальным capture-ядром может составлять 30-50 мегабайт только для самого бинарника vmlinuz. Но важнее другое: минимальное ядро загружает меньше модулей при старте, что снижает пиковое потребление памяти в момент инициализации capture-окружения.

Убедиться, что capture-ядро загружено и готово:

# Статус kdump-сервиса
systemctl status kdump

# Проверить что capture-ядро загружено в память
cat /sys/kernel/kexec_crash_loaded # должно быть 1

# Какой образ используется как capture-ядро
ls -lh /boot/initramfs-$(uname -r)kdump.img
file /boot/initramfs-$(uname -r)kdump.img

makedumpfile и фильтрация страниц памяти

Оптимизация резервации это только одна сторона задачи. Вторая сторона, размер итогового файла дампа. На сервере с 256 GB памяти полный vmcore будет занимать 256 GB на диске. Это неприемлемо по двум причинам: время записи и требования к хранилищу.

makedumpfile решает эту задачу через два механизма: исключение ненужных страниц памяти и компрессию. Перед настройкой фильтрации разумно сначала понять структуру памяти на конкретной системе:

# Оценить потенциальный размер дампа при разных уровнях фильтрации
makedumpfile --mem-usage /proc/kcore

Вывод покажет таблицу с типами страниц и их объёмом. Типичный результат на production-сервере выглядит примерно так:

TYPE PAGES EXCLUDABLE DESCRIPTION
ZERO 8541200 yes Страницы заполненные нулями
CACHE 892340 yes Страницы кэша файлов
CACHE_PRIV 43210 yes Приватные страницы кэша
USER 187650 yes Страницы пользовательских процессов
FREE 52341200 yes Свободные страницы
KERN_DATA 1893450 no Данные ядра (обязательны для анализа)

Свободные страницы и страницы заполненные нулями занимают абсолютное большинство памяти и не несут никакой диагностической ценности. Именно поэтому уровень фильтрации -d 31 является стандартной рекомендацией для большинства сценариев.

Логика уровней фильтрации makedumpfile строится на битовой маске:

Бит 0 (1) = исключить нулевые страницы
Бит 1 (2) = исключить кэш-страницы
Бит 2 (4) = исключить приватные страницы кэша
Бит 3 (8) = исключить страницы пользовательских процессов
Бит 4 (16) = исключить свободные страницы
Итого -d 31 = 1+2+4+8+16 = все исключаемые страницы

Конфигурация makedumpfile в /etc/kdump.conf для разных сценариев:

# Стандартная конфигурация: lzo-компрессия, уровень фильтрации 31
core_collector makedumpfile -l --message-level 1 -d 31

# Максимальная компрессия через zlib (медленнее, но меньше)
core_collector makedumpfile -c --message-level 1 -d 31

# Быстрая компрессия через snappy (быстрее, чуть хуже ratio)
core_collector makedumpfile -p --message-level 1 -d 31

# Только данные ядра, без каких-либо страниц пользователя,
# кэша и свободных: минимальный размер дампа
core_collector makedumpfile -l --message-level 1 -d 31 \
--exclude-xen-dom0

Проверить оценку итогового размера дампа при текущих настройках фильтрации без реального снятия дампа:

makedumpfile --mem-usage /proc/kcore \
| awk 'NR>2 && $3=="yes" {sum += $2} END \
{print "Исключаемые страницы: " sum*4/1024 " MB"}'

Сохранение дампа по SSH и параллельная запись

Локальный диск не всегда является надёжным местом для хранения дампа: если паника вызвана проблемой с дисковым контроллером, попытка записать дамп на этот же диск может завершиться неудачей. Сохранение по SSH на отдельный сервер решает эту проблему, но добавляет требование сетевой инициализации в capture-ядре.

# Создать выделенный SSH-ключ для kdump без пароля
ssh-keygen -t ed25519 -f /root/.ssh/kdump_id_ed25519 -N ""
ssh-copy-id -i /root/.ssh/kdump_id_ed25519 \
backup@dump-server.internal

# Настроить в /etc/kdump.conf
ssh backup@dump-server.internal
sshkey /root/.ssh/kdump_id_ed25519
path /var/crash
core_collector makedumpfile -F -l --message-level 1 -d 31

Флаг -F в makedumpfile включает вывод в flattened-формат на стандартный вывод, который через pipe передаётся в SSH. Это позволяет начать передачу данных немедленно, не дожидаясь завершения записи на локальный диск. На серверах с медленным хранилищем и быстрой сетью это принципиально сокращает время снятия дампа.

Для систем с очень большим объёмом памяти makedumpfile поддерживает параллельное разбиение дампа на несколько файлов:

# Разбить дамп на 4 файла для параллельной записи на разные устройства
makedumpfile --split -d 31 -x /usr/lib/debug/boot/vmlinux-$(uname -r) \
/proc/vmcore \
/mnt/disk1/dump1 /mnt/disk2/dump2 \
/mnt/disk3/dump3 /mnt/disk4/dump4

# Использовать несколько потоков для компрессии
makedumpfile --num-threads 4 -l -d 31 \
-x /usr/lib/debug/boot/vmlinux-$(uname -r) \
/proc/vmcore /var/crash/vmcore

Тестирование и верификация конфигурации в продакшене

Самая опасная ошибка при работе с kdump: считать, что раз сервис запущен и не выдаёт ошибок, значит дамп будет снят успешно. На практике это не так. Неправильный размер резервации, несовместимая версия makedumpfile с ядром, отсутствие нужных модулей в capture-ядре, нехватка места на целевом хранилище, всё это обнаруживается только при реальном снятии дампа.

Тестирование kdump разрушительно: оно вызывает kernel panic и перезагрузку. Поэтому его проводят только в обслуживании или на специально выделенных тестовых машинах. Никогда на активных production-системах с работающей нагрузкой.

# ТОЛЬКО В ОКНЕ ОБСЛУЖИВАНИЯ
# Метод 1: через sysrq
echo 1 > /proc/sys/kernel/sysrq
echo c > /proc/sysrq-trigger

# Метод 2: через Magic SysRq по Alt+SysRq+c (физический доступ)

# После перезагрузки проверить результат
ls -lh /var/crash/
journalctl -b -1 | grep -i kdump

# Верифицировать целостность дампа
makedumpfile --check-params /var/crash/*/vmcore

После успешного тестового дампа обязательно проверить, что файл читаем инструментом анализа:

# Установить crash и debuginfo
dnf install crash kernel-debuginfo-$(uname -r)

# Открыть дамп
crash /usr/lib/debug/boot/vmlinux-$(uname -r) \
/var/crash/$(ls -t /var/crash | head -1)/vmcore

# Внутри crash: базовые проверки
# crash> bt <- stack trace
# crash> log <- kernel ring buffer
# crash> ps <- список процессов в момент краша
# crash> quit

Если crash успешно открывает дамп и показывает стек трейс, конфигурация kdump работает корректно. Если дамп не читается или неполный, уровень фильтрации слишком агрессивен и нужно снизить значение -d: например, перейти с 31 на 17, исключив только свободные страницы и нулевые, но оставив кэш и пользовательские данные.

Баланс между минимальной резервацией памяти и надёжностью capture-процесса требует однократного измерения на каждом классе серверов и периодической верификации после крупных обновлений ядра. Система с недостаточной резервацией памяти для kdump это система, которая в момент наибольшей необходимости тихо потеряет дамп и оставит инженера один на один с пустым /var/crash и вопросом, что же произошло.

https://fileenergy.com/linux