Зачем eBPF, когда есть tcpdump и ss
Классический набор для сетевой диагностики в Linux — tcpdump, ss, ip, ethtool, иногда conntrack. Этого достаточно, когда проблема видна «на проводе» или в статистике сокетов. Но как только начинается история уровня «потери есть, но где именно?» или «ретрансляции растут, но в дампе тихо», вы упираетесь в отсутствие наблюдаемости внутри ядра.
eBPF закрывает именно эту дыру: вы можете подключиться к ключевым точкам стека и ответить на вопрос: в каком месте пакеты или события исчезают, тормозят или массово дропаются — на входе в стек, на qdisc, в conntrack/NAT, на выходе к драйверу, в очередях.
Ниже — практический разбор, как собрать картину из трёх источников, которые чаще всего дают «невидимые» проблемы в проде: симптомы TCP через ss, дропы в очередях через tc/qdisc, и насыщение таблицы состояний через conntrack. А eBPF используем как «клей», который связывает симптомы с местом, где они возникают.
Быстрый чеклист симптомов: с чего начать
Прежде чем включать eBPF, полезно зафиксировать симптомы «в лоб» — это ускорит интерпретацию eBPF-данных и поможет не уйти в «трейсинг ради трейсинга».
1) TCP ретрансляции и очереди сокетов
Проверьте, есть ли явные признаки проблем доставки (retransmits, RTO, очереди):
ss -ti dst :443
ss -s
netstat -s | grep -i retrans
В выводе ss -ti обращайте внимание на рост retransmits, большие RTT, признаки RTO, а также на очереди (send-q/recv-q). Если retransmits растут, это уже хороший маркер «потери или недоставки», но ещё не ответ на вопрос «где именно».
2) Drops в qdisc (tc)
Дропы могут происходить до того, как пакет попадёт в TCP/UDP (например, на egress-очереди). Проверяем:
tc -s qdisc show dev eth0
tc -s class show dev eth0
Ищите поля drops, overlimits, backlog. Если растут именно drops — это уже локализация по слою: очередь/шейпинг/буфер.
3) Переполнение conntrack
Если сервер делает NAT, балансирует L3/L4, работает как VPN-шлюз или просто имеет много коротких соединений, conntrack может стать узким местом. Признаки:
dmesg -T | grep -i conntrack
sysctl net.netfilter.nf_conntrack_count net.netfilter.nf_conntrack_max
Сообщение conntrack table full — почти готовый диагноз. Но важно понять источник всплеска и что именно «забивает» таблицу, чтобы исправление не свелось к бесконечному повышению лимитов.

Минимальная подготовка: что нужно для eBPF в проде
На практике быстрее всего стартовать с bpftrace и утилитами из bpftool или пакета libbpf-tools. BCC тоже полезен, но чаще тяжелее по зависимостям.
Минимальные условия:
- ядро с поддержкой eBPF (в современных LTS это норма);
- права root (для инцидента обычно разумнее, чем долго настраивать capabilities);
- наличие BTF (ускоряет запуск многих eBPF-скриптов и упрощает доступ к структурам ядра).
Быстрые проверки:
uname -r
bpftool feature probe | head
ls -l /sys/kernel/btf/vmlinux
eBPF тоже потребляет ресурсы. В проде держите трейсинг короткими сессиями, фиксируйте окно времени и по возможности фильтруйте по порту, адресу или cgroup, чтобы не «снимать весь мир».
Если вы выбираете площадку под сервисы с сетевой нагрузкой (прокси, балансеры, VPN, high-traffic API), удобнее, когда у вас есть полный контроль над ядром и доступ к трейсингу. В таких задачах чаще берут VDS, чтобы без ограничений использовать bpftool/bpftrace и диагностировать инциденты на уровне хоста.
Часть 1. TCP retransmit через bpftrace: подтверждаем «потери» на уровне транспорта
Если вы видите ретрансляции в ss, следующий вопрос: это реальная потеря пакетов, перегруз очередей, проблема MTU/PMTU, деградация на пути, или локальные дропы на выходе или входе?
Начнём с подтверждения события ретрансляции из ядра. В современных ядрах есть tracepoint’ы по TCP. Один из самых быстрых способов «прямо сейчас» — использовать bpftrace по tracepoint’ам.
bpftrace: счётчик ретрансляций в секунду
Сначала убедитесь, что нужные события присутствуют (названия зависят от ядра):
bpftrace -l | grep -E 'tcp:tcp_retransmit|sock:inet_sock_set_state|tcp:tcp_retransmit_skb' | head -n 50
Пример «ретрансляции в секунду» (имя tracepoint уточняйте по выводу выше):
bpftrace -e 'tracepoint:tcp:tcp_retransmit_skb { @retrans = count(); } interval:s:1 { printf("tcp retransmit/s: %d\n", @retrans); clear(@retrans); }'
Как интерпретировать результаты
- Ретрансляции растут вместе с нагрузкой и синхронно растут
dropsв qdisc: вероятна локальная проблема очередей или шейпинга. - Ретрансляции растут, но qdisc drops = 0: смотрите RX-дропы/драйвер/NAPI, MTU/PMTU, деградацию на пути, и отдельно проверьте conntrack (если есть stateful firewall или NAT).
- Ретрансляции растут скачками: часто это микробёрсты, конкуренция за CPU (softirq), неудачная IRQ affinity, либо буферизация в неожиданных местах.
Если вам нужно глубже разобрать инструменты и подходы, которые обычно доступны в дистрибутивах (BCC, bpftrace, libbpf-tools), пригодится материал про выбор набора для диагностики: как подобрать eBPF-инструменты для продакшена.
Часть 2. Drops в tc/qdisc: где очередь начинает «сыпаться»
Qdisc — место, где Linux реально «держит» пакеты перед отправкой и может их сбрасывать при переполнении очереди или при шейпинге/полисинге. На виртуальных интерфейсах и под нагрузкой qdisc нередко становится первым узким местом именно из-за микробёрстов.
Быстрая диагностика через tc
Фиксируем, какой qdisc стоит и сколько там дропов:
tc -s qdisc show dev eth0
Типовые варианты, которые часто встречаются:
fq_codelилиcake— борются с буферблоатом, дропы возможны при перегрузе;fq— нередко идёт как дефолт;htb/tbf— шейпинг, легко устроить «самострел» неправильным rate/ceil/limit;ingress/clsact— если включены фильтры/полисинг/eBPF на ingress/egress.
Что считать подозрительным
dropsрастут на egress qdisc — вы теряете пакеты ещё до «реальной отправки» в сторону линка/виртуального свитча.backlogпостоянно ненулевой и увеличивается — очередь не успевает разгребаться.overlimitsрастут при шейпинге — вы упираетесь в заданный rate/ceil/limit, и это начинает проявляться как latency и retransmits.
Где тут eBPF полезен
tc -s показывает факт, но не отвечает на главный вопрос: какой трафик и какие потоки создают дропы. eBPF помогает привязать событие к 5-tuple (src/dst IP, порты, протокол) и иногда к cgroup.
Если у вас уже используется eBPF в tc (например, фильтры), обязательно проверьте счётчики самих фильтров:
tc -s filter show dev eth0 ingress
tc -s filter show dev eth0 egress
Сценарий из практики: tc показывает рост drops, приложение видит таймауты и TCP retransmits. Частая причина — слишком маленький limit у tbf или агрессивная настройка burst/latency, из-за чего микробёрсты превращаются в дропы. Дальше TCP ретранслирует, усиливая нагрузку на очереди, и получается замкнутый круг.
Часть 3. conntrack table full: когда stateful NAT начинает убивать сеть
Conntrack нужен для stateful firewall и NAT. Цена — память и CPU на ведение таблицы соединений. При всплесках коротких коннектов (особенно UDP или TCP с быстрым закрытием) таблица может заполняться, и ядро начнёт дропать новые соединения. Снаружи это выглядит как «рандомные таймауты», а в логах — conntrack table full.
Подтверждаем переполнение
dmesg -T | grep -i 'conntrack table full'
sysctl net.netfilter.nf_conntrack_count
sysctl net.netfilter.nf_conntrack_max
Если nf_conntrack_count близко к nf_conntrack_max и параллельно пользователи жалуются на «отваливается API», вы почти наверняка нашли причину деградации.
Находим, кто забивает таблицу
Дальше нужно понять распределение по протоколам и состояниям. Если есть conntrack из conntrack-tools:
conntrack -S
conntrack -L | head
Часто «виноваты» такие классы событий:
- бурст входящих SYN (много
SYN_RECV); - UDP-трафик с большим количеством уникальных 5-tuple;
- исходящие короткие подключения без keep-alive (сервис «стреляет» запросами наружу);
- NAT на узле, который не должен был быть NAT’ом (например, случайно включён MASQUERADE).
Как eBPF помогает с conntrack
Проблема conntrack в том, что вы видите «таблица полная», но не всегда понимаете, какой именно трафик генерирует новые записи и какие пути в netfilter чаще всего срабатывают.
eBPF-трейсинг по функциям/хукам netfilter позволяет:
- посчитать скорость создания новых conntrack entries;
- увидеть, какие порты и протоколы лидируют;
- сопоставить всплеск с конкретным приложением (особенно для исходящих соединений, если удобно фильтровать по cgroup).
Здесь важна сама идея: conntrack — это измеряемый поток событий. Если вы умеете померить «rate создания entries», вы обычно быстро находите первопричину (не только симптом).

Сводим всё вместе: практический сценарий расследования
Ниже — рабочий порядок действий для инцидентов уровня «таймауты», «потери», «скачки latency».
Фиксируем симптомы:
ss -s,ss -ti,netstat -s. Понимаем: это больше похоже на потери/ретрансляции или на прикладные очереди.Смотрим qdisc:
tc -s qdisc. Если растутdrops— локализовали слой. Дальше выясняем: шейпинг/лимиты или реальная перегрузка.Проверяем conntrack:
dmesgиnf_conntrack_count. Если близко к максимуму или есть conntrack table full — это отдельная ветка расследования.Подтверждаем события из ядра через eBPF: короткими сессиями
bpftraceизмеряем частоту ретрансляций и коррелируем по времени с ростом drops и насыщением conntrack.Корреляция: retransmit синхронно с qdisc drops — лечим очередь/шейпинг. Retransmit синхронно с conntrack saturation — лечим conntrack/NAT. Retransmit без обоих — идём в MTU/PMTU, RX/TX в драйвере, IRQ/softirq и сеть между хостами.
Если ваша проблема проявляется «между машинами» (например, балансировка TCP/UDP или прокси на уровне L4), полезно проверить конфигурацию и keep-alive на стороне балансера: настройка Nginx stream для TCP/UDP.
Частые причины и что чинить, если диагноз подтвердился
Если виноват tc/qdisc
- Проверьте, не включён ли ограничивающий qdisc (
htb/tbf) с слишком маленькими лимитами и неудачнымиburst/latency. - Если это буферблоат и длинные очереди, рассмотрите
fq_codel/cake, но настройку делайте осознанно и с измерениями до/после. - Ищите микробёрсты: иногда помогает не «увеличить очередь», а стабилизировать отправку (пейсинг, правильный qdisc, разгрузка приложения).
Если виноват conntrack
- Проверьте, действительно ли вам нужен conntrack для всего трафика: иногда часть потоков можно обрабатывать без stateful логики (в рамках вашей политики безопасности).
- Поднимать
nf_conntrack_maxимеет смысл только вместе с расчётом памяти, CPU и мониторингом, иначе можно получить OOM или деградацию. - Сократите churn: keep-alive, пулы соединений, меньше коротких коннектов.
- Найдите источник всплеска и фильтруйте как можно раньше (на периметре, на входе, в правилах firewall), не доводя до заполнения таблицы.
Если retransmits есть, но drops не видны
- Проверяйте MTU/PMTU blackhole и MSS (особенно через туннели, VLAN, overlay).
- Смотрите CPU softirq и обработку RX/TX (перегруз на одном ядре, IRQ affinity, RPS/RFS).
- Проверяйте ошибки интерфейса и драйвера:
ethtool -S eth0, а также общую статистику линка.
Мини-рукбук: команды, которые удобно держать рядом
# Симптомы TCP
ss -s
ss -ti dst :443
netstat -s | grep -i retrans
# qdisc / tc drops
tc -s qdisc show dev eth0
tc -s filter show dev eth0 ingress
tc -s filter show dev eth0 egress
# conntrack saturation
dmesg -T | grep -i conntrack
sysctl net.netfilter.nf_conntrack_count net.netfilter.nf_conntrack_max
# eBPF: поиск tracepoint по TCP
bpftrace -l | grep -E 'tcp:tcp_retransmit|tcp:tcp_retransmit_skb' | head
# eBPF: ретрансляции в секунду (пример, имя tracepoint уточняйте)
bpftrace -e 'tracepoint:tcp:tcp_retransmit_skb { @retrans = count(); } interval:s:1 { printf("tcp retransmit/s: %d\n", @retrans); clear(@retrans); }'
Что мониторить, чтобы не ловить это во время пожара
Если один раз поймали такой инцидент, следующий шаг — «приземлить» его в метрики:
- TCP retransmits, RTT, RTO (хотя бы агрегаты по хосту).
tcdrops и backlog по ключевым интерфейсам.nf_conntrack_countи доля отnf_conntrack_max, плюс скорость создания новых записей (если можете измерять).
Тогда eBPF останется инструментом второго уровня: быстро выяснить, какой трафик и почему дал всплеск — а не единственным способом понять, что вообще происходит.
Итог
eBPF не заменяет ss, tc и conntrack-инструменты — он связывает их в причинно-следственную цепочку. Практический подход такой: сначала фиксируем симптомы (ретрансляции), затем проверяем явные места дропов (qdisc), затем исключаем «тихий убийцу» conntrack, и только после этого включаем eBPF-трейсинг короткими сессиями для точной локализации и корреляции по времени.
Главное правило: не пытайтесь «лечить сеть» вслепую настройками таймаутов в приложении. Сначала измерьте: retransmit, drops, conntrack saturation. Потом чините ровно тот слой, который подтвердился метриками.


