Ошибка в логах ядра. request_sock_TCP: Possible SYN flooding

Введение

Столкнулся с ошибкой “kernel: TCP: request_sock_TCP: Possible SYN flooding on port 5005. Sending cookies. Check SNMP counters” на RHEL 7. Для понимания и закрепления информации изучил различные источники и задокументировал основные моменты.

SYN Queue

В целом нужно понимать, как работает TCP, у которого есть некий буфер очередей на кол-во соединений. И когда сервис не справляется с наплывом клиентов и перестает обрабатывать новые соединения, они накапливаются в backlog, т.е. в той самой очереди.
Тут-то в игру и вступают SYN Cookie, которые являются механизмом ядра от Red Hat. При заполнении очереди, ядро формирует куки с содержанием специального SYN+ACK, в котором порядковый номер TCP является функцией времени, MSS и IP-адресов клиента и сервера. И в итоге куки позволяют устанавливать TCP-соединения, когда очередь сокета переполнена по какой-либо причине (SYN flood атака или само приложение уже упёрлось в лимиты).
Для конечного пользователя это всё хорошо, т.к. его соединение не будет дропнуто. А вот для сервера, где такие сообщения об отправке кук встречаются очень часто, является нехорошим признаком того, что пора тюнить ядро.
Отключать куки не рекомендуется, поэтому необходимо выявить, где установлены лимиты, и увеличить их.

Ранее говорилось про бэклог, т.е. некую очередь. Так вот существует две очереди у каждого сокета. У этих очередей имеются различные названия, например, «reqsk_queue», «ACK backlog», «listen backlog» или даже «TCP backlog», но их корректные наименования представлены ниже:

  • SYN queue, когда сервер получает SYN, шлет SYN-ACK и не получает ACK в ответ, т.е. получается полу-открытое соединение и ожидание ACK – последнего пакета для установления хендшейка. Повторная отправка SYN-ACK ограничена лимитом в net.ipv4.tcp_synack_retries. После получения ACK, ядро Linux удаляет элемент из очереди SYN и перемещает его в следующую очередь приёма. Когда таких соединений накапливается большое кол-во, формируется очередь, на размер которой влияет параметр tcp_max_syn_backlog;
  • Accept queue содержит в себе уже полностью установленные соединения и их кол-во ограничивает net.core.somaxconn

В интернете гуляет множество ответов по запросу “kernel: TCP: request_sock_TCP: Possible SYN flooding”, где предлагается увеличить и net.ipv4.tcp_max_syn_backlog и net.core.somaxconn. В конечном итоге в статье cloudflare было сказано, что в настоящее время за размер и SYN очереди и Accept очереди отвечает один параметр net.core.somaxconn, т.е. тюнингу подлежит именно он, и у cloudflare его значение имеет следующее значение:

$ sysctl net.core.somaxconn
net.core.somaxconn = 16384

Про тюнинг ядра

Я не буду писать про то, в чём досконально не разбираюсь, а именно про тюнинг ядра. В интернете есть много примеров с описанием, в т.ч. даже в исходном коде. Поэтому кратко выписал основные параметры, которые в рамках данной статьи могут быть интересны:

а) net.ipv4.tcp_syncookies = 1 – включает куки (по дефолту включены)
б) net.core.somaxconn – максимальное кол-во открытых сокетов, ждущих соединения, по дефолту значение 128
в) net.ipv4.tcp_max_syn_backlog – максимальное кол-во запоминаемых запросов на соединения, для которых не было получено подтверждения от подключающегося клиента, по дефолту значение 128
г) net.ipv4.tcp_synack_retries – кол-во попыток отправки SYN-ACK пакетов, дефолтом 5.

И в конце возникает главный вопрос: какое же значение наиболее корректное? Ответ, как правило, звучит так – зависит от ситуации и обстоятельств. Да, тюнинг ядра такая вещь, что нет универсальных рецептов. Тем не менее можно взять за основу следующие утверждения:

  • “Простым” серверам, которыми в большинстве случаев являются не сильно нагруженные проекты типа интернет-магазина или корпоративного портала, данный вид тюнинга вообще не требуется. А вот серверам, например, которые обслуживают клиентские чаты на часто посещаемом сайте, такой вид тюнинга точно понадобится с увеличением количества пользователей;
  • Если большинство клиентов находятся физически далеко от сервера, т.е. имеют более высокие задержки, то значение очередей также можно подтюнить в большую сторону;
  • Увеличение в большую сторону бездумно имеет негативные последствия и отразится на памяти – каждый слот в SYN-очереди будет занимать 256 байт (ядро 4.14) и при SYN Flood-атаке память может закончиться.

Средства диагностики

Как понять, что очередь заполнена и с этим имеются проблемы, кроме косвенных признаков медленного соединения? В команде ниже размер глобальных счётчиков TcpExtListenOverflows и TcpExtListenDrops будет активно расти, входящие пакеты SYN и ACK в SYN-очередь дропаются:

nstat -az | grep -i listen

TcpExtListenOverflows           3518352            0.0
TcpExtListenDrops               3518388            0.0
TcpExtTCPFastOpenListenOverflow 0  0.0

То, что пакеты дропаются, в целом нормальное поведение – клиент рано или поздно повторит отправку SYN или ACK. Но если такое происходит постоянно и из-за этого возникают проблемы, то необходимо заниматься ещё более тонкой настройкой ядра и приложения, что уже выходит за рамки данного материала.

Наконец, можно воочию посмотреть на кол-во соединений в очереди SYN, используя netstat или более современный аналог ss:

ss -n state syn-recv sport = :443 | wc -l

Если в очереди нет соединений, то в команде выше будет пустой результат, т.е. всё хорошо. Ещё более наглядный пример:

ss -plnt sport = :443 | cat
State   Recv-Q Send-Q  Local Address:Port  Peer Address:Port
LISTEN  0      1024                *:6443             *:*

Цифры в Recv-Q показывают кол-во сокетов в Accept очереди, а Send-Q размер бэклог-лимита.

Заключение

Когда приложение не успевает по каким-либо причинам обработать все соединения, начинает накапливаться очередь и параметр somaxconn её регулирует. Если очередь мала, то клиент отвалится, т.е. будет разрыв соединения, а если очередь будет большого размера, то у клиента будут задержки в работе, но соединение не разорвётся. Так и получилось, что у меня пришло сообщение в логе про куки – лимиты заполнились, а nginx не успевал обрабатывать соединения и немного подтупливал.

Вообще тема тюнинга больше актуальна на больших проектах, о чем я уже говорил, но в какой-то момент возникает тонкая грань, по которой надо будет определять, когда проект постепенно начинает из среднего перерастать в большой. Для этого, как минимум, нужно настраивать мониторинг и наблюдать за динамикой собираемых метрик приложения и ОС.

UPD. Спустя какое-то время после написания данного материала вышла интересная статья на хабре, решил обновить пост и указать на неё ссылку, т.к. там неплохо рассказывается про сетевой стек в Linux и его настройку для хайлоада.

Используемые источники

Понравилась статья? Поделиться с друзьями:
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: