«Битва балансеров» — это нагрузочный тест балансеров / прокси, которые поддерживают 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