Битва балансеров

в 8:44, , рубрики: balancers, haproxy, hipache, http-proxy, nginx, node.js, stud, системное администрирование

«Битва балансеров» — это нагрузочный тест балансеров / прокси, которые поддерживают WebSockets. Данные технологии незаменимы при масштабировании инфраструктуры.

Тестировались следующие технологии:

http-proxy, версия: 0.10.0
HAProxy, версия: 1.5-dev18 (девелопмент релиз)
— элементарный “echo сервер”, для контрольного теста.

Были сомнения относительно hipache. Причина по которой он был исключен проста — он построен на базе http-proxy. В данный момент они используют форк проекта, в котором попросту отсутствуют патчи, связанные с производительностью.

Для тестирования были использованы 3 различных, не связанных сервера, все хостились на joyent.

1. Прокси, 512Мб, Ubuntu сервер. На этом сервере были установлены все прокси-сервера. образ: sdc:jpc:ubuntu-12.04:2.4.0
2. WebSocket-сервер, 512Мб «умная машина» с Node.js, на которой крутился наш WebSocket echo сервер. Сервер написан на Node.js и запускался на нескольких ядрах используя cluster модуль. образ: sdc:sdc:nodejs:1.4.0
3. Thor, 512Мб, еще одна «умная машина» на Node.js со спецификациями, аналогичными предыдущему. С этого сервера мы генерировали необходимую нагрузку. Thor — это разработанный нами WebSocket инструмент для генерации нагрузки. Данное приложение распространяется с открытым исходным кодом и доступно по ссылке http://github.com/observing/thor.

Настройка прокси-сервера

Нашим прокси-сервером был «чистый» сервер c Ubuntu 12.04. Для настройки и установки всех зависимостей были проделаны следующие шаги. Что бы удостоверится, что мы работаем с последними версиями, запустили:

apt-get upgrade 

В систему установили следующие зависимости:
— git для доступа к репозиториям github
— build-essential для компилирования прокси из исходников, большинство прокси только недавно обзавелись поддержкой WebSockets или HTTPS
— libssl-dev необходимо для поддержки HTTPS
— libev-dev требуется для stud, который просто невероятен

apt-get install git build-essential libssl-dev libev-dev

Node.js

Node.js нужен для http-proxy. В то время как http-proxy использует последнюю версию Node.js, эти тесты были выполнены на версии 0.8.19 с тем, что бы обеспечить совместимость всех зависимостей. Node.js был склонирован с github.

git clone git://github.com/joyent/node.git
cd node
git checkout v0.8.19
./configure
make
make install

При этом установливается бинарный npm, так что мы можем установить зависимости этого проекта. Запустите npm install в корне этого репозитория и http-proxy и все зависимости установятся автоматически.

Nginx

Nginx уже широко распространенный сервер. Он поддерживает проксирование на различные бекенд сервера, но не поддерживал WebSockets. Не так давно это было добавлено в девелопмент ветку Nginx. Таким образом, мы установили последнюю девелопмент версию и скомпилировали из исходников:
Обратите внимание, что с момента тестирования и написания данной статьи вышел nginx 1.4.0, в котором есть поддержка WebSockets. Так что если Вы читаете данную статью и планируете развернуть это на продакшене, мой совет – использовать версию 1.4.0. вместо девелоперских версий.

wget http://nginx.org/download/nginx-1.3.15.tar.gz
tar xzvf nginx-1.3.15.tar.gz
cd nginx-1.3.15
./configure --with-http_spdy_module --with-http_ssl_module 
--pid-path=/var/run/nginx.pid --conf-path=/etc/nginx/nginx.conf 
--sbin-path=/usr/local/sbin --http-log-path=/var/log/nginx/access.log 
--error-log-path=/var/log/nginx/error.log --without-http_rewrite_module

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

Configuration summary
  + PCRE library is not used
  + using system OpenSSL library
  + md5: using OpenSSL library
  + sha1: using OpenSSL library
  + using system zlib library

  nginx path prefix: "/usr/local/nginx"
  nginx binary file: "/usr/local/sbin"
  nginx configuration prefix: "/etc/nginx"
  nginx configuration file: "/etc/nginx/nginx.conf"
  nginx pid file: "/var/run/nginx.pid"
  nginx error log file: "/var/log/nginx/error.log"
  nginx http access log file: "/var/log/nginx/access.log"
  nginx http client request body temporary files: "client_body_temp"
  nginx http proxy temporary files: "proxy_temp"
  nginx http fastcgi temporary files: "fastcgi_temp"
  nginx http uwsgi temporary files: "uwsgi_temp"
  nginx http scgi temporary files: "scgi_temp"

После этого:

make
make install

HAProxy

HAProxy и раньше умела проксировать WebSockets в tcp режиме, а теперь еще и в http режиме. HAProxy также получила поддержку терминации HTTPS. Так что нам опять необходимо установить девелопмент бранч.

wget http://haproxy.1wt.eu/download/1.5/src/devel/haproxy-1.5-dev18.tar.gz
tar xzvf haproxy-1.5-dev18.tar.gz
cd haproxy-1.5-dev18
make TARGET=linux26 USE_OPENSSL=1
make install

Stud

Хотя HAProxy и имеет возможность SSL-терминации, как правило для SSL терминации перед HAProxy используется stud. И это мы также хотим проверить.

git clone git://github.com/bumptech/stud.git
cd stud
make
make install

Теперь, когда все установлено, необходимо настроить конфигурационные файлы. Для Nginx можно скопипастить nginx.conf из корня этого репозитория в /etc/nginx/nginx.conf. Другие прокси можно конфигурировать “на лету”.

Настройка ядра

После установки всех прокси требуется некоторый тюннинг сокетов. Эту информацию я утянул из Интернета:

vim /etc/sysctl.conf

И установлены следующие значения:

# General gigabit tuning:
net.core.somaxconn = 16384
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
net.ipv4.tcp_syncookies = 1
# this gives the kernel more memory for tcp
# which you need with many (100k+) open socket connections
net.ipv4.tcp_mem = 50576   64768   98152
net.core.netdev_max_backlog = 2500

Бенчмаркинг

Проводится 2 разных теста:
1. Нагрузочный тест прокси-серверов без SSL. В этом случае мы тестируем только производительность проксирования WebSockets.
2. Нагрузочный тест прокси-серверов с SSL. Не стоит использовать незащищенные WebSockets, т.к. у них очень плохое соединение в браузерах. Но здесь добавляется лишняя нагрузка в процессе SSL-терминации на прокси-сервер.
В дополнение к нашим двум тестам мы пробуем различное число соединений:
— 2k
— 5k
— 10k
А для одинаковых результатов еще и:
— 20k
— 30k
Перед каждым тестом все WebSocket сервера сбрасываются, а прокси – реинициализируются. Thor нагружает все прокси-сервера с X-количеством соединений при 100 одновременных соединений. Для каждого установленного соединения отправляется и получается одно UTF-8 сообщение. После того, как сообщение получено, соединение закрывается.

Запуск

Stud

stud --config stud.conf

HAProxy

haproxy -f ./haproxy.cfg

Nginx

nginx

http-proxy

FLAVOR=http node http-proxy.js

WebSocketServer

FLAVOR=http node index.js

Результаты

http-proxy оправдал свое название, он проксирует запросы и делает это достаточно быстро. Но т.к. он основан на Node.js, он съедает много памяти. Даже для самого простого node-процесса необходимо 12+ Мб памяти. Для 10k запросов потребовалось около 70 Мб памяти. Если сравнивать с контрольным тестом, HTTP прокси понадобилось на 5 секунд больше. HTTPS, как и ожидалось, показал самый медленный результат, ведь Node.js с треском проигрывает по SSL. И это не говоря еще о том, что, будучи под серьезной нагрузкой, он полностью останавливает ваш основной цикл(event loop).
Существует pull request для http-proxy, который существенно снижает использование памяти. Я вручную применил патч, и в результате съедаемая память снизилась вдвое. Но все равно, даже после патча, использует больше памяти по сравнению с Nginx что легко объясняется написанием последнего на чистом С.
Я возлагал большие надежды на Nginx, и он меня не подвел. Он использовал не более 10 Мб памяти, и действительно отрабатывал очень быстро. В первый раз когда я тестировал Nginx, он показал ужастную производительность. Node показал даже более быстрые результаты c SSL чем Nginx, и я чувствовал, что тут должна быть какая-то ошибка, я должно быть ошибся в настройке Nginx. После пары подсказок от друзей я действительно изменил одну строку в конфиге – были неправильные настройки шифрования. Небольшая настройка и подтверждение при помощи openssl s_client -connect server:ip все исправило (теперь по умолчанию используется действительно быстрое шифрование RC4).
Следующим был НАРroxy, которое показало такую же производительность как и NGINX, но требовало меньше (7 Мб) памяти. Самая большая разница была при тестировании по HTTPS: он был очень медленный, даже близко не сравним с Nginx. Надеемся, что это будет исправлено, т.к. мы пока тестировали только девелоперский бранч. Тут я сделал такую же ошибку как и с Nginx, неправильно настроил шифрование, о чем мне правильно заметили на HackerNews. Дополнительно к тестированию HTTPS мы установили stud перед ним, чтоб проверить показанную производительность.

Выводы

http-proxy замечательная гибкая прокси, легко расширяемая и дописываемая. При использовании в продакшен я бы советовал запускать перед ней stud для для SSL терминации.
nginx и haproxy показали очень близкие результаты, трудно сказать, что бы кто-то из них был быстрее или лучше. Но если смотреть на них с точки зрения администрирования, проще деплоить и работать с одним nginx, чем со stud и haproxy.

HTTP
Proxy Connections Handshaken (средне) Latency (средне) Всего
http-proxy 10k 293 мс 44 мс 30168 мс
nginx 10k 252 мс 16 мс 28433 мс
haproxy 10k 209 мс 18 мс 26974 мс
контрольно 10k 189 мс 16 мс 25310 мс

Победитель: Nginx и HAProxy действительно быстрые и показанные ими результаты близки.

HTTPS
Proxy Connections Handshaken (средне) Latency (средне) Всего
http-proxy 10k 679 мс 62 мс 68670 мс
nginx 10k 470 мс 30 мс 50180 мс
haproxy 10k 464 мс 25 мс 50058 мс
haproxy + stud 10k 492 мс 42 мс 52403 мс
контрольно 10k 703 мс 65 мс 71500 мс

Победитель: Nginx и HAProxy действительно быстрые и показанные ими результаты близки.

Все результаты тестов доступны по: https://github.com/observing/balancerbattle/tree/master/results

Вклады(Contributions)

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

Автор: valch85

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js