Зачем вообще смотреть backlog и SYN-ACK retransmits
В продакшене история «сервер медленно отвечает» часто начинается не с CPU и не с диска, а с сетевых очередей TCP. На уровне симптомов вы видите:
- рост SYN-ACK retransmits (повторные SYN-ACK со стороны сервера);
- сообщения в логах ядра/сервиса про accept queue overflow;
- скачки 5xx/таймаутов на балансере при внешне «живом» сервисе;
- под нагрузкой новые соединения «не проходят», но уже установленные работают.
Чтобы диагностировать это быстро, держите в голове две очереди:
- SYN backlog — очередь полуоткрытых соединений (SYN получен, SYN-ACK отправлен, ACK от клиента ещё не пришёл).
- accept queue — очередь полностью установленных соединений, которые готовы, но приложение ещё не успело сделать
accept().
Термин listen backlog часто используют как «размер очереди на listening socket», но реальное поведение зависит от ядра, sysctl и того, как именно приложение слушает порт.
Короткая модель: что происходит при входящем TCP-соединении
Упрощённо TCP handshake и очередь выглядят так:
- Клиент посылает SYN.
- Сервер отвечает SYN-ACK и кладёт соединение в SYN backlog.
- Клиент отвечает ACK — соединение становится «полностью установленным» и попадает в accept queue.
- Приложение вызывает
accept()и забирает соединение из accept queue.
Если переполняется SYN backlog, новые SYN начинают дропаться/отклоняться (как именно — зависит от настроек и версии ядра). Если переполняется accept queue, ядро не может «припарковать» уже установленные соединения до того, как приложение их примет.
Почему растут SYN-ACK retransmits
SYN-ACK retransmits означают: сервер отправил SYN-ACK, но не получил подтверждение (ACK) вовремя и переслал SYN-ACK снова. Причины обычно в трёх зонах:
- Сеть/клиент: потери пакетов, перегрузка канала, асимметричная маршрутизация, stateful middlebox, проблемы MTU.
- Сервер: перегрузка CPU/softirq, переполненные очереди, дропы на уровне NIC/драйвера.
- Параметры ядра: слишком маленький
net.ipv4.tcp_max_syn_backlog(и связанные ограничения), из-за чего часть рукопожатий ломается на пике.
Рост SYN-ACK retransmits сам по себе не доказывает переполнение очередей, но часто идёт рядом с ситуацией «SYN backlog на пределе».

Быстрая проверка состояния: ss -s и /proc/net/sockstat
ss -s: агрегаты по TCP/UDP
Начинайте с общей картины:
ss -s
В контексте backlog полезно понять:
- сколько всего TCP соединений и в каких состояниях (например,
estab,timewait,syn-recv); - есть ли заметный объём
SYN-RECV(полуоткрытые соединения); - растёт ли это именно на пике, коррелируя с ошибками/таймаутами.
Если вы видите «залипание» SYN-RECV на высоких значениях — копайте SYN backlog и параллельно сетевые потери/фильтрацию.
/proc/net/sockstat: сокеты и память
Второй быстрый «датчик» — состояние сокетов ядра:
cat /proc/net/sockstat
Если важен IPv6-стек, дополнительно:
cat /proc/net/sockstat6
Смотрите на общую картину по TCP: сколько сокетов в use и сколько памяти занято буферами. Это не покажет конкретный порт, но помогает понять, упираетесь ли вы в ресурсность сетевого стека на хосте.
Если вы тюните сеть регулярно (или ловите такие инциденты раз в квартал), удобно собрать базу по sysctl и наблюдаемым эффектам в одном месте. См. также практику сетевого тюнинга sysctl в Linux.
Как увидеть listen backlog и переполнение accept queue
В большинстве инцидентов полезно ответить на два вопроса:
- переполняется ли accept queue (приложение не успевает принимать соединения);
- переполняется ли SYN backlog (не успевает/не может завершиться рукопожатие).
Смотрим очереди на listening сокетах через ss
Чтобы увидеть очереди (Send-Q/Recv-Q) для слушающих портов:
ss -lntp
Типичная интерпретация для строк в состоянии LISTEN:
- Recv-Q — сколько соединений стоят в accept queue и ждут, пока приложение сделает
accept(). - Send-Q — лимит accept queue (фактический размер очереди на данном сокете).
Если у конкретного порта Recv-Q стабильно приближается к Send-Q на пике и держится там — это почти прямой признак accept queue overflow (или того, что вы очень близко к нему).
netstat: если привыкли, можно и так
На старых системах/в старых гайдах встретите netstat:
netstat -lntp
Смысл тот же: сравнивайте текущую очередь с лимитом для нужного порта.
Какие sysctl связаны с listen backlog: somaxconn и tcp_max_syn_backlog
Два параметра всплывают почти всегда:
net.core.somaxconn— верхняя граница backlog уlisten()со стороны ядра (потолок для accept queue на сокет).net.ipv4.tcp_max_syn_backlog— размер SYN backlog (полуоткрытые TCP).
Проверить текущие значения:
sysctl net.core.somaxconn
sysctl net.ipv4.tcp_max_syn_backlog
Или через /proc:
cat /proc/sys/net/core/somaxconn
cat /proc/sys/net/ipv4/tcp_max_syn_backlog
Важная оговорка про listen backlog
Приложение передаёт в listen(fd, backlog) желаемый backlog, но ядро может ограничить его (например, через net.core.somaxconn). Поэтому типовая ловушка такая:
- в конфиге Nginx/HAProxy/приложения написано «backlog 4096»;
- в ядре
somaxconnстоит 128 или 512; - фактическая accept queue заметно меньше ожиданий.
Проверка через ss -lntp как раз и показывает фактический лимит (Send-Q) для каждого слушающего сокета.
Диагностика по симптомам: что именно упирается
Сценарий A: растёт Recv-Q на LISTEN, SYN-RECV небольшой
Чаще всего это означает «приложение не успевает принимать соединения»:
- мало воркеров/потоков accept;
- воркеры заняты (CPU bound, блокировки, медленные внешние вызовы);
- слишком маленький backlog (ограничен
somaxconn); - scheduler/CPU steal в виртуализации;
- лимиты по файловым дескрипторам (процесс не может принять/открыть новый сокет).
Повышение somaxconn и backlog в приложении помогает, если сервис в целом вывозит поток, но ему не хватает «буфера» на пики. Если же сервис системно не вывозит — backlog лишь отсрочит отказ и может увеличить latency установления соединения.
Сценарий B: много SYN-RECV и рост SYN-ACK retransmits
Это уже про рукопожатие и SYN backlog/сеть:
- потери пакетов на пути клиент↔сервер;
- фильтрация SYN/ACK (фаерволы, stateful middleboxes);
- перегрузка сетевого стека на сервере (softirq, drops на интерфейсе);
- малый
tcp_max_syn_backlogна пике.
Проверьте, не «зажат» ли SYN backlog, и параллельно смотрите дропы/ошибки на интерфейсе и нагрузку на softirq.
Сценарий C: и SYN-RECV, и Recv-Q на LISTEN растут
Так бывает при резкой шиповой нагрузке, когда сервер одновременно:
- не успевает завершать рукопожатия (SYN backlog);
- и не успевает принимать уже установленные соединения (accept queue).
В этом сценарии «крутить sysctl» без понимания источника нагрузки и профиля приложения опасно: можно увеличить потребление памяти ядром и сделать деградацию тяжелее.
Практический чек-лист: команды для инцидента
1) Найти проблемный порт и увидеть очередь accept
ss -lntp
Сразу выпишите:
- какой порт(ы) на пике имеют высокий
Recv-Q; - какой лимит
Send-Q; - какой процесс (PID/имя) слушает.
2) Посмотреть, есть ли много полуоткрытых
ss -ant state syn-recv | wc -l
И для общего среза:
ss -s
3) Снять sockstat
cat /proc/net/sockstat
4) Проверить sysctl по теме
sysctl net.core.somaxconn
sysctl net.ipv4.tcp_max_syn_backlog
5) Быстро исключить «упёрлись в лимиты процесса»
Для процесса, который слушает порт, полезно проверить лимиты файлов:
pidof nginx
cat /proc/$(pidof nginx)/limits | sed -n '1,40p'
Если это не nginx, подставьте PID вашего сервиса. Иногда «очередь заполнена» оказывается вторичным симптомом: процесс не может принять соединение из-за лимитов или ошибок (например, уткнулся в open files).
Тюнинг: что менять и как не навредить
Сетевой тюнинг имеет смысл, когда вы уверены, что приложение и архитектура в целом корректны, а проблема именно в буферизации пиков и настройках ядра.
somaxconn: поднять лимит accept queue
Посмотреть текущее значение:
sysctl net.core.somaxconn
Временно (до перезагрузки):
sysctl -w net.core.somaxconn=4096
Постоянно (пример для Debian/Ubuntu через отдельный файл):
cat > /etc/sysctl.d/99-backlog.conf << 'EOF'
net.core.somaxconn = 4096
EOF
sysctl --system
Дальше убедитесь, что приложение/веб-сервер тоже выставляет достаточный backlog. Иначе вы подняли потолок, но фактический backlog на сокете не изменится.
tcp_max_syn_backlog: увеличить SYN backlog
Посмотреть:
sysctl net.ipv4.tcp_max_syn_backlog
Временно:
sysctl -w net.ipv4.tcp_max_syn_backlog=8192
Постоянно:
cat >> /etc/sysctl.d/99-backlog.conf << 'EOF'
net.ipv4.tcp_max_syn_backlog = 8192
EOF
sysctl --system
Увеличение tcp_max_syn_backlog особенно уместно при кратковременных всплесках новых подключений (релизы, массовые кроны, «прогрев» клиентов).
Как понять, помогло ли
Минимальный набор критериев после изменения:
- на пике
Recv-Qу LISTEN реже упирается вSend-Q; - уменьшается доля таймаутов/ошибок подключения на клиентах/балансере;
- число
SYN-RECVперестаёт «залипать» на высоких значениях; - падает уровень SYN-ACK retransmits (если причина была в перегрузе очередей, а не в сети).
Backlog — это не «ускоритель сервера», а буфер. Он помогает переживать пики, но не заменяет производительность приложения, достаточное число воркеров и нормальную сеть.

Частые ошибки и ловушки интерпретации
Ошибка 1: лечить SYN-ACK retransmits только sysctl
Если причина в потере пакетов или фильтрации на сети, увеличение tcp_max_syn_backlog даст слабый эффект или не даст вовсе. В таких случаях параллельно проверяйте дропы на интерфейсе (RX/TX), загрузку softirq и путь трафика (особенно если есть L4/L7 балансеры).
Ошибка 2: поднять somaxconn, но не поднять backlog в приложении
somaxconn — это потолок. Если ваш сервер слушает с backlog 128, он и останется 128 (или около того), даже если somaxconn стал 4096. Всегда проверяйте факт через ss -lntp.
Ошибка 3: игнорировать лимиты файловых дескрипторов
Когда у процесса заканчивается лимит на открытые файлы/сокеты, входящие соединения начинают «сыпаться» похоже на backlog-проблему. Держите в голове связку: очередь переполнена ↔ процесс не принимает ↔ возможно, он не может принять из-за лимита.
Ошибка 4: считать, что переполненный accept queue всегда означает атаку
Атака возможна, но на практике переполнение accept queue часто случается и при легитимных всплесках: массовый рестарт клиентов, перегрузка пула воркеров, ошибка в приложении, медленный upstream, блокировки в БД. Начинайте с измерений и корреляции по времени.
Набор «полевых» метрик, которые стоит добавить в мониторинг
Чтобы ловить такие проблемы по графикам, а не по жалобам, добавьте регулярный сбор:
ss -s(агрегаты TCP, долиSYN-RECV);ss -lntp(очереди для ключевых портов:Recv-Q/Send-Q);/proc/net/sockstat(сокеты/память);- дропы/ошибки интерфейса и загрузку softirq (для корреляции с retransmits).
Если у вас на входе есть L4-балансировка (stream) и хочется устойчивее переживать пики, пригодится материал про балансировку TCP/UDP в Nginx stream и контроль очередей на нодах.
Если проблема повторяется: куда копать глубже
Когда вы уже убедились, что listen backlog и sysctl настроены разумно, а переполнение всё равно происходит, первопричина обычно в том, что приложение не успевает:
- увеличьте параллелизм обработки (воркеры/пулы), проверьте блокировки;
- сократите время обработки запроса (БД, внешние API, I/O);
- пересмотрите модель keep-alive и лимиты соединений на балансере;
- проверьте, нет ли шипов из-за деплоя/рестартов/GC (JVM/Go/Python).
Сетевые очереди — место, где проблема становится видимой, но первопричина часто выше по стеку.
Итог
Для практической диагностики проблем уровня accept queue overflow и SYN-ACK retransmits обычно хватает трёх опор:
ss -lntp— увидеть факт переполнения accept queue черезRecv-Q/Send-Q;ss -s— понять долю полуоткрытых соединений и общую картину TCP;/proc/net/sockstat— подтвердить состояние сокетов/ресурсов ядра.
Дальше — аккуратный тюнинг net.core.somaxconn и net.ipv4.tcp_max_syn_backlog плюс проверка, что приложение действительно может использовать увеличенные очереди. Если же очереди растут из-за того, что сервис не успевает принимать/обрабатывать запросы, backlog лишь маскирует проблему и отодвигает её на несколько секунд.
Когда нужно быстро дать сервису ресурсы и изолировать соседей по железу, чаще всего удобнее переехать на VDS: проще прогнозировать CPU/сеть и безопаснее крутить сетевые лимиты под вашу нагрузку.


