3 June 2015

Увеличиваем производительность с помощью SO_REUSEPORT в NGINX 1.9.1

High performance
Translation
Original author: Andrew Hutchings
В NGINX версии 1.9.1 появилась новая возможность, позволяющая использовать сокетную опцию SO_REUSEPORT, которая доступна в современных версиях операционных систем, таких как DragonFly BSD и Linux (ядра 3.9 и новее). Данная опция разрешает открывать сразу несколько слушающих сокетов на одном и том же адресе и порту. При этом, ядро будет распределять входящие соединения между ними.

(В NGINX Plus эта функциональность появится в выпуске 7, который выйдет позже в этом году.)

У опции SO_REUSEPORT есть множество потенциальных вариантов применения для решения различных задач. Так, некоторые приложения могут использовать её для обновления исполняемого кода на лету (NGINX всегда имел такую возможность с незапамятных времен, используя иной механизм). В NGINX включение данной опции увеличивает производительность в отдельных случаях за счет уменьшения блокировок на локах.

Как показано на рисунке, без SO_REUSEPORT один слушающий сокет разделен между множеством рабочих процессов и каждый из них пытается принимать от него новые соединения:



С опцией SO_REUSEPORT у нас есть множество слушающих сокетов, по одному на каждый рабочий процесс. Ядро операционной системы распределяет в какой из них попадет новое соединение (а тем самым какой из рабочих процессов его в итоге получит):



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

Конфигурация


Для включения SO_REUSEPORT в модулях http или stream достаточно указать параметр reuseport директивы listen, как показано в примере:
http {
     server {
          listen 80 reuseport;
          server_name example.org;
          ...
     }
}

stream {
     server {
          listen 12345 reuseport;
          ...
     }
}

Указание reuseport при этом автоматически отключает accept_mutex для данного сокета, поскольку в данном режиме мьютекс не нужен.

Тестируем производительность с reuseport


Измерения производились с помощью wrk, используя 4 рабочих процесса NGINX на 36 ядерном AWS инстансе. Чтобы свести к минимуму сетевые издержки клиент и сервер работали через loopback-интерфейс, а NGINX был сконфигурирован для отдачи строки OK. Сравнивались три конфигурации: с accept_mutex on (default), c accept_mutex off и с reuseport. Как видно на диаграмме, включение reuseport в 2-3 раза увеличивает количество запросов в секунду и уменьшает задержки, а также их флуктуацию.



Также были проведены замеры, когда клиент и сервер были запущены на разных машинах и запрашивался html-файл. Как видно из таблицы, с reuseport происходит снижение задержек, аналогичное предыдущему замеру, а их разброс снижается еще сильнее (почти на порядок). Другие тесты также демонстрируют хорошие результаты от использования опции. С использованием reuseport нагрузка распределялась равномерно по рабочим процессам. С включенной директивой accept_mutex наблюдался дисбаланс в начале теста, а в случае отключения все рабочие процессы занимали больше процессорного времени.

Latency (ms) Latency stdev (ms) CPU Load
Default 15.65 26.59 0.3
accept_mutex off 15.59 26.48 10
reuseport 12.35 3.15 0.3

В данных тестах частота запросов была крайне высокой, при этом они не требовали какой-либо сложной обработки. Различные наблюдения подтверждают, что наибольший эффект от применения опции reuseport достигается когда нагрузка отвечает данному паттерну. Таким образом, опция reuseport не доступна для модуля mail, поскольку почтовый трафик однозначно не удовлетворяет данным условиям. Мы рекомендуем всем производить собственные замеры, чтобы убедиться в наличии эффекта от reuseport, а не слепо включать опцию везде, где только это возможно. Некоторые советы по тестированию производительности NGINX вы можете почерпнуть из выступления Константина Павлова на конференции nginx.conf 2014.

Благодарности


Спасибо Sepherosa Ziehau и Yingqi Lu, каждый из которых предложил собственное решение для работы SO_REUSEPORT в NGINX. Команда NGINX использовала их идеи для реализации, которую мы считаем идеальной.
Tags:nginxбенчмаркивысокая нагрузкавысокая производительность
Hubs: High performance
+35
30.7k 211
Comments 31
Top of the last 24 hours