Москва: проверенные б/у ноутбуки с гарантией и проверкой перед оплатой
+7 906 722-94-45

Главная → Статьи → tcpdump и ss: сетевая диагностика на Linux

Сетевая диагностика Linux: tcpdump, ss и разбор проблем с соединениями

Инструменты диагностики сети на сервере: ss по состояниям соединений, tcpdump-захват и фильтры, TIME_WAIT и retransmit, типичные диагнозы по выводам команд.

Прямой ответ

Когда «клиенты жалуются на соединение», а ping/curl-базис чист — уровень выше: ss (состояние сокетов — замена netstat: ss -tanp — все TCP-соединения с процессами; ss -s — сводка по состояниям; ss -tan state time-wait | wc -l — счётчик TIME_WAIT; ss -ti — внутренности: rtt/ретрансмиты/cwnd по соединению — «сеть плохая» доказывается цифрами, не ощущениями) и tcpdump (захват пакетов — последний аргумент: «что реально ходит по проводу» — SYN дошёл? RST от кого? ретрансмиты? — фильтры BPF: tcpdump -i any -nn port 8000 and host 10.0.1.5, запись в файл -w cap.pcap для Wireshark — «смотреть tcpdump глазами в проде» — только короткие сеансы с фильтрами — трафик большой). Три диагноза, которые эти инструменты ставят за минуты: (1) TIME_WAIT-накопление (тысячи сокетов в TIME_WAIT — активная сторона закрывает много коротких соединений — обычно клиент к БД/API без keepalive/пулинга — лечится пулингом/keepalive (PgBouncer/httpx-пулы), не «sysctl-ом по совету форума» — tcp_tw_reuse помогает исходящим, но причина — отсутствие переиспользования соединений); (2) переполнение backlog (ss -lnt — Recv-Q listen-сокета против Send-Q ( backlog-лимита) — Recv-Q растёт — приложение не принимает соединения быстрее поступления — «connection refused/timeout под нагрузкой» при живом процессе — воркеров мало/accept медленный — gunicorn-настройка); (3) ретрансмиты/потери (ss -ti — retrans:X/Y растёт, rto высокий — потери в сети/перегруз — tcpdump покажет дубли и SACK; netstat -s | grep -i retrans — глобальная статистика — рост доли ретрансмитов >1% — разговор с сетевиками с цифрами в руках). Плюс связка с процессами: ss -tanp — чей сокет (pid/имя — процессная диагностика) — «кто держит 300 соединений к БД» находится одной командой.

ss: состояния соединений и что они значат

TCP-состояния в выводе ss — словарь диагнозов: ESTAB (рабочие — счёт по сервисам: ss -tan state established '( dport = :5432 )' | wc -l — сколько соединений к БД — пул в норме/утёк); TIME_WAIT (закрытое активной стороной — норма жизни, тысячи — симптом коротких соединений без reuse; живёт 60 с (2MSL) — не «убивать», а не создавать — keepalive/пулы); CLOSE_WAIT (удалённая сторона закрыла, наша — нет — всегда баг приложения — сокет не закрыт в коде — накопление CLOSE_WAIT — классика «забытого response.close()»/утёкшего клиента (httpx-дисциплина: контекст-менеджеры закрывают); SYN_SENT (исходящий коннект без ответа — хост недоступен/файрвол дропает — «висит подключение» — tcpdump покажет уходящие SYN без ответа); SYN_RECV (много — SYN-flood или backlog-переполнение — ss -s + netstat -s | grep -i listen — drops/overflows счётчики — ядро считает отказанные accept'ы — ListenOverflows растёт — backlog мал/приложение медленно — somaxconn/backlog приложения — прокси-настройка — у nginx свой backlog к апстриму); FIN_WAIT_1/2 (закрываемся — массовое скопление — приложение рвёт соединения пачками — штатно при шторме рестартов). Полезные флаги: -t/-u TCP/UDP, -a все, -n без резолва (быстрее — резолв DNS на тысячах сокетов виснет), -p процессы (нужен root — чей сокет), -i внутренняя информация (rtt:X/Y, retrans, cwnd, unacked — качество канала по конкретному соединению — «до БД 40 мс rtt и 5% ретрансмитов» — аргумент в разговоре про «медленную БД»), -e — расширенное (таймеры — когда таймаут); сводка — ss -s (общие числа по состояниям — первый взгляд при инциденте). UDP — отдельная история (ss -uanp — Recv-Q растёт — потребитель не успевает — логи/statsd-агенты теряют датаграммы молча — UDP потерь не показывает — только очереди/счётчики ядерных дропов).

tcpdump: захват, фильтры, чтение

Базовые приёмы: tcpdump -i any -nn -s0 port 5432 (интерфейс any — не гадать какой; -nn — без DNS/портовых имён — быстрее и однозначнее; -s0 — полный пакет; фильтр порта/хоста — обязательно — «tcpdump без фильтра на проде» — гигабайты в секунду); запись для разбора — -w /tmp/cap.pcap -C 100 -W 5 (ротация файлов по 100 МБ — не убить диск — дисковая осторожность); чтение на месте — -A (ASCII payload — HTTP-запросы видны), -tttt (таймстампы), счётчики — -c 1000 (захватить N и выйти). BPF-фильтры — мини-язык (host 10.0.1.5 and port 8000, tcp[tcpflags] & tcp-syn != 0 — только SYN, tcp[tcpflags] & tcp-rst != 0 — кто шлёт RST — «connection reset» находит виновника: RST от сервера (порт не слушает/файрвол) против RST от клиента (таймаут/обрыв)); что искать в захвате по симптомам: connection refused — SYN → RST мгновенно (порт закрыт — процесс не слушает/не тот порт — сервис-дискавери в кластерном контексте); timeout — SYN уходят, ответа нет (дроп — файрвол/маршрут — traceroute/mtr соседствует); медленно — большие RTT в handshake, window zero (получатель не успевает — приложение не читает сокет — Recv-Q в ss подтверждает), ретрансмиты (одни и те же seq повторно — потери); reset при загрузке — RST после данных (прокси-таймаут/LB-лимит — nginx-таймауты); TLS-проблемы — handshake без application data (сертификат/версии — TLS-механика); «прокси виноват или бэкенд» — два захвата (перед и после прокси — сравнение таймстампов — вопрос закрывается фактами). Безопасность: захват содержит payload (пароли/данные в открытом трафике — pcap-файл — чувствительный артефакт — гигиена — удалять после разбора, не коммитить «пример в тикет»); TLS-трафик payload не покажет (только метаданные handshake — для содержимого — ключи приложения/SSLKEYLOGFILE — dev-сценарии).

Практический сценарий: «API intermittently отказывает» под нагрузкой

Исходник: жалобы — часть запросов к API (uvicorn за nginx) отваливается «connection timed out» волнами под нагрузкой; nginx-лог — upstream timed out; приложение «живо» (healthcheck зелёный). Диагностика по слоям: (1) ss -s на пике — 40 ESTAB к порту 8000 (ok), но ss -lnt — Recv-Q listen-сокета 8000: 129 при Send-Q 128 — backlog переполнен; (2) netstat -s | grep -iE "listen|overflow" — ListenOverflows растёт на 300/мин — ядро отбрасывает новые соединения в пике (клиент видит timeout, не refused — SYN дропнут молча — совпадает с жалобами); (3) tcpdump 30 с на 8000 — SYN-пакеты есть, часть без SYN-ACK — подтверждение дропа на входе, не в приложении-логике; (4) корень: backlog uvicorn (дефолт 2048? фактически — somaxconn машины = 128 — ядро обрезает backlog приложения до somaxconn — процесс-настройки) при 4 воркерах и всплесках accept-очереди; фикс: net.core.somaxconn=4096 (sysctl + конфиг — ansible на все узлы) + backlog=4096 в запуске uvicorn + воркеры 4→8 (процессная модель — CPU позволял); (5) проверка нагрузкой (locust — ступень ×3 от пика жалоб) — Recv-Q в норме (<10), ListenOverflows — ноль, таймауты исчезли; (6) мониторинг закрепил: ListenOverflows в node_exporter-алерт (метрики — рост = ранний сигнал), Recv-Q listen — панель в Grafana. Второй диагноз той же недели (для контраста): CLOSE_WAIT ×240 к внешнему API — скрипт отчётов не закрывал httpx-ответы в цикле — фикс в коде (with-блок) — ss-картина разошлась за час после деплоя; оба случая — одна методичка: ss-состояния → ядерные счётчики → tcpdump-подтверждение → фикс по причине.

FAQ

ss против netstat — что использовать? ss — современный (netlink из ядра напрямую — на порядок быстрее на тысячах сокетов, больше информации -ti/-e; netstat — парсит /proc — медленно и устарел (не входит в новые дистрибутивы — iproute2 против net-tools); исключением остаётся netstat -s — сводная ядерная статистика по протоколам (ss её не дублирует — альтернатива nstat -az); привычка «netstat -tulpn» переносится как «ss -tulpn» один в один — мигрировать мышление за минуту.

Почему TIME_WAIT — это нормально и сколько их допустимо? TIME_WAIT — гарантия корректного закрытия (2MSL — старые дубликаты пакетов не всплывут в новом соединении с теми же портами — протокольная необходимость на активной стороне); десятки тысяч — не катастрофа сама по себе (память ~сокета мала — порт-ресурс расходуется по паре «ip:port-назначения» — к одному backend:port — предел ~28k исходящих); «лечить» нужно причину (короткие соединения пачками — keepalive/пулы — паттерн); sysctl tcp_tw_reuse=1 — безопасно для исходящих (клиентская сторона) и помогает; tcp_tw_recycle — удалён из ядра (4.12+) и опасен за NAT (старые статьи его советуют — не применять — «совет с форума убил коннективность за NAT» — классика).

Как диагностировать UDP-потери (метрики/логи/статсd)? UDP не имеет состояний/ретрансмитов — «потеря» невидима на уровне протокола; признаки: Recv-Q растёт на слушающем сокете (ss -uanp — потребитель не успевает — увеличивать буферы SO_RCVBUF/число читателей), ядерные дропы — netstat -su / nstat -az | grep -i udp (RcvbufErrors/InErrors — переполнение буфера — сокеты дропают до приложения); tcpdump покажет, что пакеты доходят (претензия к сети снимается — потеря в стеке/приложении); приложения-получатели метрик (statsd-агенты) считают drops сами — метрика «dropped» — инструментировать получателя (метрики); для критичных данных UDP без прикладного подтверждения — архитектурная ошибка (переходить на TCP/очереди — доставка с гарантиями).

Нужен ли Wireshark, если есть tcpdump? Разделение труда: захват — tcpdump (сервер, headless, фильтры/ротация — ssh-сессия не нужна для анализа), разбор — Wireshark на своей машине (pcap скачан — GUI: follow TCP stream, статистика ретрансмитов, экспертные предупреждения, декодирование протоколов — на порядок продуктивнее чтения hex-дампа); «tcpdump -A глазами на 50 пакетов» — законно для быстрого «дошёл ли SYN/кто RST»; систематический разбор (ретрансмиты/window-проблемы/TLS-handshake) — Wireshark; tshark (консольный Wireshark) — середина (скриптуемый разбор на сервере).

Источники: man tcpdump/ss, документация ядра (ip-sysctl) — ссылки в шапке.