Сетевой стек Linux: путь пакета и где возникают задержки

Рейтинг: 59.6% · 10 голосов
Подробный курс по диагностике и производительности Linux для админов и DevOps: с чего начать, методология USE, логи (journalctl, dmesg), процессы, CPU, память и OOM, диск и IO (iostat), сеть (ss, tcpdump), системные вызовы и strace, ltrace, perf, флеймграфы, ftrace, eBPF и bpftrace, lsof, мониторинг. Разбор каждого инструмента с чтением вывода.
Ответить
Аватара пользователя
Dmitry_SRE
Сообщения: 47
Зарегистрирован: 11 май 2026, 05:31

Сетевой стек Linux: путь пакета и где возникают задержки

Сообщение Dmitry_SRE »

Оглавление курса (47)
  1. С чего начать диагностику Linux: методология вместо паники
  2. Первые 60 секунд: экспресс-диагностика нагруженного сервера
  3. Методологии диагностики: USE, RED и здравый смысл
  4. Логи systemd через journalctl: где искать причину
  5. Где лежат логи Linux: /var/log, dmesg и rsyslog
  6. Источники правды: load average, /proc и /sys
  7. Процессы Linux: ps, pstree и состояния процессов
  8. Интерактивный мониторинг: top и htop
  9. Метрики процессов во времени: pidstat
  10. Приоритеты и ограничения: nice, ionice, cgroups
  11. Сигналы и зависшие процессы: kill, и что делать с D-state
  12. Загрузка CPU: user, system, iowait, steal и контекст-свитчи
  13. Диагностика CPU по ядрам: vmstat и mpstat
  14. Профилирование CPU: perf top и поиск пожирателя
  15. Частоты, троттлинг и NUMA: turbostat и numastat
  16. Память Linux: RSS, VSZ, page cache и миф о нехватке памяти
  17. Сколько памяти занято: free, /proc/meminfo и vmstat
  18. Поиск утечек и пожирателей памяти: smem, pmap, smaps
  19. Swap и подкачка: swapon, swappiness, когда своп - это боль
  20. OOM killer: кто и за что убил процесс
  21. Память ядра и slab: slabtop и куда уходит RAM
  22. Подсистема ввода-вывода: путь запроса от приложения до диска
  23. Диагностика диска: iostat и чтение await, %util
  24. Кто грузит диск: iotop и атрибуция io процессам
  25. Файловые системы: df, du, иноды и куда делось место
  26. Глубокая диагностика блочного слоя: blktrace и biolatency
  27. Кеш страниц и грязные данные: dirty pages, fsync, drop_caches
  28. Сетевой стек Linux: путь пакета и где возникают задержки (вы здесь)
  29. Сокеты и соединения: ss и netstat
  30. Захват трафика: tcpdump для диагностики сети
  31. Задержки и потери в сети: ping, mtr, диагностика латентности
  32. Сеть как источник проблем: nftables, conntrack, дропы
  33. Что такое системный вызов и зачем его трассировать
  34. strace: трассировка системных вызовов на практике
  35. strace в бою: почему программа висит, падает или тормозит
  36. ltrace: трассировка вызовов библиотек
  37. Накладные расходы трассировки и безопасные альтернативы
  38. perf: универсальный профайлер Linux
  39. Флеймграфы: визуализация профиля производительности
  40. Трассировка ядра: ftrace и trace-cmd
  41. eBPF: революция в наблюдаемости Linux
  42. Инструменты eBPF на практике: BCC и bpftrace
  43. lsof: открытые файлы, дескрипторы, кто держит файл и порт
  44. Разбор кейса: приложение тормозит - пошаговая диагностика
  45. Непрерывный мониторинг: sar, node_exporter, Grafana, Zabbix
  46. Диагностика в контейнерах: cgroups, лимиты, Docker и Kubernetes
  47. Карта инструментов и сквозной разбор инцидента производительности
Знакомая боль: приложение "тормозит по сети", а где именно - непонятно. Браузер крутит спиннер, ответ от API приходит то за 5 мс, то за 800, дашборд показывает retransmit, а ты сидишь и гадаешь - это провайдер, ядро, переполненная очередь или само приложение залипло на чтении сокета. Без карты тут легко закопаться: запустишь tcpdump там, где надо было смотреть ss, или будешь крутить буферы, когда проблема в драйвере.

Этот урок дает ту самую карту. Мы пройдем путь одного пакета от приложения до провода и обратно, разберем, где именно растет latency и теряются пакеты, какие команды смотреть в первую очередь и почему на 2026 год часть старой диагностики уже вытесняется eBPF. Это концептуальная основа (часть знаменитой карты Брендана Грегга), на которую дальше лягут конкретные инструменты. Цель простая: чтобы ты, глядя на проблему, сразу понимал, в какой слой тыкать.

Сетевой стек Linux: из чего он собран

Представь сетевой стек linux как многоэтажку, по которой данные едут на лифте сверху вниз (отправка) и снизу вверх (прием). На каждом этаже свой контроль и своя очередь, и пакет может застрять на любом.

Путь на отправку (TX), сверху вниз:
  • Приложение - твой код вызывает send()/write() в сокет.
  • Сокет и его буфер - данные копируются в буфер отправки (wmem). Если приложение пишет быстрее, чем сеть успевает отдавать, буфер растет.
  • TCP/UDP (L4) - TCP режет данные на сегменты, нумерует, ждет подтверждений (ACK), управляет окном. UDP просто заворачивает и отдает дальше, без гарантий.
  • IP (L3) - выбирает маршрут, ставит адреса, при необходимости фрагментирует.
  • qdisc (сетевая очередь) - дисциплина очередей перед отправкой в драйвер. Здесь живут шейпинг, приоритеты и pacing. На современном Linux с systemd по умолчанию это fq_codel (так с ядра 4.12); на нагруженных TCP-серверах под 10G и выше часто ставят sch_fq, особенно вместе с congestion control BBR.
  • Драйвер NIC и ring buffer - кольцевой буфер карты. Драйвер кладет туда дескрипторы, карта забирает данные через DMA.
  • Провод - дальше уже физика и провайдер.
На прием (RX) тот же лифт едет снизу вверх, но с важной деталью. Карта получает пакет, через DMA пишет его в ring buffer в оперативке и дергает аппаратное прерывание (hard IRQ). Обработчик прерывания не делает тяжелую работу - он лишь планирует софтовое прерывание NET_RX_SOFTIRQ. Дальше включается NAPI: вместо того чтобы дергать прерывание на каждый пакет (на высоком pps это убило бы CPU), ядро переключается в режим опроса (polling) и пачкой выгребает пакеты из кольца. Обрабатывает их softirq-контекст на том же ядре, а если CPU перегружен и не успевает - работа уходит в поток ksoftirqd/N (по одному на ядро). Растущий в top ksoftirqd на одном ядре - классический симптом, что весь сетевой RX свалился в одно прерывание. Дальше пакет идет вверх по IP, по TCP/UDP, попадает в буфер приема сокета (rmem), и только когда приложение вызовет recv()/read() - данные уезжают к нему.

Ключевые понятия, без которых дальше никак. Throughput - это сколько байт в секунду протекает (ширина трубы). Latency - сколько ждет один пакет (длина трубы). Это разные вещи: канал на 10 Гбит/с с пингом 200 мс - широкий, но медленный на отклик. RTT (round-trip time) - время "туда и обратно", от отправки до прихода ACK. Окно TCP - сколько данных разрешено держать "в полете" без подтверждения; congestion window (cwnd) ядро само сужает при потерях и осторожно наращивает обратно. Практическое правило: максимальный throughput одного TCP-потока ограничен сверху как (окно в байтах) / RTT. Поэтому на "толстом длинном" канале (большой BDP - bandwidth-delay product) маленькое окно или редкие потери режут скорость в разы, и это не лечится "более широким каналом".

Изображение

Где растут задержки и теряются пакеты

Главная мысль: задержка и потери - это почти всегда переполненная очередь. Где очередь переполнилась, там и проблема. Идем по слоям сверху вниз.
  • ring buffer на приеме переполнился - CPU не успел выгрести пакеты (один поток softirq уперся в 100% ядра). Эти дропы НЕ видны в обычных RX-ошибках ip -s, их показывает только ethtool -S как rx_missed_errors (в ip -s это колонка missed). Лечится увеличением кольца (ethtool -G) или раскидыванием прерываний по ядрам (RSS/RPS, балансировка IRQ).
  • буфер сокета мал или приложение медленно читает - данные не влезают, отправитель тормозится. На приеме видно как растущий Recv-Q.
  • qdisc/txqueuelen переполнилась на отправке - пакеты дропаются перед уходом в провод (видно как dropped на TX и в tc -s qdisc).
  • backlog очередь на listen-сокете переполнилась - новые TCP-соединения отбрасываются (классическое "сервер не принимает коннекты под нагрузкой"). Сюда же SYN backlog: счетчик переполнений видно в nstat -az как TcpExtListenOverflows и TcpExtListenDrops.
  • retransmit - TCP не дождался ACK и шлет сегмент заново. Каждый ретрансмит - это потерянный где-то по пути пакет linux плюс лишний RTT задержки. Растущие ретрансмиты - почти верный признак потерь на участке.
Практика: команды для сети linux диагностика

Выбор инструмента диктуется слоем. Сокеты и буферы - ss. Сводные счетчики стека - nstat. Счетчики карты - ip -s и ethtool. Сырые пакеты на проводе - tcpdump. А первопричину дропов и ретрансмитов в 2026-м чаще всего быстрее найти через eBPF, не трогая tcpdump. Начнем сверху.

ss - заглянуть внутрь сокетов и TCP.

Код: Выделить всё

sudo ss -tinp state established
Кусок вывода по одному соединению:

Код: Выделить всё

State  Recv-Q Send-Q  Local Address:Port   Peer Address:Port
ESTAB  0      4320    10.0.0.5:443         10.0.0.9:51544
     cubic wscale:7,7 rto:312 rtt:48.5/12.1 mss:1448 cwnd:10 ssthresh:7
     bytes_sent:982340 bytes_retrans:14480 delivery_rate:6.1Mbps
     retrans:0/9 reord:3 rcv_rtt:49.0 send 2.4Mbps pacing_rate 4.8Mbps
Как читать. Recv-Q - сколько байт пришло, но приложение их еще не прочитало; стабильно большое значение тут означает, что твой процесс не успевает читать (норма около 0). Send-Q - сколько байт ушло, но еще не подтверждено ACK от пира; постоянно большое - сеть не успевает прокачивать или потери. Дальше строка -i: rtt:48.5/12.1 - средний RTT 48.5 мс и его разброс 12.1 (rttvar); большой разброс это нестабильный канал. rto - таймаут, после которого TCP считает сегмент потерянным. cwnd:10 - окно перегрузки в сегментах (в байтах это cwnd*mss); маленький cwnd при большом RTT режет throughput. retrans:0/9 - сейчас в полете 0 ретрансмитов, всего за жизнь соединения было 9; растущее второе число - сигнал потерь. Полезные поля посвежее (есть в актуальных ss из iproute2): bytes_sent и bytes_retrans - доля ретрансмитов в байтах честнее процента потерь, чем счетчик сегментов; delivery_rate - реальная измеренная ядром скорость доставки (если она много ниже ширины канала при cwnd, упертом в потолок - явный congestion); pacing_rate - с какой скоростью ядро разгоняет отправку. Куда смотреть дальше: большой Recv-Q -> чини приложение; большой Send-Q плюс растущий bytes_retrans -> иди в eBPF/tcpdump и к ip -s.

ip -s link и nstat - счетчики карты и стека.

Код: Выделить всё

ip -s link show eth0

Код: Выделить всё

2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 ...
    RX:  bytes packets errors dropped missed mcast
    8123456   91022   0      37      12     0
    TX:  bytes packets errors dropped carrier collsns
    4501233   60110   0      0       0      0
Как читать. errors - битые кадры (CRC, обычно физика: кабель, оптика, SFP). dropped на RX - ядро отбросило уже принятые пакеты (нет места в буфере, фильтр, нет протокола-получателя). missed - карта не успела отдать пакеты, ring buffer был полон; это и есть rx_missed_errors драйвера, классический симптом нехватки NAPI/прерываний под высоким pps. Любое из этих чисел, что заметно растет со временем - твоя зацепка (важно смотреть именно дельту, а не абсолют - за месяцы аптайма накапливается всякое). Для самых ранних дропов на кольце смотри драйверные поля:

Код: Выделить всё

sudo ethtool -S eth0 | grep -E 'drop|miss|err|no_buf|fifo'
Имена полей зависят от драйвера: rx_missed_errors и rx_no_buffer_count - чаще переполнение кольца, rx_fifo_errors - не успели по шине. А агрегированные счетчики всего TCP-стека (ретрансмиты, переполнения backlog, отброшенные SYN) дает nstat:

Код: Выделить всё

nstat -az | grep -E 'Retrans|ListenDrops|ListenOverflows|OutOfWindow'
nstat удобнее старого netstat -s: показывает дельту между запусками и не врет на форматировании.

tcpdump - посмотреть сами пакеты на проводе.

Код: Выделить всё

sudo tcpdump -ni eth0 -tt 'host 10.0.0.9 and tcp port 443'
Флаги: -n не резолвить DNS (иначе tcpdump сам начнет слать запросы), -i интерфейс, -tt абсолютные метки времени, дальше фильтр по host и port. В выводе ищи флаг R (reset - кто-то рвет соединение), дубли SEQ (ретрансмиты), большие паузы между меткой запроса и ответом (это и есть твоя сетевая задержка на проводе). Если на проводе пакеты приходят быстро, а приложение отвечает медленно - проблема не в сети, а выше, в обработке. На нагруженном хосте пиши в файл (-w cap.pcap), а разбирай потом в Wireshark - так не потеряешь пакеты и не нагрузишь CPU парсингом.

eBPF - актуальный на 2026 способ ловить причину. Когда ss показал, что ретрансмиты есть, а tcpdump на 10G захлебывается, спускайся в ядро напрямую. Инструменты из bcc и bpftrace получают данные из ядра без захвата и фильтрации трафика, поэтому накладные расходы минимальны:

Код: Выделить всё

sudo tcpretrans     # каждый ретрансмит: кто, куда, в каком TCP-состоянии
sudo tcpdrop        # где именно ядро дропнуло сегмент, со стеком вызовов
sudo tcplife        # сводка по каждому закрытому соединению (длительность, байты)
sudo tcptracer      # connect/accept/close в реальном времени
Это уже зрелый стек: tcpdrop сразу показывает место в коде ядра, где пакет умер, чего tcpdump не может в принципе. На современных ядрах с CONFIG_DEBUG_INFO_BTF эти инструменты ставятся пакетом bpfcc-tools (или bcc-tools) и работают из коробки. Для разовых проверок удобен bpftrace-однострочник вместо целого скрипта. Strace и тяжелый perf для сети теперь нужны реже - eBPF дает то же самое с меньшим оверхедом.

Типичные грабли и заблуждения
  • "ping хороший, значит сеть ок". ping меряет ICMP RTT, но не видит потери на TCP-уровне, переполнение буферов сокета и ретрансмиты. Низкий пинг и тормозящее приложение - обычная комбинация.
  • "раз есть дропы - надо крутить буферы". Сначала пойми, ГДЕ дроп: missed на карте (ring), dropped в backlog и переполнение qdisc лечатся по-разному. Слепое увеличение rmem/wmem часто только маскирует проблему и съедает память, а на современных ядрах размеры буферов и так автотюнятся.
  • Запуск tcpdump без -n на нагруженном хосте. Резолвинг имен сам генерит трафик и искажает картину, а на 10G еще и роняет производительность. Почти всегда нужен -n, а лучше -w в файл.
  • Путать throughput и latency. "Скорость хорошая" (throughput) не отменяет того, что каждый запрос ждет лишний RTT из-за маленького cwnd или потерь.
  • Recv-Q путают с проблемой сети. Большой Recv-Q - это почти всегда твое приложение медленно читает из сокета, сеть тут ни при чем.
  • "netstat покажет". netstat и ifconfig устарели и местами врут на счетчиках дропов. На 2026 правильный набор - ss, ip, nstat, ethtool, и eBPF для глубины.
На Astra Linux и RED OS все эти команды (ss, ip, nstat, tcpdump, ethtool) штатные, bcc/bpftrace доступны из репозиториев, ядро с systemd - различий по сути нет.

Мини-лаба: проверь руками прямо сейчас
  • Запусти sudo ss -tinp state established и найди соединение с ненулевым Send-Q или retrans. Прочитай его rtt, cwnd и delivery_rate, прикинь, упирается ли throughput в окно (вспомни формулу окно/RTT).
  • Сделай ip -s link show <твой интерфейс> два раза с паузой и посмотри, растут ли dropped/missed/errors. Растут - запиши, какой именно счетчик, и проверь его драйверного двойника через sudo ethtool -S <iface> | grep -E "drop|miss".
  • Запусти nstat -az два раза с паузой под нагрузкой и найди, растут ли TcpRetransSegs и TcpExtListenDrops.
  • В одном терминале запусти sudo tcpdump -ni <iface> -tt "tcp port 443", в другом дерни любой https-сайт через curl. Найди в дампе SYN, SYN-ACK, ACK (рукопожатие) и прикинь RTT по меткам времени.
  • Если есть bpfcc-tools: запусти sudo tcpretrans под нагрузкой и сравни, что он ловит, с числом ретрансмитов из ss и nstat.
Контрольные вопросы
  • Чем отличается throughput от latency и почему канал может быть "широким", но "медленным"?
  • Что означают Recv-Q и Send-Q в выводе ss, и о чем говорит стабильно большой Recv-Q?
  • Зачем нужен NAPI и что произойдет, если CPU не успевает выгребать ring buffer (как это будет видно в top и в ip -s)?
  • Какой инструмент в 2026-м выберешь, чтобы с минимальным оверхедом увидеть, где именно ядро дропает TCP-сегмент, и почему не tcpdump?
Что запомнить
Пакет едет лифтом через слои: приложение - сокет - TCP/UDP - IP - qdisc - драйвер с ring buffer - провод, и обратно через прерывания и NAPI. Задержки и потери - это всегда переполненная сетевая очередь, и весь фокус в том, чтобы найти, КАКАЯ именно переполнилась. Сокеты и буферы смотришь через ss, сводные счетчики стека - через nstat, счетчики карты - через ip -s и ethtool, сами пакеты - через tcpdump, а первопричину дропов и ретрансмитов в 2026-м быстрее всего ловить через eBPF (tcpretrans/tcpdrop). Сначала карта, потом инструмент - в обратном порядке только теряешь время.
👍4 ❤️ 🔥1 😄 🤔
Аватара пользователя
sail44
Сообщения: 1
Зарегистрирован: 31 май 2026, 09:01

Re: Сетевой стек Linux: путь пакета и где возникают задержки

Сообщение sail44 »

Спасибо, наконец дошло про Recv-Q vs Send-Q. У меня как раз Recv-Q висел под 200к, грешил на провайдера, а оказалось воркер в апликухе тупо медленно читал сокет. Полез профилировать приложение.
👍1 ❤️1 🔥 😄 🤔
Аватара пользователя
kate4
Сообщения: 1
Зарегистрирован: 03 июн 2026, 17:12

Re: Сетевой стек Linux: путь пакета и где возникают задержки

Сообщение kate4 »

Поставил bpfcc-tools, запустил tcpdrop под нагрузкой - и сразу видно стек, где ядро рубит сегмент. tcpdump на 10g до этого захлебывался и я ничего не видел. Жаль раньше про eBPF не знал, годами сидел на tcpdump.
👍 ❤️ 🔥2 😄 🤔
Ответить
← Предыдущая глава
Кеш страниц и грязные данные: dirty pages, fsync, drop_caches
Следующая глава →
Сокеты и соединения: ss и netstat

Все главы курса «Диагностика и производительность Linux: логи, strace, perf и eBPF»

Поделиться темой: ✈ Telegram VK
  • Похожие темы
Похожие запросы: как посмотреть сколько памяти занято в linuxlsof кто держит файл и порт в linuxss как посмотреть открытые сокеты и соединенияperf top как найти что грузит процессорчто такое системный вызов и зачем трассироватьhtop и top как читать и в чем разница

Вернуться в «Диагностика и производительность Linux: логи, strace, perf и eBPF»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость