Суть Читай реальные трассы tcpdump, вывод ss и сниппет обработки соединений, предсказывай поведение TCP и выбирай фикс с наибольшим рычагом.
Высота — путь к senior
НольJuniorMiddleSenior
Ты на senior-высоте — в орбите
◷ 14 min
Захваты пакетов и дампы сокетов — это место, где реально диагностируются проблемы TCP. Читай каждую трассу, разбирай, что делает соединение, затем выбирай фикс, к которому senior-инженер потянется первым.
Цель
Отработай цикл, который ты запускаешь в каждом инциденте TCP: прочитай трассу или строку ss, восстанови механику sequence number и состояний, и назови ту единственную правку, что решает проблему до касания sysctl.
Четвёртый пакет несёт 14 байт данных, начиная с seq 1000001. Почему он начинается там, а не с 1000000, и что подтверждает ack 4200001?
Heads-up Резервного байта данных нет. Сдвиг — потому что сам SYN потребляет ровно один sequence number, поэтому данные приложения начинаются с ISN+1.
Heads-up Поле ACK — это следующий ожидаемый sequence number, а не счётчик байт. Это server-ISN+1, потому что SYN сервера потребил один номер; данные ещё не текли.
Heads-up Третий пакет — голый ACK; у четвёртого флаг PSH и payload 14 байт — это первая запись приложения, а не ретрансмит.
SyncookiesSent равно 41 827, но SyncookiesRecv всего 312. Сервер не уходит в нехватку памяти. Что происходит и почему сервер в безопасности?
Heads-up Это именно то, что предотвращают cookie — request_sock на SYN не аллоцируется. Высокий Sent при низком Recv — сигнатура поглощённого флуда, а не утечки.
Heads-up Низкий Recv ожидаем: флуд со спуфнутых источников никогда не завершает handshake, поэтому возвращается мало cookie. 312 — легитимные клиенты; валидация работает.
Heads-up Отключение cookie дало бы half-open очереди переполниться и отказывать легитимным клиентам. Cookie — это защита; цена — CPU на HMAC, а не память.
Трасса 3 — ss во время инцидента
$ ss -tan state established | wc -l12384$ ss -tan state close-wait | wc -l9821$ ss -sTCP: 23552 (estab 12384, closed 8920, orphaned 2, timewait 1247)$ ps -p 1234 -o pid,stat,rss,cmd PID STAT RSS CMD 1234 Ssl 8392000 /usr/bin/app-server # RSS растёт каждую минуту
Викторина
Completed
9.8k сокетов сидят в CLOSE-WAIT, а RSS продолжает расти. В чём баг и куда смотреть в коде?
Heads-up 1247 TIME-WAIT нормальны и самосливаются; утечка — это 9.8k CLOSE-WAIT, которые расчистит только close() в приложении. MSL тут ни при чём.
Heads-up Ядро не может освободить сокет в CLOSE-WAIT, пока приложение не вызовет close(). Это баг приложения, а не проблема производительности ядра.
Heads-up Диапазон портов управляет исходящим connect() и исчерпанием TIME-WAIT, а не накоплением входящих CLOSE-WAIT. Фикс — закрывать принятые сокеты, а не больше портов.
Трасса 4 — ss -tin на медленной передаче
$ ss -tin state established dst 203.0.113.20ESTAB 0 0 10.0.0.5:44120 203.0.113.20:443 cubic wscale:7,7 rtt:148.2/9.1 mss:1448 cwnd:11 ssthresh:8 bytes_sent:9M bytes_acked:9M retrans:0/214 reordering:12 rate:780Kbps
Викторина
Completed
RTT 148 мс, cwnd застрял на 11 MSS при ssthresh 8, 214 кумулятивных ретрансмитов и CUBIC — и всё же пропускная способность лишь 780 Кбит/с на быстром канале. Какой диагноз и самая перспективная правка?
Heads-up wscale:7 уже допускает многомегабайтное окно; ограничитель — что CUBIC режет cwnd до ~11 на потере. Правка — алгоритм congestion control, а не scale-фактор.
Heads-up 1448 — нормальный Ethernet MSS и не узкое место. Обвал cwnd от ретрансмитов под CUBIC и есть потолок пропускной способности; jumbo-фреймы всё равно не выживут на пути.
Heads-up ss сообщает его как ESTAB и активно шлющим. Ограничитель — реакция CUBIC на потерю на пути 148 мс, решается переходом на BBR.
Итог
Каждый инцидент TCP читается в трассах. Арифметика sequence number вытекает из одного правила: SYN (и FIN) потребляют по одному номеру, поэтому первый байт данных — ISN+1. Высокий SyncookiesSent при низком Recv — это поглощённый флуд, а не утечка. Завал CLOSE-WAIT с растущим RSS — всегда отсутствующий close() в приложении. А cwnd, прижатый низко с ретрансмитами под CUBIC на long-RTT lossy пути, — сигнатура, говорящая: переведи этот сокет на BBR. Диагностируй с провода и таблицы сокетов, затем делай ту единственную правку, на которую указывают данные.