Pull to refresh

Comments 41

Вообще говоря, немного неожиданный результат для nginx. Я предполагал что nginx (ну и HAProxy, возможно), будет далеко впереди. А не пробовали поставить их всех без Docker?

А Caddy сам пошёл за сертификатами в LE? В какой момент?

С год назад выбирал прокси для Docker Swarm. В первую очередь нужна была гибкость и разные настройки. nginx я люблю, но подкупила реклама Traefik о том, что сам может обнаруживать смену конфигурации апстримов кластера. Envoy и Caddy что-то показались туповатыми с точки зрения конфигов. Traefik, честно говоря, тоже, но кое-как смог его завести. В итоге очень не нравится, серьёзно думаю поменять на nginx. Производительность не очень интересовала - у меня не такие большие нагрузки.

Caddy сам ходит за сертами на основе Caddyfile, в момент запуска docker compose

Без Docker, с тем же Caddy или Nginx, результаты лучше процентов на 5

А что касается результатов, как я уже писал, возможно с помощью грамотного тюнинга можно выжать и больше, но из коробки увы, мы сами удивились ))

Для Swarm плохи все прокси, основанные на файлах конфигов. Пришлось пилить свой на лейблах и событиях Докера, без редеплоя.

Любопытно, а можете показать что у вас получилось? Или хотя бы рассказать поподробнее?

Судя по логам Traefik, он не использует события докера, а раз в несколько секунд перечитывает весь список контейнеров. Ну, либо в логи зачем-то слишком (слишком!) часто пишет о том что нашёл изменения. Это мне в нём тоже не нравится.

В принципе, у меня есть вариант использовать nginx и резолвер докера, а для динамической смены конфига без редеплоя - хранить его в Redis и обновлять через Lua (upstreams).

nginx 1.27.3
  • в директиву server, используемую в блоке upstream, добавлена поддержка параметра resolve, включающего отслеживание изменения IP-адреса для используемого доменного имени и автоматическое обновление конфигурации блока upstream без необходимости перезапуска nginx в случае изменения адреса;

Пожалуйста, напишите статью, о текущих или итоговых результатах этой разработки. Будет невероятно интересно и полезно.

Статья, конечно, хорошо, но есть сомнения. Открывать код не планировал, а проприетарщину тут не любят...

С гибкостью и разными настройками у Envoy всë в порядке. Просто его формат конфигов определяется схемой на Protobuf. Это следствие того, что основной use case для Envoy - динамическое переконфигурирование на лету. Файл конфига, который указывается при старте - это просто bootstrap конфиг, который чаще всего просто подсказывает, где брать остальное - внешние процессы, знающие текущее состояние кластера (Cluster Discovery Service), роуты (Routes Discovery Service) и прочие xDS. Это причина, по которой именно на Envoy довольно часто строят сервисмэши, ингресс-контроллеры и API- гейтвеи. Не надо из темплейтов генерить файлы конфигов...

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

Traefik пытается брать всё из labels, но не всегда получается через них это задать.

nginx может всё и даже больше, но ему нужен конфиг, который, в принципе, можно генерировать и подсовывать прямо в контейнер для hot reload. Однако, на каждый новый контейнер это немного не динамически, да.

Спасибо за отличную стать Интересно было бы посмотреть результаты тестирования http2/grpc

И на h3, quic посмотреть бы.

Вот бы ещё Angie протестировали - это форк Nginx от бывших разработчиков nginx на стероидах.

Не ради рекламы спрашиваю, но ищу замену NPM

А как Вам Angie поможет заменить NPM? Это же вроде как троллейбус буханкой белого хлеба заменять, если вы понимаете о чем я.
Есть подозрения, что у Angie будут результаты такие же или хуже чем у Nginx, из-за количества дополнительных модулей в стандартной сборке.

Есть подозрения

Ну подозрение подозрениями, а вот тесты бы дали фактические результаты.

А как Вам Angie поможет заменить NPM? 

И то и другое можно использовать в качестве реверсивного прокси, и то и другое умеет работать с LetsEncrypt, отличие в том, что NPN, являясь надстройкой над nginx имеем веб интерфейс для настройки сайтов (в что можно и лучше перенести на CI/CD), но не имеет никаким вменяемых мониторингов.

В моем случае, я не знаю зачем, но дома имею

  1. некоторую домашнюю сетевую лабу с несколькими мини ПК на проксмоксе

  2. одноплатник с NPN

  3. роутер, с dnat www трафика на NPN и локальным DNS

  4. Ряд сервисов (42 хоста), которые идут на NPM, а он уже стучится виртуалки и контейнеры внутри кластера.

Хочу: запустить кластер из реверс прокси, как минимум добавить по 1 экземпляру на каждом инстансе PVE, в локальном dns прописать для DNS имени не одноплатник, а проксик, находящийся на одном физическом хосте с сервисов, чтобы по локальной сети меньше гонять трафика. Как минимум вариант с конфигом в гите и деплоем на несколько машин выглядит решением

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

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

"Сырой конфиг" тоже можно вставить, но NPN это не для извращений в конфигах, а для, например, недавнего варианта: настроил в контейнере свой nginx, там сложные правила, работа как с локальным кешем, так и с api бэком, все по классике, в общем. Далее, зашел в веб интерфейс и прописал, что по https://notes.mydomain.tld хостится на http://notes.lan и все

Ну и в плюсы NPM можно занести отличную работу в докере, новичок не всегда завернет nginx и certbot в docker-compose.yml с первой попытки, а тут полностью прозрачная работа с сертификатами, как это есть у конкурентов типа caddy

В итоге первым шагом реализовал следующее
1. несколько python скриптов, скрипт добавления записи спрашивает у пользователя домен, адрес бэкенда, мидлварки и т.д. и создает файлы конфигов, которых в 90% случаев достаточно
2. скрипт последним шагом или сам пользователь коммитит файлы и пушит в git репозиторий
3. CI/CD запускается по пушу, валидирует конфиги и заливает их в consul и сообщает об этом в телегу
4. несколько нод с traefik + consul автоматом подтягивают обновление конфигурации
5. PROFIT

Еще написал скрипт, который подключается к базе NPM, вытягивает из нее конфигурацию хостов и генерирует файлы для traefik.

Плюсы:

1. IaC подход
2. Можно подключить к докеру напрямую для получения конфигурации из меток

Минус:
1. в 3.4 усложнилась структура consul и приходится загружать много записей, в целом у меня до 1.5 занимает весь процесс CI/CD

Для интерактивности, кстати, можно реализовать проект типа NPM но с хранением конфигурации в consul или другой распределенной kv СУБД, чтобы изменения в веб морде сразу же применялись, но тогда не будет подхода IaC

Вот так вот, натестируют по 1й минуте, а потом на проде "ой, а у нас тут фигня какая-то"

Господа, делайте проверки длительными, система себя проявляет когда все кэш области забиваются и вот там проявляется архитектура.

Когда я говорю длительными, я имею в виду часы, дни. Мы испытываем системы неделями и открываем много нового для себя а иногда и для производителя.

А можно на примерах поподробнее? И вообще есть ли в этом смысл если релизы чаще раза в неделю (прокси можно рестартить по очереди)?

У нас нт проводится 12 часов. Большое количество проблем возникает в промежутках с 4 до 8 часов работы. Условно в первые 4х часа работает стабильно, если же 8+ то уже дальше всё стабильно . Причины самые невероятные возникали (кеши, коннекшены к базе, утечки памяти, подвисшие потоки и тд). Так что нт важно проводить в течении длительного времени. Особенно в высоконагруженных системах.

Но ведь в посте тестируются прокси, а не приложение, а вы описываете проблемы приложения

Спасибо за пост. Можете выложить результаты в виде таблицы?

Сам использую haproxy, от nginx отказался давно уже, простота конфигурации на haproxy подкупила. С 2.8 в связке с acme обновляет сертификаты без перезапуска, появился quic, не назвал бы его там готовым к проду, но оно работает и в целом quic внутри страны ходит исправно, в 3.0 версии добавили сохранение статистики и доработали quic, должен выйти 3.1 lts где quic довели до ума. И есть экспортер Prometheus в коробке, что куда проще чем с nginx, одна строка в frontend и пошли метрики.

Полезная нагрузка в виде "hello world" - не сказать что эталон по объему ответа. Результаты могли исказиться так или иначе - служебного трафика сильно больше полезного.

Но тут тогда сразу и разный объем ответа просится на тестирование - чтобы выявить разницу при разных объемах ответа. Что удлинит тест в разы.

А не пробовали сразу Golang-сервис запустить с HTTPS? Т.е. без обратного прокси. Как отправная точка тоже было бы полезно (помимо голого HTTP). Правда тогда бекенд тоже с 32 vCPU и 128 ГБ RAM надо было бы запускать...

Вероятно будет еще несколько статей с подобным тестированием, в разных вариациях + есть идея посмотреть на это все со стороны пентестов

Можете протестировать с таким конфигм nginx? Есть гипотеза что вся разница между проксирующими серверами свелась к включенному или выключенному keepalive по умолчанию. Как следствие - заканчиваются эфемерные порты и такое большое время на обработку и так много фейлов.

http {
  upstream backend {
    server 10.0.0.4:8080;
    keepalive 4;
  }
  server {
    listen 443 ssl;
    server_name test-backend.mish.design;

    ssl_certificate /etc/letsencrypt/live/test-backend.mish.design/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/test-backend.mish.design/privkey.pem;
	
    location / {
        proxy_pass http://backend;
        proxy_set_header Connection '';
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
	}
}


Я думаю завтра потестирую с этим конфигом, спасибо за идею ;-)

Дополнил статью тестами, если кратко keepalive - не помог

Очень странный результат для nginx. Надеюсь, дело в неправильных настройках (как выше написали про keepalive).

Зачем включили multi_accept? Он выключен по умолчанию не просто так. Это лучший способ вызвать дисбаланс в бенчмарке. Скорее всего у вас большинство соединений в итоге приняли и обрабатывали всего несколько первых рабочих процессов. От того и такие результаты...

Что в логе ошибок было? nginx пишет обычно что пошло не так... возможно у вас закончились дескрипторы или уперлись в лимит как раз из-за multi_accept.

Перед тем, как тестировать, выровняли ли настройки TLS-шифрования? У nginx по умолчанию `ssl_ciphers HIGH:!aNULL:!MD5;`. У других серверов скорее всего шифрование использовалось более слабое и менее ресурсоемкое, так что CPU не стал для них бутылочным горлышком.

Одинаковы ли у серверов настройки логирования?

Крайне предвзятый тест, без попытки разобраться в причинах и изначально неравными настройками.

Моя гипотеза: из-за "multi_accept" соединения между рабочими процессами распределялись крайне неравномерно, а из-за тяжелой криптографии рабочие процессы, набрав соединения, заблокировались на CPU.

Затем и включили, что без него только хуже)
Результаты разных комбинаций добавил в статью

Настройки TLS выровняли в последнем тесте + включенный multi_accept - результаты стали немного получше, но увы до Envoy или HAProxy - очень и очень далеко

Какие ошибки в логах? Во всех тестах, что мы проводили на моей памяти, haproxy оказывался чуть хуже nginx, да в общем-то неоткуда там разнице особой взяться, тем более в разы - архитектура очень похожа. Поэтому есть все основания полагать, что что-то фундаментально не так с конкретной установкой nginx. Что все же в логах ошибок? И сам nginx, кстати, откуда? Из официального репозитория на `nginx.org`?

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

Если интересно все же разобрать в причинах, я бы предложил попробовать повторить тест без TLS в принципе. Если результаты nginx и haproxy окажутся в этом случае близки, то дальше нужно будет разбираться, а что не так с TLS.

И обращаю также внимание на то, что у nginx по умолчанию включен `access_log`, а у того же haproxy, насколько я помню, его нужно включать принудительно.

> Затем и включили, что без него только хуже)

По вашим данным с выключенным multi_accept число успешных запросов больше:

checks_succeeded...................: 30.91% 312910 out of 1012194 checks_failed......................: 69.08% 699284 out of 1012194

против с включенным:

checks_succeeded...................: 25.90% 244664 out of 944528 checks_failed......................: 74.09% 699864 out of 944528

или я неправильно интерпертирую данные?

Но должно быть вообще 100%. То, что nginx теряет запросы - это что-то ненормальное, в error_log должны быть причины этому.

Изначально цель статьи была — сравнить производительность “из коробки”, с минимальными настройками, что и было сделано.

Также я упомянул, что для nginx требуется дополнительный тюнинг.

Понятно, что нюансов масса. Если у вас, как у бывшего разработчика ядра nginx, есть понимание, как быстро и эффективно настроить nginx для обработки 50k RPS — будет круто, если поделитесь рабочим конфигом. Думаю, сообщество будет только благодарно.

Мое понимание заключается в том, что nginx из коробки не должен проигрывать haproxy в разы. Указанное число RPS для сервера с 32 CPU - это вообще крайне мало... и выглядит очень подозрительно.

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

Вопрос, у вас HTTPS соединения keepalive или на каждый запрос новое? А если на каждый запрос новое соединение, то используется ли возобновление TLS-сессий и каким механизмом? Полный хендшейк - это весьма CPU-нагруженная операция, и лишь разница в настройках TLS-сессий может полностью перевернуть картину между серверами. Опять же, каждая настройка хороша под конкретный стенд, поэтому выравнивать сервера по настройкам, тем более таким критичным, как TLS - необходимо, иначе будет просто необъективный результат, который применим только к конкретному стенду, а на другом стенде будет совсем другим. Так вы протестировали сервера на то, как их настройки по умолчанию подходят для вашего стенда и это будет иметь мало общего с производительностью в реальности, даже на тех же настройках - просто в силу того, что клиенты обычно не ведут себя как отдельно взятый тестовый стенд.

У haproxy, кстати, по умолчанию включен кэш SSL-сессий, а у nginx он выключен. И если клиент, например, не умеет в сессионные тикеты, то вот и разница - тогда в одном случае вы считаете полные хендшейки, а в другом возобновления сессий.

50k RPS для nginx - это вообще пустяки, но вот криптография, которой занимается TLS-библиотека - она может стать лимитирующим фактором. К примеру, вот такой sizing guide для nginx plus: https://www.f5.com/pdf/deployment-guide/Sizing-Guide-for-Deploying-NGINX-Plus-on-Bare-Metal-Servers-2019-11-09.pdf - он уже старенький, ещё от 2019 года, но можно заметить, что на 32 CPU легко может быть 1 000 000 RPS, но всего около 50к полных хендшейков.

Спасибо да статью!

А если использовать режим network_mode: host ?

Надо бы указывать версии продуктов.

haproxy 3.1.6

envoy 1.34.0-dev

nginx 1.27.4

traeffik 3.3.5

caddy 2.9.1

P.s. Добавил и в начало статьи

еще важна реализация SSL

haproxy и nginx по умолчанию билдятся с openssl 3.x (и у разработчиков haproxy есть претензии к производительности настолько что дают совет "не используйте openssl3 - используйте альтернативы, причем nginx меньше подвержен)

envoy использует boringssl - форк openssl 1.x еще до этих проблем

traeffik и caddy - не использовал, поэтому не стал закапываться.. какую-то гошную реализацию tls судя по всему

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

Имхо надо разделять тестирование чисто по http - оно бОльше скажет о производительности самой прокси(не учитывая проблему значений по умолчанию) и по https.

Да, в golang можно сказать чтобы использовал boringssl, например. Во время компиляции. Но автор упомянул, что тестирование "из коробки" было. Иначе бы было 1000 комбинаций наверное.

Sign up to leave a comment.

Articles