eBPF vs BitDive: Сравнение решений для системного и прикладного профилирования
Разбираем разницу между eBPF и BitDive: системное профилирование против глубокого анализа Java-приложений. Что выбрать для продакшена?
Зачем вообще нужен профайлинг в проде?
Производительность приложений — не абстракция. Это ошибки, таймауты, утекающие пользователи и ненужные расходы. Но чтобы понять, что именно тормозит, мало просто знать, что "CPU загружен". Нужна детализация: какой сервис, какой метод, какой запрос, какие параметры.
Здесь в игру вступают два подхода:
eBPF — супер легковесное ядро-ориентированное профилирование
BitDive — Java-агент, встроенный в приложение, ориентированный на бизнес-логику
Хотя eBPF и BitDive работают на разных уровнях — системном и прикладном — они часто встречаются в одной проблемной зоне: когда нужно понять, почему в проде что-то тормозит.
И тут важно выбрать правильный инструмент: нужен ли тебе общий системный обзор (eBPF) или глубокое понимание, что происходит в коде (BitDive)?
Проблемы eBPF, о которых не говорят в брошюрах

eBPF внедряется на уровне ядра Linux и перехватывает системные вызовы, сокеты, файловые операции и сетевые события. Но он не видит, что именно делает приложение на уровне методов и бизнес-логики.
Требуется root-доступ
Чтобы запустить eBPF-агент, нужен доступ к ядру: root, либо CAP_BPF
, CAP_PERFMON
, CAP_SYS_ADMIN
.
В облаках это означает — договариваться с DevOps/SRE, настраивать IAM, делать exec в node, раскатывать DaemonSet.
Разработчику самому запустить это невозможно в 99% случаев (только если это не стартап из 4-х человек).
Работает только на хосте
Если приложение распределено по нескольким VM или узлам, eBPF не видит за пределы текущего ядра.
Нужно ставить агентов на каждый хост и собирать данные в централизованное хранилище. Это сложно и требует инфраструктурной поддержки.
Непрозрачность кода
eBPF не видит структуру Java-приложений — он не знает названий методов, классов и пакетов, не видит параметры, ошибки, исключения и возвраты.
Он работает на уровне нативных вызовов (malloc
, syscall
, pthread_create
) и оперирует только тем, что происходит внутри ядра и системных библиотек.
Теоретически существуют обходные подходы, позволяющие "вытянуть" часть этой информации. Но на практике это крайне нестабильно, сложно в поддержке, требует глубокого вмешательства в JVM и не масштабируется для продакшен-сред.
Во всех популярных реализациях (Pixie, Parca, Phlare и др.) eBPF остаётся полностью слепым к бизнес-логике Java-кода.

Пример flame graph, полученного с использованием eBPF, демонстрирующий, как отображаются стеки вызовов без контекста бизнес-логики.
Много шума
На продакшене работает 100+ контейнеров. eBPF видит их все: в одном контейнере может быть несколько процессов, а в каждом процессе — много логических слоёв.
Без фильтрации и группировки данные быстро превращаются в бесполезную свалку.
Сырые данные = мало аналитики
eBPF-профайлеры (Parca, Phlare, Elastic) не показывают ошибок, замедлений или связей между сервисами. Всё это приходится строить вручную на основе stack trace'ов.
Что с распределёнными системами?
eBPF имеет серьёзные ограничения в распределённых архитектурах:
Он не видит trace или span — не может показать, что метод A был вызван в рамках запроса пользователя X.
Он не передаёт данные между узлами — каждый агент живёт в изоляции.
Он не связывает события в разные процессы или контейнеры, если они в разных cgroups / namespaces.
Нет понимания "запроса как целого" — только фрагменты CPU-нагрузки.
В результате вы видите, что на узле 1 метод encrypt()
потреблял CPU, но не видите, что это был шаг №3 в цепочке вызова от frontend до billing.
Что даёт BitDive
Уровень метода + контекст
BitDive встроен в JVM, знает структуру кода (Java, Spring, Kotlin) и показывает метод, класс, пакет, фреймворк, кто вызвал метод, в каком контексте, какие параметры переданы и какие downstream-запросы были вызваны (SQL, Redis, Kafka).
Ошибки, исключения, аномалии
BitDive автоматически помечает медленные методы (например, >1 сек), ошибки и исключения, а также фиксирует спайки и отклонения от нормы по времени исполнения.
Нужен только доступ к коду
BitDive внедряется как зависимость Maven/Gradle. Разработчику достаточно добавить агент в pom.xml
, указать конфигурацию и запустить приложение. Всё — профилирование работает.
Никакого root-доступа, никакой настройки ядра.
BitDive и распределённые вызовы
BitDive отслеживает, как пользовательский запрос проходит через все слои — от фронтенда до глубин бэкенда, связывая вызовы между сервисами, модулями и API.

Пример карты сервисов в BitDive: видны связи между компонентами, очередь Kafka, ошибки в одном из сервисов (
faculty
), а также задержки на каждом участке. Такие визуализации позволяют быстро локализовать, где именно происходит деградация в распределённой системе.
В отличие от классического distributed tracing, который ограничен верхни уровневыми span’ами, BitDive показывает, что происходит внутри: методы, параметры, исключения, downstream-интеграции.
Это позволяет строить детальные карты вызовов на уровне кода, группировать данные по HTTP-запросам и видеть, где именно внутри цепочки возникает задержка — вплоть до конкретного метода.
В результате вы получаете не просто трассировку между сервисами, а глубокий кодовый профайлинг в контексте запроса.

Фрагмент вызова в BitDive с ошибкой внутри метода
save
. Видно, какие аргументы передавались, какая именно ошибка произошла (ошибка поиска объектаTeacher
с id 2754), и на каком слое это случилось. Такой уровень детализации помогает понять причину проблем — а не просто увидеть, что что-то пошло не так.
BitDive дополняет классический tracing, показывая то, что обычно остаётся за кадром — что реально происходит внутри методов, а не только между ними.
Полное сравнение: eBPF vs BitDive
Категория | eBPF | BitDive |
---|---|---|
Уровень | Ядро, процессы | Приложение, методы |
Требует root | ✅ Да | ❌ Нет |
Установка в облаке | ❌ Затруднена (IAM, DaemonSet) | ✅ Просто: Java-зависимость |
Поддержка нескольких хостов | ❌ Только через доп. инфраструктуру | ✅ Нативно, через сервисные уровни |
Глубина вызовов | libc / функции | Методы, классы, пакеты |
Понимание логики | ❌ Нет | ✅ Да |
Ошибки / исключения | ❌ Нет | ✅ Да |
Параметры метода | ❌ Нет | ✅ Да |
SQL/HTTP/Redis и др. вызовы | ❌ Не видно | ✅ Да |
Flame Graph | ✅ Есть, но сырые | ✅ Есть + группировка по логике |
Интерфейс | CLI / UI | UI для разработчиков |
Языковая поддержка | Любые, но без контекста | Java (Spring, Kotlin) |
Поддержка распределённых связей | ❌ Нет | ✅ Да |
Когда использовать BitDive?
У вас Java-приложение (монолит или микросервисы )
Вы хотите знать, какой метод тормозит, почему и с какими параметрами
Вам важны ошибки, SQL-запросы, ретраи и реальные причины лагов
У вас нет root-доступа к продакшену
Вы хотите дать профилировщик в руки разработчику, а не только DevOps
Вы работаете с распределёнными вызовами и хотите понимать бизнес-цепочку, а не просто потребление CPU
Вывод
eBPF — мощный инструмент системного уровня. Он незаменим для профилирования Go, C++ и анализа ядра.
Но он не даёт контекста, если вы Java-команда, и вам нужно:
Понять, что именно тормозит в коде
Разобраться, где ошибка и почему
Отслеживать распределённые вызовы на уровне методов
Работать без root-доступа в облаке
BitDive — это инструмент уровня приложения (Application Profiling / Continuous Profiling).
eBPF — это механизм системного уровня (System Observability).
Они не конкуренты по реализации, но альтернативные подходы к решению одной и той же задачи: «Что тормозит прод?».
BitDive — это профилировщик, говорящий на языке Java-разработчика.
И там, где заканчивается eBPF, он только начинается.