eBPF для трассировки прикладного стека: от сокетов до приложения
Практическое руководство по сквозной трассировке через eBPF: от сетевого стека до прикладного кода с корреляцией по trace_id. Обновлено 2026.
eBPF для трассировки прикладного стека: от сокетов до приложения
Аннотация
Практическое руководство по сквозной трассировке запросов через eBPF: от поступления пакета в сетевой стек до возврата из прикладного кода. Покрываем трассировку TCP-соединений, системных вызовов, TLS-библиотек и фреймворков (Go, Java, Python) с корреляцией по trace_id.
1. Архитектура сквозной трассировки
Компоненты:
- kprobes/uprobes: точки входа в ядро и пользовательское пространство.
- tracepoints: стабильные события ядра (netif_receive_skb, tcp_v4_rcv).
- USDT: статические точки трассировки в приложениях.
- BPF maps: передача контекста между программами, агрегация.
- Коррелятор: сквозной идентификатор (trace_id) через все уровни.
Ключевые метрики:
- Время в ядре (qdisc → tcp_v4_rcv → recvmsg)
- Время в TLS (SSL_read/SSL_write)
- Время в рантайме (Go: runtime.schedule; Java: GC pauses)
- Время в приложении (handler/endpoint)
2. Инструментарий
- bpftrace для быстрого прототипирования.
- libbpf/CO-RE для production-обвязки.
- BCC для сложных сценариев.
- OpenTelemetry eBPF для интеграции с APM.
3. Практические примеры
3.1 Трассировка TCP-рукопожатия и задержек
uprobe:/lib/x86_64-linux-gnu/libssl.so:SSL_read {
@start[tid] = nsecs;
}
uretprobe:/lib/x86_64-linux-gnu/libssl.so:SSL_read /@start[tid]/ {
$latency = nsecs - @start[tid];
@ssl_read_latency = hist($latency);
delete(@start[tid]);
}
3.2 Корреляция с прикладным кодом (Go)
tracepoint:syscalls:sys_enter_write /comm == "server"/ {
@write_start[tid] = nsecs;
}
tracepoint:sys_calls:sys_exit_write /@write_start[tid]/ {
$latency = nsecs - @write_start[tid];
@write_latency = hist($latency);
delete(@write_start[tid]);
}
3.3 USDT в Nginx
usdt:/usr/sbin/nginx:request__start {
@req_start[arg0] = nsecs;
}
usdt:/usr/sbin/nginx:request__done /@req_start[arg0]/ {
$latency = nsecs - @req_start[arg0];
@nginx_request_latency = hist($latency);
delete(@req_start[arg0]);
}
4. Корреляция по trace_id
- Inject trace_id в HTTP-заголовки (traceparent/tracestate).
- Передача через контекст корутин/goroutines.
- BPF-программа читает trace_id из сокета/памяти.
- Все события пишутся в единую систему с общим ключом.
5. Производительность и оверхед
- kprobes: 100–500 нс на событие.
- uprobes: 500–2000 нс.
- USDT: 100–300 нс.
- Maps: минимальные при правильной схеме ключей.
Рекомендации:
- Фильтрация на ранней стадии (comm, pid, fd).
- Агрегация в ядре, отправка батчами.
- Sampling для высоконагруженных путей.
6. Сценарии использования
- Поиск хвостов распределения (P99/P999 latency).
- Диагностика взаимоблокировок в Go runtime.
- Анализ влияния GC в Java на latency.
- Поиск утечек файловых дескрипторов.
- Трассировка падения соединений (RST, timeouts).
Обновления 2026
- Интеграция с OpenTelemetry eBPF auto-instrumentation.
- Поддержка USDT в Go 1.22+ без перекомпиляции.
- BPF CO-RE стабилен для production на ядрах 5.15+.
- Рекомендация: использовать sampling 1:100 для P999 анализа.
Заключение
eBPF даёт рентген всей системы без модификации приложения. При грамотной фильтрации и агрегации оверхед минимален, а видимость — максимальная.