Балансировщик HAProxy
HAProxy - это балансировщик нагрузки, который умеет распределять и проксировать запросы по TCP и HTTP протоколу.
Он бесплатный, легкий и шустрый, способен обрабатывать 20 тысяч запросов в секунду, а то и больше. Хорош для http-трафика. Его несложно вклинить в уже работающий проект. У него простая конфигурация и поэтому его можно быстро настроить под свои нужды.
Еще HAProxy использует Airbnb, Alibaba, Github, Instagram, Vimeo и еще не менее сорока известных высоконагруженных проектов.
Базовые понятия
Настройка HAProxy обычно сосредоточена вокруг пяти разделов: global, defaults, frontend, backend, реже listen.
- Раздел global определяет общую конфигурацию для всего HAProxy
- Defaults определяет настройки по-умолчанию для остальных разделов проксирования.
-
Раздел listen объединяет в себе описание для фронтенда и бэкенда и содержит полный список прокси. Он полезен для TCP трафика.
-
Раздел Frontend определяет, каким образом перенаправлять запросы к бэкенду в зависимости от того, что за запрос поступил от клиента.
-
Секция Backend содержит список серверов и отвечает за балансировку нагрузки между ними в зависимости от выбранного алгоритма
Разделы global, defaults и listen я затрагивать в статье почти не буду, поэтому просто дам стандартную конфигурацию из панели D2C, которую достаточно взять и применить:
global
log 127.0.0.1 local0
log 127.0.0.1 local1 notice
maxconn 4096
tune.ssl.default-dh-param 2048
defaults
log global
mode http
option httplog
option dontlognull
option http-server-close
option http-pretend-keepalive
option forwardfor
option originalto
retries 3
option redispatch
maxconn 2000
timeout connect 5000
timeout client 50000
timeout server 50000
default-server init-addr last,libc,none
А вот на разделах Frontend и Backend я остановлюсь подробнее. Они помогут нам настроить балансировщик исходя из наших задач.
Frontend и типы распределения нагрузки
Фронтенд обычно отвечает за тип распределения нагрузки и выбор бэкенда исходя из правил списков контроля доступа (ACL).
Транспортный уровень или Layer 4
Самый простой способ распределения нагрузки — транспортный или Layer 4. В этом случае HAProxy будет выбирать Бэкенд в зависимости от порта, на который поступил запрос. Например, если запрос поступил на http://ваш-сайт.ру, то трафик обработает Бэкенд, отвечающий за 80 порт.
Пример конфигурации фронтенда для работы на транспортном уровне:
mode. Тип распределения нагрузки. В данном случае мы используем транспортный, поэтому указан протокол TCP. Если указать http, HAProxy станет работать на прикладном уровне (Layer 7). bind. IP Адрес и порт, которые HAProxy должен слушать «на входе». default_backend. Название конфигурации группы серверов, к которым надо направить запрос для обработки. В данном случае запросы пойдут к backend с названием http-backend.
На Бэкенде так же придется прописать mode tcp. В случае с транспортным уровнем конфигурация бэкенда может выглядеть так:
backend web_server_tcp
mode tcp
balance roundrobin
server srv1 luna-1:80 check
server srv2 luna-2:80 check
В HAProxy в одном конфигурационном файле допустимо использовать несколько типов распределения нагрузки. Например, можно для 80 порта задать режим http и распределять нагрузку на 7 уровне, а для 443 задать TCP и перенаправлять запросы на 4 уровне.
Такая функциональность будет полезна при работе с SSL: можно переадресовать запросы с 80 порта на 443:
потом на транспортном уровне передать обработку запросов дальше:
и тогда уже сервера на бэкенде будут разбираться с SSL, а не HAProxy
Так будет выглядеть схема. В этом случае HAProxy передаст запрос на транспортном уровне, а его терминация произойдет на одном из серверов бэкенда.
Прикладной уровень или Layer 7
Прикладной уровень посложнее. Однако он позволит запускать несколько групп серверов приложений на одном домене и распределять между ними запросы в зависимости от их содержания.
Распределение нагрузки на прикладном уровне пригодится, если, например, один сайт состоит из разных веб-приложений.
Покажу на примере. Допустим, для блога используется WordPress, на сайте самописный движок на php, а личный кабинет требует Node-js для фронтенда. И все это обслуживают разные команды разработчиков, которые работают в нескольких git репозиториях.
При таком раскладе вы бы точно захотели разъединить все это физически. В этом помогут списки контроля доступа (ACL). Чтобы решить задачу, распределим трафик в завимости от пути на сайте:
если запрос идет к основному сайту http://ваш-сайт.ру, будем отправлять на Бэкенд №1 к NGINX, который отдает страницы промосайта;
при обращении к блогу по адресу /blog на Бэкенд №2 к Варнишам, которые кэшируют наш Блог;
при обращении к кабинету /cabinet на Бэкенд №3 с Nodejs.
Пример распределения нагрузки на прикладном уровне
Так схема выглядит в конфигурации фронтенда:
frontend http
bind *:80
mode http
acl url_blog path_beg /blog
use_backend backend-2 if url_blog
acl url_cabinet path_beg /cabinet
use_backend backend-3 if url_cabinet
default_backend backend-1
mode http сообщает о том, чтобы HAProxy работал на уровне 7 по http-протоколу; инструкция acl url_blog path_beg /blog создает правило url_blog, которое будет срабатвать при обращении по этому адресу; инструкция use_backend backend-2 if url_blog сообщает, что если срабатывает правило url_blog, надо отправлять запросы к списку серверов на backend-2; default_backend backend-1 говорит о том, что по умолчанию отправлять всех к списку серверов на backend-1, если ни одно правило не сработало.
На бэкенде мы так же пропишем mode http:
backend web_server_tcp
mode http
balance roundrobin
server srv1 luna-1:80 check
server srv2 luna-2:80 check
Алгоритмы балансировки
За алгоритм выбора сервера отвечает секция Backend конфигурационного файла. Всего у Haproxy 9 алгоритмов.
Roundrobin
Первый в списке и самый простой алгоритм — Round Robin. Включается записью balance roundrobin в секции backend. С этой опцией HAProxy будет перебирать сервера по очереди и равномерно покрывать нагрузкой вашу «ферму». Пример конфигурации:
* в моем случае luna-1 — это внутренний alias сервера, у вас скорее всего будет IP-адрес.
Если к серверам добавить параметр weight, то получится более продвинутая версия алгоритма — weighted roundrobin:
Благодаря разным значением весов, балансировщик будет распределять нагрузку исходя из физических возможностей серверов. И сервер с параметром weight 2 из примера выше будет получать в 2 раза больше запросов, чем с параметром weight 1.
+
Алгоритм поможет добиться понятной, предсказуемой и стабильной балансировки. Все сервера получат справедливое, обозначенное в соответствии со значением веса, количество запросов на обработку.
—
Однако, Round Robin имеет один существенный недостаток, который не позволяет его применять там, где есть длинные сессии. При балансировке алгоритм не учитывает количество активных соединений. И даже если один из узлов будет полностью загружен, он все равно получит новые запросы.
Static-rr
Об этом алгоритме скажу кратко. По сути, Static-rr — это тот же Roundrobin. Одно исключение: изменение веса серверов на лету с его применением не даст никакого эффекта. Зато Statc-rr не ограничен по количеству бэкендов в отличие от Roundrobin, который может работать максимум с 4095 активными серверами.
Включается с помощью записи «balance static-rr» в секции бэкенда.
Least Connections
Алгоритм с названием «Least connections» учитывает количество подключений на серверах. Таким образом, каждый следующий запрос передаётся серверу с наименьшим количеством активных подключений. Включить алгоритм можно с помощью опции «balance leastconn» в секции backend.
Алгоритм «Least connections» в Haproxy динамический и способен назначать веса серверам «на лету».
+
Least connections подходит для задач, сопряженных с длительными соединениями. Например, для распределения нагрузки между серверами БД. Если на каких-то узлах будет слишком много активных подключений, новых запросов они уже не получат, и наоборот.
—
Нет никакого смысла применять алгоритм для задач с короткими сессиями, характерными, например, для http протокола. Там подойдет Round Robin.
First
Алгоритм First появился в HAProxy в версии 1.5. Если применить его , то балансировщик начнет заполнять свободные для соединений слоты начиная с первого сервера в списке бэкенда и по порядку.
Чтобы использовать алгоритм First, нужно прописать в секции Backend «balance first» и определить желаемое значение «maxconn» для серверов.
Исходя из конфигурации в примере, HAProxy сначала заполнит тысячью соединений srv1, а потом пойдет наполнять srv2.
+
Главная цель алгоритма First — использовать наименьшее количество серверов. Это позволяет выключать дополнительные сервера в неинтенсивные часы работы.
Для полного эффекта придется поставить контроллер, регулярно проверяющий использование серверов в ферме. Он должен будет отключать неиспользуемые сервера и включать дополнительные при повышении нагрузки.
—
Не сказать, что это минус ввиду специфики алгоритма, однако алгоритм First совершенно не учитывает веса серверов и распределяет нагрузку в зависимости от заданного вручную значения maxconn.
Source
При использовании этого алгоритма, IP-адрес источника хэшируется и делится на общий вес работающих серверов, чтобы определить, какой сервер будет получать запрос. Таким образом источник с одним и тем же IP всегда обращается к одному серверу. Включить эту опцию можно при помощи «balance source».
+
Этот алгоритм обычно используют для работы по TCP протоколу, где невозможно присвоить cookie.
—
Если у источника динамический IP, алгоритм не сможет привязать его сессии к одному и тому же серверу.
URI
Алгоритм выбирает сервер исходя из адреса страницы. Благодаря ему один и тот же сервер будет обрабатывать определенные конечные адреса страниц. Включить алгоритм можно с помощью опции «balance uri«.
+
Алгоритм полезен при балансировке нагрузки между кэширующими серверами. Если использовать другие решения, суммарный объем кэша на всех узлах будет раздуваться. В случае же с алгоритмом URI обращение к конкретному адресу гарантированно направит запросу к тому серверу, на котором хранится кэш для данной страницы.
—
Минус алгоритма заключается в его узкой специфике применения. На мой взгляд, история с кэширующими серверами — единственная, где решение находит применение.
URL parameter
Алгоритм URL parameter выбирает сервер на основе GET-параметров запроса. Если используется модификатор «check_post», то алгоритм будет принимать решение, в том числе в зависимости от аргумента параметра. Для наглядности приведу 2 примера использования алгоритма:
- balance url_param userid
- balance url_param session_id check_post 64
В первом случае алгоритм будет запросы пользователей направлять на одинаковые сервера, руководствуясь значением их userid. Во втором случае алгоритм назначит определенный сервер для обработки запросов с id сессии 64.
Если никаких параметров передано не будет, алгоритм будет распределять нагрузку по принципу Round robin.
+
URL parameter может быть полезен, если вы хотите закрепить сервера за авторизованными пользователями, а для анонимных распределять нагрузку с помощью простого Round Robin.
—
Алгоритм будет работать только в http mode. Для TCP трафика он бесполезен.
HDR
Выбирается сервер на основе заголовка HTTP запроса. Если искомое значение отсутствует в заголовке, то используется принцип Round Robin.
- balance hdr(User-Agent: Mozilla/5.0)
В данном случае HAProxy будет искать в заголовке запроса запись User-Agent: Mozilla/5.0.
+
Алгоритм будет полезен, если необходимо, например, привязывать пользователей к серверам по типу браузера, адресу запроса и т.п.
—
Опять же, алгоритм для очень специфических узких задач. Пригодится не многим.
rdp-cookie
Алгоритм эквивалентен ACL ‘req_rdp_cookie()’ секции Frontend. Его задача — передавать одного и того же пользователя на один и тот же сервер с идентификацией по cookie.
+
Алгоритм предназначен привязки к серверам сессии с определенными cookie.
—
Если cookie не используются клиентом, то алгоритм будет работать как простой Round robin.
Резюме
В широкой практике обычно используются 2 алгоритма из списка: Round Robin и Leastconn. Первый для http трафика, второй — для обслуживания кластера баз данных. Остальные по ситуации.
Если у вас несколько кэширующих серверов, то пригодится URI. Если требуется привязать источники запросов к определенным серверам, помогут source и rdp-cookie. Если захотите распределить запросы по каким-то их свойствам, то пригодятся HDR и URL parameter.
Об алгоритмах, пока все. В следующей статье цикла о HAProxy разберу полноценную конфигурацию.