Зачем администратору eBPF
В реальном продакшене у нас мало времени и нулевой допуск к экспериментам: нельзя останавливать службы, нельзя перезагружать ядро, и каждый процент overhead важен. eBPF как раз про это: с его помощью мы можем точечно наблюдать системные события на уровне ядра и user‑space с минимальными накладными, приближаясь к «рентгену» Linux без инвазивной отладки. Инструменты bcc и bpftrace закрывают большинство сценариев диагностики: от профилирования CPU до поиска узких мест диска и сети.
В этой статье — практический набор готовых one‑liners для быстрого анализа инцидентов. Я делаю упор на команды, которые можно безопасно запускать на живых серверах, а также на то, как читать их вывод и какие решения принимать.
bcc и bpftrace: что выбрать
bcc — набор готовых утилит на Python/C для типовых задач. Они стабильны, проверены временем и подходят, когда важна «боеготовность»: взял и запустил. bpftrace — это «awk для eBPF»: мощный язык одноразовых скриптов и статистики. Там, где библиотечной утилиты нет, выручит краткий скрипт на bpftrace.
- Выбирайте bcc, если вам нужна известная утилита:
profile,runqlat,biolatency,tcpretrans,opensnoop,execsnoop,oomkill,cachestat,ext4slowerи десятки других. - Выбирайте bpftrace, если нужно быстро собрать нестандартную метрику: например, гистограмму задержек конкретного системного вызова в определённом процессе, или объединить ядро и userspace‑стек.
На практике оба инструмента дополняют друг друга. Начинаем с bcc, а при необходимости допиливаем измерение bpftrace-ом.

Подготовка сервера: ядро, пакеты, доступ
Минимум усилий — максимум совместимости дают ядра 5.x с BTF. На старых 4.9+ большинство утилит тоже работает, но часть расширенных возможностей может быть недоступна.
Установка пакетов
Debian/Ubuntu:
apt update
apt install -y bpfcc-tools bpftrace linux-headers-$(uname -r)
RHEL/AlmaLinux/Rocky (версиям понадобится EPEL):
yum install -y bcc-tools bpftrace kernel-headers
Права: большинство команд требуют root. Можно тонко выдать возможности через CAP (например, CAP_BPF и CAP_SYS_ADMIN), но в аварийной практике проще запускать от root и ограничивать время работы инструментов.
Если у вас окружение без root или нужного ядра (общий хостинг, строгие политики), проще поднять стенд или перенести сервис на VDS, где вы контролируете ядро и пакеты. При выборе конфигурации пригодится материал как выбрать конфигурацию VDS по CPU и RAM.
Безопасность и накладные расходы
- Запускайте точечно и недолго: 15–60 секунд на сбор «среза» почти всегда хватает, чтобы понять картину.
- Сэмплирующее профилирование (
profile 99Hz) обычно даёт менее 1–3% CPU overhead на загруженном хосте. Трассировки на событиях ядра обычно ещё легче. - Сужайте область: фильтры по PID/имени процесса/порту/устройству резко снижают нагрузку и мусор.
- Предпочитайте гистограммы и агрегаты, а не потоковые «логи каждого события», если задача — обзор.
Главное правило: короткие измерения, строгие фильтры, понятная цель. Вы пришли за ответом «где узкое место», а не за гигабайтами сырых событий.
Базовый сценарий диагностики
- Сформулируйте симптом: «CPU 100%», «рост latency HTTP», «высокий IOwait», «ретрансмиты TCP», «много open()».
- Выберите 1–2 подходящих one‑liner и запустите на 30–60 секунд.
- Сохраните вывод в файл, остановите, сделайте короткие выводы, примите меры.
- Повторите после изменения (например, снизили число воркеров — сравните профили до/после).
CPU: кто жрёт и почему
Сэмплирующий профиль CPU (системно)
Когда загрузка CPU высока, начните с общего профиля. Он покажет горячие стеки ядра и/или user‑space.
bcc:
profile -F 99 -a -d 30
Смысл: частота 99 Гц, все процессы, длительность 30 секунд. На выходе — «свернутые» стеки и счётчики. Ищите «горячие» пути: функции хеш‑таблиц, JSON‑парсеры, TLS, сжатие, регулярки, блокировки.
bpftrace (ядро):
bpftrace -e 'profile:hz:99 { @[kstack] = count(); } interval:s:30 { exit(); }'
Если вас интересует конкретный процесс, используйте фильтр по PID:
profile -F 99 -p PID -d 30
Либо в bpftrace добавьте условие:
bpftrace -e 'profile:hz:99 /pid == PID/ { @[ustack] = count(); } interval:s:30 { exit(); }'
Интерпретация: «горячие» пользовательские функции показывают, где именно тратится время. Если стеки в основном в ядре — смотрите планировщик (run queue), контенцию, сетевой или дисковый путь.
Очередь планировщика: ждём CPU
Если load average выше числа ядер, это может быть как CPU‑bound, так и ожидание CPU. Проверьте латентность и длину очереди.
bcc:
runqlat 1 10
runqlen 1 10
runqlat даёт гистограмму задержек, runqlen — длину очереди. Если хвосты задержек больше 1–2 мс под нагрузкой — признак конкуренции за CPU или приоритетов.
OFF‑CPU: где ждём и на что блокируемся
OFF‑CPU время — когда поток не на CPU, а ждёт: мьютексы, I/O, условные переменные. Это ключ к «странным» задержкам при низком CPU.
bcc (весь хост):
offcputime -f 30
Фильтр по процессу:
offcputime -p PID -f 30
Смотрите стеки: блокировки в libc/pthread, ожидание сокета, дисковые вызовы. Часто «золотая находка» — конкретный мьютекс или функция ожидания в вашем приложении.
Диск: задержки, кэши, FS
Гистограмма задержек блочного I/O
Когда растёт IOwait или замедляются операции БД/файловой системы, начните с общей картины задержек.
bcc:
biolatency 1 10
Смотрите распределение по корзинам (микро/миллисекунды). Хвосты больше 10–50 мс — признак проблем нижележащего слоя: перегрузка устройства, очереди, конкуренция. Дополнительно — «кто» делает I/O:
biosnoop
biosnoop выведет PID/процесс, LBA, размер и задержку. Сужайте фильтрами по PID или устройству при необходимости.
Кэш страницы: промахи и эффективность
Плохой hit‑ratio page cache приводит к лишним чтениям с диска. Исследуем кэш.
bcc:
cachestat 1 10
На выходе будет число обращений, hit/miss, размеры. Если доля промахов велика и растёт, проверьте объёмы активных данных, рабочие наборы и настройки памяти.
Файловая система: медленные операции
Нужно понять, что именно тормозит на уровне FS (например, ext4).
bcc:
ext4slower 1
ext4dist 1 10
ext4slower покажет «медленные» операции (обычно больше 10 мс), ext4dist — распределение задержек по типам событий FS. Для XFS аналогично есть xfsdist/xfsslower (если доступно).

Сеть: коннекты, accept, ретрансмиты
Новые TCP‑соединения и задержки
Рост latency приложений часто связан не только с CPU/диском, но и сетью: медленные connect(), backlog, SYN‑всплески в легитимном трафике или избыточные ретрансмиты.
bcc (исходящие connect()):
tcpconnect
Для входящих соединений на сервере веб/бэкенда:
tcpaccept
Параметры утилит позволяют фильтровать по порту/процессу. Обращайте внимание на всплески и время до установления соединения.
Ретрансмиты TCP
Высокий процент ретрансмитов — явный сигнал проблем на сети: перегрузка очередей, плохие каналы, настройки TCP или MTU.
bcc:
tcpretrans
Смотрите источник/назначение, процессы и частоту событий. В паре с системными счётчиками это даёт быстрое понимание динамики.
Файлы и процессы: кто открывает, кто запускается
opensnoop: кто к чему тянется
«Странные» задержки часто связаны с большим числом open() (шаблоны, статики, логи). Проверим.
bcc:
opensnoop
Фильтр по процессу:
opensnoop -n nginx
Смотрите ошибки, частоту, пути. Если приложение мячит тысячи мелких открытий, подумайте об агрегации, кэше дескрипторов, предзагрузке или конфигурации пула воркеров. Для PHP‑фронтов может пригодиться и slowlog PHP‑FPM — см. практику в отдельной статье.
execsnoop: частые spawn/exec
Чрезмерные запуски процессов добавляют накладные и давление на планировщик/диск. Быстрый просмотр:
execsnoop
Если видите неожиданно частые cron‑задачи, shell‑обёртки или вспомогательные бинарники — это повод пересмотреть архитектуру (демоны, пулы, долгоживущие процессы).
Память: OOM и давление
oomkill: кто стал жертвой
Когда система уходит в OOM, важно быстро понять, кого убили и при каких условиях. Утилита покажет событие из ядра.
bcc:
oomkill
Дальше анализируйте логи приложения, лимиты cgroup и настройки ядра. Частые OOM — триггер к ревизии лимитов, утилизации Swap/zram, профилирования памяти приложения. Практические шаги см. в материале лимиты памяти и CPU в systemd.
Симптом‑ориентированные рецепты
HTTP 5xx/таймауты растут, CPU низкий
runqlat/runqlen— исключите ожидание CPU.tcpretrans— проверьте сеть.biolatencyиext4slower— ищите хвосты диска.offcputime -p PIDпо основному воркеру — смотрите блокировки/ожидания.opensnoop -n nginx— нет ли штормов на файловой системе (например, логротация, частыеstat/openшаблонов).
CPU 100%, но медленно
profile -F 99 -a -d 30— найдите «горячие» функции. Это может быть парсинг JSON, сжатие, криптография, неудачные регулярные выражения.offcputime -p PID -f 30— покажет, что часть времени уходит в ожидание мьютексов, диска или сети, даже если CPU «на крыше» из‑за других потоков.- Если ядро в топе — проверьте сетевой/дисковый стеки, прерывания, копирование данных.
Высокий IOwait
biolatency 1 10— распределение задержек I/O.biosnoop— «кто» именно делает запросы.cachestat 1 10— промахи кэша страниц.ext4slower/xfsdist— уровень FS, медленные операции.
Всплески latencies на бэкенде
tcpacceptиtcpconnect— задержки установления соединений.tcpretrans— спайки ретрансмитов.runqlat— исключить, что «потеет» планировщик.
bpftrace: микро‑скрипты под задачу
Когда готовой утилиты нет, bpftrace выручит. Ниже — несколько полезных шаблонов.
Гистограмма задержек системного вызова read() для процесса PID
bpftrace -e 'kprobe:__x64_sys_read /pid == PID/ { @ts[tid] = nsecs; } kretprobe:__x64_sys_read /@ts[tid]/ { @usec = hist((nsecs - @ts[tid]) / 1000); delete(@ts[tid]); } interval:s:30 { print(@usec); clear(@usec); exit(); }'
Интерпретация: если хвосты задержек велики, а biosnoop показывает активный диск — bottleneck на I/O. Если cachestat говорит об избытке промахов — не помещается рабочий набор или есть «пилообразная» нагрузка, вымывающая кэш.
Счётчик частых вызовов write() по файлам (path в аргументах)
Агрегируем по comm и грубо по дескриптору (для детального path потребуется дополнительная логика), но для быстрой оценки частоты хватает:
bpftrace -e 'kprobe:__x64_sys_write { @[comm] = count(); } interval:s:30 { print(@); clear(@); exit(); }'
Если видите тысячи write() в секунду от веб‑воркеров по мелочи — подумайте о буферизации, batch‑логировании, настройках fsync/flush в приложении и ротации логов.
Кто часто делает connect() на определённый порт
bpftrace -e 'tracepoint:syscalls:sys_enter_connect { @ = count(); } tracepoint:syscalls:sys_enter_connect /args->addrlen == 16/ { @[comm] = count(); } interval:s:30 { print(@); clear(@); exit(); }'
Смысл: смотрим динамику connect, разбивку по процессам. Помогает ловить «шторм» исходящих коннектов на соседний сервис.
Практика чтения выходных данных
eBPF‑инструменты часто дают гистограммы (логарифмические дайджесты) или свёрнутые стеки. Несколько практических советов:
- Сравнивайте «до/после»: запуск того же one‑liner после правки конфигурации — лучший валидатор гипотезы.
- Не пугайтесь единичных больших «хвостов»: важны устойчивые хвосты, а не разовые пики.
- Если «горячий» путь — библиотечная функция (например, zlib), рассмотрите отключение/перенастройку сжатия или перенос нагрузки на другой узел.
- OFF‑CPU стеки часто показывают тип блокировки/ожидания. Это подсказка к параметрам пула, размерам очередей, объектным кэшам.
Контейнеры, cgroup и namespaces
Запуская eBPF‑диагностику на хосте, помните, что видите всё сразу, включая контейнеры. Чтобы сузить область до конкретного сервиса, фильтруйте по PID (из docker top или crictl), по имени процесса или по cgroup‑пути, если утилита поддерживает.
Некоторые bcc‑утилиты умеют показывать cgroup в выводе, но если нет — используйте фильтры на стороне инструмента или предварительно определите PID лидера нужного контейнера и трассируйте его.
Подводные камни и совместимость
- Версии ядра: имена символов и tracepoint‑поля меняются. Если one‑liner не срабатывает, проверьте вывод ошибки и адаптируйте имя события.
- Символы/стек: для читаемых user‑space стеков нужны дебажные символы и/или
perf map. Без них увидите адреса — это всё равно полезно для относительного профиля. - Анти‑шум: фильтры по
pid,comm, порту и устройству резко повышают ценность данных. - Права: в средах с жёсткими политиками безопасности eBPF может быть ограничён. Планируйте диагностику заранее, держите инструменты на сервере.
Чеклист «быстрый старт» для дежурного
- CPU «горит» —
profile -F 99 -a -d 30; затем прицельно —offcputime -p PID -f 30. - Высокий IOwait —
biolatency 1 10,biosnoop,cachestat 1 10,ext4slower. - HTTP тормозит —
tcpaccept,tcpconnect,tcpretrans, плюс проверка run queue. - Много мелких файловых операций —
opensnoop -n app, подумайте об агрегации и кэше. - Случился OOM —
oomkill, затем аудит лимитов и профилирование памяти приложения.
Как превратить находки в действия
- CPU‑bound: оптимизация кода «горячих» функций, включение JIT/кэша, уменьшение частоты сериализаций/сжатий, распараллеливание.
- OFF‑CPU блокировки: настройка размеров пулов, разделение очередей по типу задач, уменьшение контенции (lock‑sharding), пересмотр критических секций.
- Диск: повышение параллелизма I/O с лимитами, переход на более быстрый класс дисков, оптимизация паттернов доступа (батчи, seq‑чтения), увеличение RAM для page cache.
- Сеть: снижение ретрансмитов через настройки TCP, устранение узких мест на путях, балансировка нагрузок, проверка MTU.
Заключение
eBPF даёт системному администратору и девопсу инструмент класса «рентген» для продакшена: запустили короткую команду, получили измерения на уровне ядра, приняли решение. Набор из десятка one‑liners bcc и пары заготовок bpftrace покрывает 80% инцидентов: CPU, планировщик, диск, сеть, файлы и память. Остальные 20% решаются точечными микро‑скриптами и аккуратной интерпретацией данных.
Поддерживайте инструменты в образе, тренируйте команду на стендах, и в реальный инцидент у вас будут и навыки, и готовые команды. Чем короче путь от симптома до метрики, тем быстрее вы вернёте сервис к нормальной работе.


