TCP handshake: чтение трасс и кода
Читай реальные трассы tcpdump, вывод ss и сниппет обработки соединений, предсказывай поведение TCP и выбирай фикс с наибольшим рычагом.
Захваты пакетов и дампы сокетов — это место, где реально диагностируются проблемы TCP. Читай каждую трассу, разбирай, что делает соединение, затем выбирай фикс, к которому senior-инженер потянется первым.
Отработай цикл, который ты запускаешь в каждом инциденте TCP: прочитай трассу или строку ss, восстанови механику sequence number и состояний, и назови ту единственную правку, что решает проблему до касания sysctl.
Трасса 1 — handshake на проводе
14:02:11.001 IP 10.0.0.5.51514 > 10.0.0.9.6379: Flags [S], seq 1000000, win 64240, length 0
14:02:11.001 IP 10.0.0.9.6379 > 10.0.0.5.51514: Flags [S.], seq 4200000, ack 1000001, win 65160, length 0
14:02:11.002 IP 10.0.0.5.51514 > 10.0.0.9.6379: Flags [.], seq 1000001, ack 4200001, win 64240, length 0
14:02:11.002 IP 10.0.0.5.51514 > 10.0.0.9.6379: Flags [P.], seq 1000001, ack 4200001, win 64240, length 14
Четвёртый пакет несёт 14 байт данных, начиная с seq 1000001. Почему он начинается там, а не с 1000000, и что подтверждает ack 4200001?
Трасса 2 — SYN-флуд под cookie
$ sudo tcpdump -i eth0 'tcp[tcpflags] & tcp-syn != 0' -tnn
IP 203.0.113.7.40001 > 198.51.100.10.443: Flags [S], seq 100, win 29200, length 0
IP 198.51.100.10.443 > 203.0.113.7.40001: Flags [S.], seq 3851629874, ack 101, win 28960, length 0
IP 203.0.113.9.55000 > 198.51.100.10.443: Flags [S], seq 200, win 29200, length 0
IP 198.51.100.10.443 > 203.0.113.9.55000: Flags [S.], seq 4025814937, ack 201, win 28960, length 0
(ещё тысячи SYN от случайных источников; почти ни один не шлёт финальный ACK)
$ nstat -az | grep -i syncookies
TcpExtSyncookiesSent 41827
TcpExtSyncookiesRecv 312
SyncookiesSent равно 41 827, но SyncookiesRecv всего 312. Сервер не уходит в нехватку памяти. Что происходит и почему сервер в безопасности?
Трасса 3 — ss во время инцидента
$ ss -tan state established | wc -l
12384
$ ss -tan state close-wait | wc -l
9821
$ ss -s
TCP: 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 растёт каждую минуту
9.8k сокетов сидят в CLOSE-WAIT, а RSS продолжает расти. В чём баг и куда смотреть в коде?
Трасса 4 — ss -tin на медленной передаче
$ ss -tin state established dst 203.0.113.20
ESTAB 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
RTT 148 мс, cwnd застрял на 11 MSS при ssthresh 8, 214 кумулятивных ретрансмитов и CUBIC — и всё же пропускная способность лишь 780 Кбит/с на быстром канале. Какой диагноз и самая перспективная правка?
Каждый инцидент TCP читается в трассах. Арифметика sequence number вытекает из одного правила: SYN (и FIN) потребляют по одному номеру, поэтому первый байт данных — ISN+1. Высокий SyncookiesSent при низком Recv — это поглощённый флуд, а не утечка. Завал CLOSE-WAIT с растущим RSS — всегда отсутствующий close() в приложении. А cwnd, прижатый низко с ретрансмитами под CUBIC на long-RTT lossy пути, — сигнатура, говорящая: переведи этот сокет на BBR. Диагностируй с провода и таблицы сокетов, затем делай ту единственную правку, на которую указывают данные.
Что-то непонятно?
Задай вопрос по этому уроку. Вопросы анонимны и попадают напрямую автору — урок станет лучше.