Как настроить Nginx для проксирования более 200K MQTT соединений?

Вопрос или проблема

Мне нужно проксировать много соединений MQTT (более 200K) и распределить их по нескольким портам на сервере обратной связи. Ниже приведена моя конфигурация Nginx.

load_module /usr/lib/nginx/modules/ngx_stream_module.so;

user www-data;
pid /run/nginx.pid;

worker_rlimit_nofile 204800;
worker_cpu_affinity auto;
worker_processes auto;

events {
    accept_mutex on;             # Несколько рабочих процессов должны принимать соединение
    worker_connections 206200;   # Общее количество соединений с upstream и клиентами
    multi_accept off;            # Принимать одно соединение в каждом рабочем процессе
}

stream {
    upstream backend {
          server backendserver.com:1885;
          server backendserver.com:1886;
          server backendserver.com:1887;
          server backendserver.com:1888;
          server backendserver.com:1889;
          server backendserver.com:1890;
          server backendserver.com:1891;
          server backendserver.com:1892;
          server backendserver.com:1893;
          server backendserver.com:1894;
          server backendserver.com:1895;
          server backendserver.com:1896;
          server backendserver.com:1897;
          server backendserver.com:1898;
          server backendserver.com:1899;
          server backendserver.com:1900;
          server backendserver.com:1901;
          server backendserver.com:1902;
          server backendserver.com:1903;
          server backendserver.com:1904;
    }

    server {
        listen 8883;
        proxy_pass backend;
    }
}

Я также установил следующие системные конфигурации:

sysctl -w fs.file-max=11000000
sysctl -w fs.nr_open=11000000
sysctl -w net.core.somaxconn=65535
sysctl -w net.ipv4.tcp_max_syn_backlog=65535
sysctl -w net.ipv4.ip_local_port_range="1025 65535"
sysctl -w net.ipv4.tcp_mem="100000000 100000000 100000000"
sysctl -w net.ipv4.tcp_rmem='2048 2048 2048'
sysctl -w net.ipv4.tcp_wmem='4096 4096 4096'
sysctl -w net.core.rmem_default=4096
sysctl -w net.core.wmem_default=4608
sysctl -w net.core.rmem_max=4096
sysctl -w net.core.wmem_max=4608

Также я установил ulimit -n 999999.

Но я могу создать только около 128K-130K соединений. После этого Nginx записывает ошибки, подобные приведенной ниже:

2023/08/16 06:46:32 [error] 4172305#4172305: *206569 recv() failed (104: Unknown error) while proxying and reading from upstream, client: 72.xxx.xxx.xxx, server: 0.0.0.0:8885, upstream: "139.xxx.xxx.xxx:8889", bytes from/to client:984/5224, bytes from/to upstream:5224/984

Я проверил непосредственное соединение со всеми портами обратной связи, и они работают нормально.

Кроме того, когда у меня была только одна запись в блоке upstream backend, я мог создать только около 64K соединений. Когда я добавляю второй элемент, я мог достигнуть около 128K-130K. Но добавление большего количества записей не позволяет мне превысить это число соединений.

Я уже пробовал сделать следующее:

  1. Установить worker_rlimit_nofile и worker_connections на 999999.
  2. Добавить больше блоков server с разными портами.
  3. Увеличить tcp_rmem, tcp_wmem, rmem_default, wmem_default, rmem_max, wmem_max в 10 раз.
  4. Настроить multi_accept on;

Как я могу заставить мой сервер Nginx проксировать более 130K соединений (по крайней мере 200K)?

У меня есть 100k WS прокси, но нет WSS прокси. Не тестирую 200k из-за ограничений ресурсов.

Технические объяснения:

  • Исходящее соединение TCP/IP требует сетевого интерфейса, исходного IP-адреса и высокого порта
  • Высокий номер порта, даже после изменения с помощью sysctl, должен составлять не более 1024-65535, что примерно ~64k соединений на исходный IP
  • Поскольку nginx (и почти все прокси) не могут распределять нагрузки на сервере обратной связи с привязкой к диапазону IP-адресов, мы можем делать это только через маршрутизацию ядра
  • Создайте несколько подсетей с маской подсети 255.255.255.252 для P-t-P связи. Найдите сетевого инженера, чтобы узнать детали, если хотите.
  • В примере ниже у меня есть 10 P-t-P подсетей между nginx и MQTT. Nginx выбирает 1 из 10 upstream, таблица маршрутизации автоматически выберет соответствующий интерфейс и исходный IP адрес.
  • Таким образом, у нас есть 10 x 64k = 640k мест для подключения от nginx к MQTT, теоретически. Так как мы не можем контролировать, как nginx выбирает upstream, сначала сделайте избыточную конфигурацию.
  • Я могу достичь 100k от HTTP/80 до WS/8083. Но я не могу превысить 10k, если фронтенд – HTTPS/443.

1/ Системная конфигурация (sysctl) все еще требуется. Вот моя. Я копировал различные конфигурации из разных источников в Интернете, обсуждающих c100k. Не уверен, что все они необходимы или нет.

# fs.file-max = 9223372036854775807
fs.nr_open=2097152
net.core.somaxconn = 262144
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_max_syn_backlog = 262144
net.ipv4.tcp_rmem = 1024 4096 16777216
net.ipv4.tcp_wmem = 1024 4096 16777216
net.netfilter.nf_conntrack_tcp_timeout_time_wait=30
net.ipv4.tcp_max_tw_buckets=8192
net.ipv4.tcp_fin_timeout=15
net.ipv4.tcp_max_orphans = 262144
net.core.netdev_max_backlog = 262144
net.core.rmem_default=262144
net.core.wmem_default=262144
net.core.rmem_max=16777216
net.core.wmem_max=16777216
net.core.optmem_max=16777216
net.ipv4.tcp_timestamps = 0
net.ipv4.tcp_synack_retries = 1
net.ipv4.tcp_syn_retries = 1
net.ipv4.tcp_fin_timeout = 5
net.ipv4.tcp_keepalive_time = 30

2/ Также ограничения

Файл: /etc/security/limits.d/tuning.conf

* hard nofile 1048576
* soft nofile 1048576
root hard nofile 1048576
root soft nofile 1048576
* hard nproc 1048576
* soft nproc 1048576
root hard nproc 1048576
root soft nproc 1048576

3/ Если вы используете systemd, как я, используя Ubuntu, нужно переопределить systemd:

# systemctl edit nginx.service

[Service]
LimitNOFILE=1048576

4/ Сервер MQTT обратной связи настраивает больше алиасных IP, например:

ens18:0 192.168.0.1/30
ens18:1 192.168.1.1/30
ens18:2 192.168.2.1/30
ens18:3 192.168.3.1/30
...
ens18:9 192.168.9.100/30

5/ Сервер nginx настраивает больше алиасных IP к серверу MQTT

ens19:0 192.168.0.2/30
ens19:1 192.168.1.2/30
ens19:2 192.168.2.2/30
ens19:3 192.168.3.2/30
...
ens19:9 192.168.9.2/30

6/ Конфигурация nginx: upstream backend (мой MQTT использует 8083 для WS)

upstream backend {
    192.168.0.1:8083;
    192.168.1.1:8083;
    192.168.2.1:8083;
    ...
    192.168.9.1:8083;
};

map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}

7/ Наконец, сделайте прокси

location /mqtt {
    proxy_pass http://backend/mqtt;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;
}

Если вы запускаете nginx и MQTT на одном сервере / виртуальной машине, вы можете создать фиктивный сетевой интерфейс. В этом случае upstream сервера nginx просто такие же, как и IP-адрес фиктивного интерфейса, и будут работать. Не используйте localhost, 127.0.0.1 и т. д. Это не сработает.

Я пробовал запускать nginx и MQTT внутри двух контейнеров docker, но не удалось.

Теперь у меня есть nginx на хостовой системе и MQTT внутри docker (внутри одной виртуальной машины), и это работает хорошо.

Ответ или решение

Конфигурация Nginx для проксирования более 200 тысяч соединений MQTT: Полное руководство


Сегодня многие системы требуют высокой производительности и масштабируемости, особенно в контексте обработки сообщений через MQTT (Message Queuing Telemetry Transport). Учитывая вашу потребность в проксировании более 200 000 соединений, вот полное руководство по настройке Nginx для достижения этой цели.

1. Основы конфигурации Nginx

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

load_module /usr/lib/nginx/modules/ngx_stream_module.so;

user www-data;
pid /run/nginx.pid;

worker_rlimit_nofile 999999;  # Максимальное количество открытых файлов

worker_processes auto;  # Автоматическая настройка количества процессов

events {
    accept_mutex on;   # Возможность многопоточной обработки соединений
    worker_connections 999999;   # Максимальное количество соединений на процесс
    multi_accept on;   # Увеличение эффективности обработки соединений
}

stream {
    upstream backend {
        server backendserver.com:1885;
        server backendserver.com:1886;
        server backendserver.com:1887;
        # Добавьте все ваши серверы в зависимости от конфигурации
    }

    server {
        listen 8883;  # Порт для прослушивания входящих соединений
        proxy_pass backend;  # Проксирование трафика на указанные серверы
    }
}

2. Системные параметры

Для поддержки такого количества соединений, важно оптимизировать системные параметры. Проверьте ваши настройки sysctl:

sysctl -w fs.file-max=2097152
sysctl -w net.core.somaxconn=262144
sysctl -w net.ipv4.tcp_max_syn_backlog=262144
sysctl -w net.ipv4.ip_local_port_range="1024 65535"
sysctl -w net.ipv4.tcp_rmem="4096 87380 16777216"
sysctl -w net.ipv4.tcp_wmem="4096 16384 16777216"

Обратите внимание на ip_local_port_range, который позволяет системе использовать порты в диапазоне от 1024 до 65535, что увеличивает количество исходящих соединений.

3. Ограничения на уровне пользователя

Убедитесь, что значения уlimits настроены правильно. Проверьте файл /etc/security/limits.d/tuning.conf:

* soft nofile 1048576
* hard nofile 1048576
* soft nproc 1048576
* hard nproc 1048576

4. Дополнительные настройки Нginx на уровне systemd

Если вы используете systemd, необходимо убедиться, что лимиты для Nginx прописаны в его служебной конфигурации:

# systemctl edit nginx.service

[Service]
LimitNOFILE=1048576

5. Настройка сетевых интерфейсов

Для поддержки большого количества соединений вам помогут алиасы IP-адресов. Создайте несколько алиасов на вашей бэкенд-системе и на Nginx:

Aliases on Backend:

ifconfig ens18:0 192.168.0.1 netmask 255.255.255.252 up
# Повторите для других интерфейсов

Aliases on Nginx:

ifconfig ens19:0 192.168.0.2 netmask 255.255.255.252 up
# Повторите для других интерфейсов

6. Обновите конфигурацию upstream

Замените конфигурацию upstream на использование алиасов:

upstream backend {
    server 192.168.0.1:1885;
    server 192.168.0.2:1885;
    # Добавьте остальные адреса
}

7. Итоговая конфигурация Nginx

После внесения всех вышеуказанных изменений конфигурация Nginx может выглядеть следующим образом:

stream {
    upstream backend {
        server 192.168.0.1:1885;
        server 192.168.0.2:1885;
        # Остальные сервера
    }

    server {
        listen 8883;
        proxy_pass backend;
    }
}

Заключение

С консолидированными усилиями на оптимизацию конфигурации Nginx и системных параметров вы сможете достичь более чем 200000 активных соединений через MQTT. Следует помнить, что вам, возможно, потребуется протестировать вашу настройку в условиях реальной нагрузки, чтобы убедиться, что система справляется с ожидаемыми вызовами. С этим планом вы будете готовы к эффективной обработке больших объемов трафика.

Если у вас возникнут дополнительные вопросы или потребуется помощь с настройкой, не стесняйтесь обращаться!

Оцените материал
Добавить комментарий

Капча загружается...