Сети и протоколы
TCP handshake: измерь и укроти churn соединений
Читать про handshake и TIME-WAIT — не то же самое, что смотреть, как сервис тонет в churn соединений, и вытаскивать его. Собери маленький клиент/сервер, загони его в реальную проблему соединения-на-запрос и примени рычаги юнита — пулинг, тюнинг, congestion control — пока числа не вернутся, с доказательствами на уровне пакетов на каждом шаге.
Преврати ментальную модель юнита в воспроизводимый инженерный цикл: захвати handshake на проводе, воспроизведи отказ по задержке и исчерпанию портов от churn соединений, почини его структурно и проверь числами до/после, измеренными под одинаковой нагрузкой.
Возьми клиент, открывающий новое TCP-соединение на каждый запрос к бэкенду, воспроизведи задержку и отказ TIME-WAIT/исчерпания портов, который он вызывает под нагрузкой, затем устрани его пулингом соединений плюс верным тюнингом ядра — доказывая каждый шаг захватами пакетов, выводом ss и измеренной задержкой, а не оценками.
- Таблица до/после: p50/p99 задержки запроса, handshake в секунду и счёт сокетов TIME-WAIT — всё измерено под одинаковой нагрузкой, не оценено.
- Аннотированный захват handshake (до) и захваченный запрос, переиспользующий установленное соединение (после), показывающий отсутствующий round-trip handshake.
- Счёт TIME-WAIT и ошибки EADDRNOTAVAIL исчезли (или резко снижены) после пулинга, подтверждено из ss, с однострочным обоснованием каждой изменённой настройки ядра.
- Короткое описание, называющее единственный структурный рычаг (переиспользование соединений) и объясняющее, почему один тюнинг sysctl — включая укороченный MSL — не был бы верным фиксом.
- Добавь демо SYN-флуда против listener с включённым tcp_syncookies, захвати счётчики SyncookiesSent/Recv из nstat и объясни, что теряют легитимные long-RTT клиенты, пока cookie активны.
- На netem-пути с ~1% случайных потерь измерь пропускную способность под CUBIC против BBR через ss -tin (следи за cwnd, ssthresh, retrans) и покажи, как BBR держит пропускную способность там, где CUBIC обваливается.
- Добавь on-call runbook: триаж исчерпания TIME-WAIT и утечек CLOSE-WAIT из ss менее чем за пять минут, лестницу приоритета фиксов (пул раньше tw_reuse раньше port-range раньше MSL) и чек-лист проверки.
- Воспроизведи стопор Nagle плюс delayed-ACK 40–200 мс на мелких конвейерных записях, затем покажи, как TCP_NODELAY его убирает, с p99 до/после из той же трассы.
Это цикл, который ты будешь запускать в каждом реальном инциденте churn соединений: захвати handshake, чтобы увидеть round-trip, который платишь, воспроизведи отказ (задержка от соединений-на-запрос, исчерпание портов от TIME-WAIT), почини на структурном уровне пулом keep-alive, добавь только тот тюнинг ядра, который оправдывают данные, и проверь числами до/после под одинаковой нагрузкой. Сделав это раз на игрушечном сервисе, ты переведёшь production-версию в мышечную память — и поймёшь, почему пулинг, а не укороченный MSL, и есть верный рычаг.