- Настройка сетевого стека Linux для высоконагруженных систем
- Максимизируем количество входящих соединений
- Очередь приема и netdev_max_backlog
- Очередь ожидающих запросов на соединение и tcp_max_syn_backlog
- SYN Cookie
- Повторы SYN+ACK
- Повторы SYN
- Очередь установленных соединений ожидающих принятия (accept queue) и somaxconn
- somaxconn и параметр backlog в listen()
- Значения по умолчанию для очереди
- Изменение размера очереди
- Потоки
- Соединения и файловые дескрипторы
- Системные ограничения
- Пользовательские ограничения
- Настройка
- Количество worker’ов
- Системные ограничения
- Пользовательские ограничения
- Настройка
- Обратный прокси и TIME_WAIT
- Собираем все вместе
- Параметры
- Заключение
- 1.tcp basis
- 2.tcp_max_syn_backlog
- 3.net.core.somaxconn
- 4. parameters
- 4.1 temporary changes
- 4.2 permanent changes
Настройка сетевого стека Linux для высоконагруженных систем
Максимизируем количество входящих соединений
В рамках набора учащихся на курс «Administrator Linux. Professional» подготовили перевод полезного материала.
Приглашаем всех желающих посетить открытый демо-урок «Практикум по написанию Ansible роли». На этом вебинаре участники вместе с экспертом будут писать, тестировать и отлаживать ansible роли. Это важно для тех, кто хочет автоматизировать настройку инфраструктуры, поскольку это один из инструментов, который это позволяет сделать. Сетевой стек — одна из самых запутанных вещей в Linux. И не только из-за сложности некоторых концепций и терминов, но и из-за изменения смысла некоторых параметров в разных версиях ядра. В этой статье приведена информация для ядра 2.2 и выше, а также, там где это возможно, указано различие между версиями вплоть до 5.5.
О том как изменять параметры ядра, описываемые здесь, можно прочитать в статье Linux Kernel Tuning for High Performance Networking: Configuring Kernel Settings.
Очередь приема и netdev_max_backlog
Каждое ядро процессора перед обработкой пакетов сетевым стеком может хранить их в кольцевом буфере. Если буфер заполняется быстрее, чем TCP-стек обрабатывает пакеты, то пакеты отбрасываются и увеличивается счетчик отброшенных пакетов (dropped packet counter). Для увеличения размера очереди следует использовать параметр net.core.netdev_max_backlog .
net.core.netdev_max_backlog — параметр задается на ядро процессора.
Очередь ожидающих запросов на соединение и tcp_max_syn_backlog
Соединения создаются для SYN-пакетов из очереди приема и перемещаются в очередь ожидания (SYN Backlog Queue). Также соединение помечается как «SYN_RECV» и клиенту отправляется «SYN+ACK». Эти соединения не перемещаются в очередь установленных соединений ожидающих обработки accept() (accept queue) до тех пор, пока не будет получен и обработан соответствующий ACK. Максимальное количество соединений в этой очереди устанавливается параметром net.ipv4.tcp_max_syn_backlog .
Для просмотра очереди приема используйте команду netstat . На правильно настроенном сервере при нормальной нагрузке значение не должно быть больше 1. При большой нагрузке значение должно быть меньше размера очереди ожидания (SYN Backlog):
Если в состоянии «SYN_RECV» находятся много соединений, то можно также подстроить продолжительность нахождения SYN-пакета в этой очереди.
SYN Cookie
Если SYN cookie отключены, то клиент просто повторяет отправку SYN-пакета. Если включены (net.ipv4.tcp_syncookies), то соединение не создается и не помещается в SYN backlog, но клиенту отправляется SYN+ACK, так как если бы это было сделано на самом деле. SYN cookie могут быть полезны при нормальной нагрузке, но при всплесках трафика некоторая информация о соединении может быть потеряна и клиент столкнется с проблемами, когда соединение будет установлено. Подробнее о SYN cookie можно прочитать в статье Грэма Коула (Graeme Cole) SYN cookies ate my dog (SYN cookie съели мою собаку), в которой подробно объясняется, почему включение SYN cookie на высоконагруженных серверах может привести к проблемам.
Повторы SYN+ACK
Что происходит, если SYN+ACK отправлен, но ответа ACK нет? В этом случае сетевой стек сервера повторит отправку SYN+ACK. Задержка между попытками вычисляется таким образом, чтобы обеспечить восстановление сервера. Если сервер получает SYN и отправляет SYN+ACK, но не получает ACK, то тайм-аут повторной передачи вычисляется по экспоненте (Exponental Backoff) и, следовательно, зависит от количества повторных попыток. Количество повторных попыток отправки SYN+ACK задается параметром ядра net.ipv4.tcp_synack_retries (по умолчанию равно 5). Повторные попытки будут через следующие интервалы: 1с, 3с, 7с, 15с, 31с. При шести попытках последняя будет примерно через 63 секунды после первой. Это позволяет удержать SYN-пакет в очереди ожидания более 60 секунд до истечения времени ожидания пакета. Если очередь SYN backlog мала, то не требуется большого количества соединений, чтобы возникла ситуация, когда полуоткрытые соединения никогда не завершатся и тогда никакие соединения не смогут быть установлены. Установите количество повторных попыток SYN+ACK равным 0 или 1, чтобы избежать такого поведения на высоконагруженных серверах.
Повторы SYN
Несмотря на то что повторные SYN-пакеты отправляются клиентом во время ожидания SYN+ACK, они могут влиять и на высоконагруженные сервера, работающие с прокси-соединениями. Например, сервер nginx, устанавливающий несколько десятков прокси-соединений к бэкенд-серверу, из-за всплесков трафика может на некоторое время перегрузить сетевой стек, а повторные попытки создадут дополнительную нагрузку на бэкэнд как в очереди приема, так и в очереди ожидания (SYN backlog). Это, в свою очередь, может повлиять на клиентские соединения. Повторные попытки SYN контролируются параметром net.ipv4.tcp_syn_retries (по умолчанию 5 или 6 в зависимости от дистрибутива). Ограничьте количество повторных попыток SYN до 0 или 1, чтобы не было долгих повторных попыток отправки в течение 63–130 с.
Более подробно о проблемах с клиентскими соединениями при обратном прокси-сервере читайте в статье Linux Kernel Tuning for High Performance Networking: Ephemeral Ports.
Очередь установленных соединений ожидающих принятия (accept queue) и somaxconn
Очередь запросов на соединение создает приложение, используя listen() и указывая размер очереди в параметре «backlog». Начиная с ядра 2.2 поведение этого параметра изменилось с максимального количества неоконченных запросов на соединение, которое может удерживать сокет, на максимальное количество полностью установленных соединений, ожидающих, пока они будут приняты. Как описано выше, максимальное количество неоконченных запросов на соединение теперь задается с помощью параметра ядра net.ipv4.tcp_max_syn_backlog .
somaxconn и параметр backlog в listen()
Хотя за размер очереди для каждого слушателя отвечает приложение, есть ограничение на количество соединений, которые могут находиться в очереди. Размером очереди управляют два параметра: 1) параметр backlog в функции listen() и 2) параметр ядра net.core.somaxconn , задающий максимальный размер очереди.
Значения по умолчанию для очереди
Значение по умолчанию для net.core.somaxconn берется из константы SOMAXCONN, которая в ядрах Linux вплоть до версии 5.3 имеет значение 128, но в 5.4 она была увеличена до 4096. Однако, на момент написания этой статьи, ядро 5.4 еще не очень распространено, поэтому в большинстве систем значение будет 128, если вы не модифицировали net.core.somaxconn.
Часто приложения для размера очереди по умолчанию используют константу SOMAXCONN, если этот размер не задается в конфигурации приложения. Хотя некоторые приложения устанавливают и свои значения по умолчанию. Например, в nginx размер очереди равен 511, который автоматически усекается до 128 в ядрах Linux до версии 5.3.
Изменение размера очереди
Многие приложения позволяют указывать размер очереди в конфигурации, указывая значение параметра backlog для listen() . Если приложение вызывает listen() со значением backlog , превышающим net.core.somaxconn, то размер очереди будет автоматически усечен до значения SOMAXCONN.
Потоки
Если очередь большая, то подумайте также об увеличении количества потоков, которые обрабатывают запросы в приложении. Например, установка для nginx очереди ожидания в 20480 для HTTP-listener без достаточного количества worker_connections для управления очередью приведет к тому, что сервер будет отказываться отвечать на запросы на установку соединения.
Соединения и файловые дескрипторы
Системные ограничения
Любое сокетное соединение использует файловый дескриптор. Максимальное количество дескрипторов, которые могут быть созданы в системе, задается параметром ядра fs.file-max. Посмотреть количество используемых дескрипторов можно следующим образом:
Вывод показывает, что используется 1976 файловых дескрипторов. Выделено, но не используется 12 (для ядер 2.6+), а максимальное количество — 2048. В высоконагруженной системе значение должно быть достаточно большим, чтобы справиться как с большим количеством соединений, так и с потребностями в файловых дескрипторах других процессов.
Пользовательские ограничения
Помимо системного ограничения количества файловых дескрипторов, у каждого пользователя есть свои лимиты. Они настраиваются в системном файле limits.conf (nofile) или, при запуске процесса под управлением systemd, в unit-файле systemd (LimitNOFILE). Чтобы увидеть значение по умолчанию запустите:
Для systemd (на примере nginx):
Настройка
Для настройки системных ограничений установите параметр ядра fs.max-file в максимальное количество файловых дескрипторов, которое может быть в системе (с учетом некоторого буфера). Например:
Для настройки пользовательского лимита установите достаточно большое значение, чтобы хватило сокетам и файловым дескрипторам рабочих процессов (также с некоторым буфером). Пользовательские ограничения устанавливаются в /etc/security/limits.conf, в conf-файле в /etc/security/limits.d/ или в unit-файле systemd. Например:
Количество worker’ов
Аналогично файловым дескрипторам, количество worker’ов или потоков, которые может создать процесс, ограничено как на уровне ядра, так и на уровне пользователя.
Системные ограничения
Процессы могут создавать рабочие потоки. Максимальное количество потоков, которые могут быть созданы, задается параметром ядра kernel.threads-max . Для просмотра максимального и текущего количества потоков, выполняющихся в системе, запустите следующее:
Пользовательские ограничения
Есть свои ограничения и у каждого пользовательского процесса. Это также настраивается с помощью файла limits.conf (nproc) или unit-файла systemd (LimitNPROC). Для просмотра максимального количества потоков, которое может создать пользователь запустите:
Для systemd (на примере nginx):
Настройка
В большинстве случаев системные ограничения достаточно большие, чтобы справиться с высокой нагрузкой. Однако их его можно настроить через параметр ядра kernel.threads-max . Установите его значение в максимальное количество потоков, необходимых системе, плюс некоторый буфер. Например:
Как и в случае с nofile , ограничения для пользователей ( nproc ) устанавливаются в /etc/security/limits.conf, в conf-файле в /etc/security/limits.d/ или в unit-файле systemd. Пример с nproc и nofile :
Обратный прокси и TIME_WAIT
При большом всплеске трафика прокси-соединения, застрявшие в «TIME_WAIT», суммарно могут потреблять много ресурсов при закрытии соединения. Это состояние говорит, что клиент получил последний FIN-пакет от сервера (или вышестоящего worker’а) и находится в ожидании для корректной обработки пакетов. Время нахождения соединения в состоянии «TIME_WAIT» по умолчанию составляет 2 x MSL (Maximum Segment Length — максимальная длина сегмента), что составляет 2 x 60 с. В большинстве случаев случаях это нормальное и ожидаемое поведение, и значение по умолчанию в 120 с вполне приемлемо. Однако много соединений в состоянии «TIME_WAIT» может привести к тому, что приложение исчерпает эфемерные порты для соединений к клиентскому сокету. В этом случае следует уменьшить FIN тайм-аут.
Управляет этим тайм-аутом параметр net.ipv4.tcp_fin_timeout . Рекомендуемое значение для высоконагруженных систем составляет от 5 до 7 секунд.
Собираем все вместе
Очередь приема (receive queue) должна быть рассчитана на обработку всех пакетов, полученных через сетевой интерфейс, не вызывая отбрасывания пакетов. Также необходимо учесть небольшой буфер на случай, если всплески будут немного выше, чем ожидалось. Для определения правильного значения следует отслеживать файл softnet_stat на предмет отброшенных пакетов. Эмпирическое правило — использовать значение tcp_max_syn_backlog, чтобы разрешить как минимум столько же SYN-пакетов, сколько может быть обработано для создания полуоткрытых соединений. Помните, что этот параметр задает количество пакетов, которое каждый процессор может иметь в своем буфере, поэтому разделите значение на количество процессоров.
Размер SYN очереди ожидания (SYN backlog queue) на высоконагруженном сервере должен быть рассчитан на большое количество полуоткрытых соединений для обработки редких всплесков трафика. Здесь эмпирическое правило заключается в том, чтобы установить это значение, по крайней мере, на максимальное количество установленных соединений, которое слушатель может иметь в очереди приема, но не выше, чем удвоенное количество установленных соединений. Также рекомендуется отключить SYN cookie, чтобы избежать потери данных при больших всплесках соединений от легитимных клиентов.
Очередь установленных соединений, ожидающих принятия (accept queue) должна быть рассчитана таким образом, чтобы в периоды сильного всплеска трафика ее можно было использовать в качестве временного буфера для установленных соединений. Эмпирическое правило — устанавливать это значение в пределах 20–25% от числа рабочих потоков.
Параметры
В этой статье были рассмотрены следующие параметры ядра:
И следующие пользовательские ограничения:
Заключение
Все параметры в этой статье приведены в качестве примеров и не должны вслепую применяться на ваших продакшн-серверах без тестирования. Есть и другие параметры ядра, которые влияют на производительность сетевого стека. Но в целом, это наиболее важные параметры, которые я использовал при настройке ядра для высоконагруженных систем.
Узнать подробнее о курсе «Administrator Linux. Professional«.
Смотреть вебинар «Практикум по написанию Ansible роли».
Источник
1.tcp basis
For a TCP connection, Server and Client needs to establish a network connection via three-way handshake. When the three-way handshake is successful, we can see the status of the port to transition from LISTEN ESTABLISHED, then you can start transferring data on this link.
For servers, a complete connection establishment process, TCP server will experience two kinds of states: SYN_REVD, ESTABELLISHED. Correspondence also maintains two queues:
1. SYN storing a queue (queue semijoins)
2. completed store queue a connection (connection queue full)
is when the state of a SYN RECEIVED connection, it will be placed in the queue SYN. When its state to ESTABLISHED, it will be transferred to another queue. Therefore, the rear end of the application acquisition request from the queue only in the connection has been completed.
If a server to handle a large number of network connections, and concurrency is relatively high, then the two queue length is very important. Because, even if the hardware configuration of the server is very high, very good server-side program performance, but these two queues is very small, so it often happens that the client can not connect because the two queues Once full, it is easy to lose package, or the connection is reset. So, if the server concurrent access volume is very high, then the two queues setting is very important.
2.tcp_max_syn_backlog
tcp_max_syn_backlog specified maximum number of acceptable synchronization client SYN packet, i.e., upper connector half, the default value is the number of connections 128, i.e. SYN_REVD state.
3.net.core.somaxconn
somaxconn is a Linux kernel parameter in, the server refers to the client can accept the maximum amount of data that is processed, i.e., the upper limit to complete the connection, the default value is 128.
4. parameters
4.1 temporary changes
The above command the value of the kernel parameter net.core.somaxconn been changed to 32768. While such changes can take effect immediately, but after the restart the machine will restore the default values.
4.2 permanent changes
4.2.1 modify the configuration file /etc/sysctl.conf, add a line at the end.
4.2.2 execute the following command to refresh the configuration file
Источник