В этом уроке разберёмся, что такое eBPF на пальцах, почему это считают прорывом, и подойдём вплотную к инструментам bcc и bpftrace, которыми ты будешь пользоваться руками уже в следующих уроках. Актуально на 2026 год: eBPF давно перестал быть экзотикой и стал стандартным слоем диагностики в Linux.
Что такое eBPF и почему это прорыв
Если совсем коротко: eBPF (extended Berkeley Packet Filter) - это способ запускать твои маленькие программы внутри ядра в ответ на события. Произошёл системный вызов, прилетел сетевой пакет, ядро зашло в свою функцию - и в этот момент срабатывает твой кусочек кода. Он что-то считает, фильтрует, агрегирует и отдаёт результат наружу. Название историческое: когда-то "BPF" был крошечным фильтром пакетов для tcpdump, но "extended"-версия разрослась далеко за пределы сети.
Аналогия. Раньше, чтобы понять, что творится в ядре, у тебя было два пути. Либо лезть с инструментом снаружи (strace, tcpdump) - это как стоять у двери магазина и записывать каждого входящего, чтобы потом руками посчитать выручку. Дорого, медленно, мешает работе. Либо патчить само ядро и пересобирать - это как ломать стену магазина, чтобы поставить камеру. Опасно и долго.
eBPF - это третий путь. Ядро само пускает внутрь маленького доверенного "наблюдателя", который сидит прямо на кассе и сразу говорит тебе итоговую цифру. Никаких стен ломать не надо, наблюдатель проверен на безопасность, и работает он почти бесплатно по нагрузке.
Ключевое отличие ebpf трассировки от старого strace вот в чём. strace ловит каждый syscall через ptrace и гонит сырой поток в userspace, дважды переключая контекст на каждый вызов - на нагруженном процессе это замедление в разы, иногда в десятки раз. А eBPF-программа считает прямо в ядре: тебе наружу падает уже готовая статистика - гистограмма задержек, счётчик по процессам, топ функций. Данные не покидают ядро без нужды, и overhead падает на порядки. Именно поэтому eBPF не боятся запускать на боевом трафике, а strace на проде - почти всегда плохая идея.

Как это устроено: события, верификатор, карты
Чтобы bpf в linux не превратился в дыру размером с ядро, придумали жёсткую механику. Разберём по частям.
События (хуки) - к чему цепляется программа. eBPF-программу можно повесить на разные точки:
- kprobe / kretprobe - вход и выход почти любой функции ядра. Динамически, без перекомпиляции. Хочешь знать, кто вызывает vfs_read - вешаешь kprobe.
- uprobe / uretprobe - то же самое, но для функций в пользовательских программах и библиотеках (например, поймать вызов в libc, в OpenSSL или в твоём бинарнике).
- tracepoint - заранее размеченные ядром стабильные точки (syscalls, планировщик, блочный слой). Надёжнее kprobe, потому что не зависят от имён внутренних функций между версиями ядра.
- fentry / fexit - современная замена kprobe (с ядра 5.5), быстрее и с типизированным доступом к аргументам через BTF. На 2026 для трассировки функций ядра это предпочтительный механизм там, где он доступен.
- perf events - аппаратные и софтверные счётчики, сэмплирование по таймеру (основа для профилирования и флеймграфов).
- USDT - статические точки трассировки внутри приложений (есть в JVM, в libc, в PostgreSQL и т.д.).
- XDP / TC - сетевые хуки на самом раннем этапе обработки пакета. На этом строят фильтрацию, балансировку, защиту от DDoS.
Карты (maps) - как данные попадают наружу. eBPF-программа сама по себе не печатает текст. Она складывает результаты в специальные структуры - eBPF maps (хеш-таблицы, массивы, кольцевые буферы). А userspace-утилита читает их и рисует тебе человеческий вывод. Именно так считалка живёт в ядре, а ты видишь готовую гистограмму. Современный канал передачи событий наружу - BPF ring buffer (с ядра 5.8), он эффективнее и проще старых per-CPU perf-буферов.
JIT. Загруженный байткод ядро компилирует JIT-ом в нативные инструкции процессора, поэтому он бежит на скорости обычного кода ядра, а не интерпретируется.
Экосистема: bpftrace, bcc, libbpf - чем работать руками
Голый eBPF-байткод руками никто не пишет. Есть удобные обёртки.
bpftrace - язык одной строкой, вдохновлённый awk и DTrace. Идеален для быстрых разовых вопросов "а что сейчас происходит". На 2026 актуальны версии ветки 0.2x. Сначала посмотри своё "меню" событий:
Код: Выделить всё
sudo bpftrace -l 'tracepoint:syscalls:*' | head
# выведет список доступных tracepoint-ов - это твоё "меню" событий
Код: Выделить всё
sudo bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @[comm] = count() }'
Код: Выделить всё
@[systemd]: 412
@[sshd]: 1530
@[nginx]: 88204
Гистограмма задержки чтения по процессам:
Код: Выделить всё
sudo bpftrace -e 'tracepoint:syscalls:sys_exit_read { @[comm] = hist(args.ret) }'
Код: Выделить всё
sudo bpftrace -lv tracepoint:syscalls:sys_enter_openat
Код: Выделить всё
sudo bpftrace -e 'tracepoint:syscalls:sys_enter_openat { printf("%-16s %s\n", comm, str(args.filename)) }'
Код: Выделить всё
sudo apt install bpfcc-tools
# на RHEL/Fedora: sudo dnf install bcc-tools
- execsnoop - показывает каждый новый процесс (вызов exec). Ловит "кто это запустил странный скрипт".
- opensnoop - какие файлы кто открывает прямо сейчас.
- biolatency - гистограмма задержек блочного ввода-вывода (диск тормозит или нет).
- tcpconnect / tcpaccept / tcplife - кто куда коннектится, кто к тебе, и сколько живут соединения.
- runqlat - задержка в очереди планировщика (процессы голодают по CPU?).
- profile - сэмплирующий профайлер стеков, основа для флеймграфов.
Код: Выделить всё
PCOMM PID PPID RET ARGS
bash 8112 8110 0 /usr/bin/ls --color=auto
curl 8120 8112 0 /usr/bin/curl http://example.com
libbpf + CO-RE - это "взрослый" способ писать переносимые eBPF-программы на C, которые компилируются один раз и работают на разных ядрах (Compile Once - Run Everywhere) за счёт BTF (формата типов ядра). Это уже для разработки своих инструментов и продуктов наблюдаемости. На 2026 именно libbpf+CO-RE - индустриальный стандарт: на нём построены и libbpf-tools, и большинство коммерческих eBPF-агентов.
Требования к ядру и где это применяют
eBPF появился в ядре 4.x, но для нормальной жизни с bcc/bpftrace ориентируйся на ядро 5.x, а лучше 5.15 LTS и новее. На 2026 в свежих дистрибутивах уже встречаются 6.x вплоть до 6.12 LTS - там eBPF в полном расцвете. Ключевые вехи: BTF - с 5.2, ограниченные циклы - с 5.3, fentry/fexit - с 5.5, кольцевой буфер (ring buffer) - с 5.8, kfuncs - с 5.13. Проверить версию и наличие BTF:
Код: Выделить всё
uname -r
# есть ли BTF (нужен для CO-RE-инструментов):
ls /sys/kernel/btf/vmlinux && echo "BTF есть"
Код: Выделить всё
sudo bpftool feature probe | head -n 30
Где eBPF используют в реальном мире, помимо трассировки: сеть (XDP - сверхбыстрая фильтрация пакетов, основа Cilium для Kubernetes и kube-proxy без iptables), безопасность (детект подозрительных syscall-ов в рантайме - Falco, Tetragon), профилирование (непрерывный сбор стеков, continuous profiling - Parca, Pyroscope), наблюдаемость без инструментирования кода (Pixie, Coroot). Одна технология - сразу несколько огромных областей.
Типичные грабли и заблуждения
- "eBPF заменяет strace/tcpdump полностью". Нет. Для разового "что вызывает программа один раз" strace проще и нагляднее. eBPF выигрывает на нагрузке и на агрегации, а не везде подряд. Хотя для долгих наблюдений на проде - почти всегда eBPF.
- "Можно запускать без root". В общем случае - нет. Загрузка большинства программ требует CAP_BPF (плюс часто CAP_PERFMON / CAP_NET_ADMIN под задачу) или CAP_SYS_ADMIN, поэтому на практике sudo. Unprivileged-режим (sysctl kernel.unprivileged_bpf_disabled) на современных дистрибутивах по умолчанию выключен из соображений безопасности - и обратно его в работающем ядре уже не включить.
- "kprobe на любую функцию вечны". Имена внутренних функций ядра меняются между версиями, а часть функций инлайнится и пропадает. Скрипт на kprobe:vfs_read может сломаться после апдейта. Где есть tracepoint - бери tracepoint, они стабильны как ABI.
- "Verifier отклонил - это баг ядра". Чаще это ты пытаешься сделать что-то небезопасное (цикл без видимой границы, доступ к полю без проверки на NULL, слишком большой стек). Читай его сообщение целиком - он подсказывает инструкцию и причину.
- "Overhead нулевой". Почти нулевой, но не магия. Повесь kprobe на горячую функцию, которая зовётся миллионы раз в секунду, - почувствуешь. Сначала меряй на узких событиях и по возможности фильтруй прямо в обработчике.
Нужна машина с современным ядром (5.15+) и sudo. По шагам:
- Поставь инструменты: (или dnf-аналог).
Код: Выделить всё
sudo apt install bpfcc-tools bpftrace - Проверь версию ядра и BTF:
Код: Выделить всё
uname -r; ls /sys/kernel/btf/vmlinux - Запусти в одном терминале , а в другом выполни любую команду (ls, curl). Найди свою команду в выводе, сопоставь PID и PPID.
Код: Выделить всё
sudo execsnoop-bpfcc - Посчитай syscall-ы по процессам: - дай поработать пару секунд, Ctrl-C, найди самый "болтливый" процесс.
Код: Выделить всё
sudo bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @[comm] = count() }' - Отфильтруй по одному процессу (отвечаем на вопрос из комментариев): - выражение в /.../ это фильтр-предикат, считаем только для nginx.
Код: Выделить всё
sudo bpftrace -e 'tracepoint:raw_syscalls:sys_enter /comm == "nginx"/ { @[probe] = count() }' - Посмотри список доступных событий: - удивись, сколько точек наблюдения у тебя под рукой.
Код: Выделить всё
sudo bpftrace -l | wc -l
- Чем принципиально отличается сбор данных eBPF от strace - почему overhead ниже?
- Зачем нужен верификатор и что он гарантирует перед загрузкой программы?
- В чём разница между kprobe и tracepoint, и почему для стабильных скриптов предпочитают tracepoint (и чем тут помогает fentry)?
- Какая роль у eBPF maps и ring buffer - как результат из ядра попадает к тебе на экран?
eBPF - это программируемая наблюдаемость: твой безопасный код бежит в ядре в ответ на события, считает и фильтрует на месте и отдаёт наружу готовую статистику, а не сырой поток. Безопасность обеспечивает верификатор, скорость - JIT, данные ходят через maps и ring buffer. На практике ты работаешь не с байткодом, а с bpftrace (быстрые однострочники) и bcc/libbpf-tools (готовые инструменты вроде execsnoop, opensnoop, biolatency, runqlat). Нужно ядро 5.15+ с BTF, доступ - через sudo. Это не просто ещё одна утилита - это фундамент, на котором на 2026 год держатся и трассировка, и сетевой стек, и безопасность Linux.