====== Балансировка нагрузки с помощью HAProxy ======
Пример горизонтального масштабирования для распределения запросов между несколькими серверами для повышения отказоустойчивости.
Рассмотрим решение по балансировке нескольких веб-серверов при помощи сервиса **HAProxy**.
[[https://fatalex.cifro.net/lib/plugins/ckgedit/fckeditor/userfiles/image/nginx/sheme.png|{{https://fatalex.cifro.net/lib/plugins/ckgedit/fckeditor/userfiles/image/nginx/sheme.png?nolink&|Общая схема}}]]
==== Технические требования ====
* Сервер под балансировщик с двумя сетевыми интерфейсами //(Рекомендация. Внешний адрес для связи с внешним миром и локальный для общения между узлами кластера)//;
* Два и более серверов под распределение запросов/трафика;
В примере будет использоваться дистрибутив **Linux CentOS 7**.
==== Установка и настройка backend-серверов ====
В качестве backend-серверов я буду использовать несколько веб-серверов с **NGINX** и настроенным **SSL**.
Прежде всего установим **NGINX**
|yum install nginx
|
== Выполним настройку веб-сервера ==
|server {
listen 80;
server_name devservers.network;
rewrite ^(.*)$ https://devservers.network$1 permanent;
}
server {
server_name devservers.network;
access_log /srv/www/devservers.network/logs/access.log;
error_log /srv/www/devservers.network/logs/error.log;
root /srv/www/devservers.network/public_html;
ssl on;
ssl_session_timeout 24h;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
listen 443 ssl http2 proxy_protocol;
set_real_ip_from 10.0.1.10/32;
real_ip_header proxy_protocol;
ssl_certificate /etc/nginx/ssl/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/privkey.pem;
location / {
try_files $uri $uri/ /index.html;
}
location ~ \.(js|css|png|jpg|gif|swf|ico|pdf|mov|fla|zip|rar)$ {
try_files $uri =404;
}
}
|
Конфигурацию **SSL** можно выполнить и на самом балансировщике, а бэкенд сервера оставить работать на 80 порту, но в моем случае я буду использовать режим ''SSL Pass-Through''. Не забываем поместить **SSL**-сертификаты в директорию ''/etc/nginx/ssl''.
Для того, чтобы принимать реальные IP-адреса клиентов на веб-сервере от **HAProxy** необходимо добавить ''proxy_protocol'' в параметр **listen**, а также указать реальный адрес откуда разрешить принимать запросы:
|set_real_ip_from 10.0.1.10/32;
real_ip_header proxy_protocol;
|
Создадим приветственную страницу на обоих веб-серверах ''touch /srv/www/devservers.network/public_html'' со следующим содержимым, изменив только номер сервера для его дальнейшего определения:
|
Server #1
This is server #1
|
Добавляем **NGINX** в автозагрузку и запускаем сервис.
|systemctl enable nginx
systemctl start nginx
|
И не забываем выполнить настройку **Firewalld**
|firewall-cmd --permanent --add-service=https
firewall-cmd --reload
|
==== Установка и настройка балансировщика ====
В качестве сервера балансировки я буду использовать **VDS** сервер с ресурсами 1 vCPU и 1Gb RAM. При правильной настройке, данных мощностей хватит для обслуживания 10-15к одновременных сессий, чего вполне достаточно для среднестатистического интернет-ресурса.
=== Установим HAProxy ===
Пакет **HAProxy** доступен в базовой репозитории **CentOS**.
|yum install haproxy
|
=== Настройка HAProxy ===
**HAProxy** обладает очень гибкими настройками и конфигурация может содержать большое количество директив и условий. Конфигурационный файл состоит из нескольких секций. Директивы //frontend, backend, listen// должны иметь своё имя, к примеру //defaults// - может, но не обязательно, а такие как //global// - не должны.
Выполняем конфигурацию **HAProxy** в файле ''/etc/haproxy/haproxy.cfg''. Рекомендую использовать свой конфигурационный файл, а представленный по умолчанию оставить как резерв.
=== Секция global ===
|global
log /dev/log local0
chroot /var/lib/haproxy
pidfile /var/run/haproxy.pid
stats timeout 30s
maxconn 4000
user haproxy
group haproxy
daemon
|
Рассмотрим настройки в директиве ''global'':
* **log** - вести лог в ''/dev/log'' сохраняя в **local0**;
* **chroot** - настройки безопасности, позволяющие работать **HAProxy** только в указанной директории;
* **maxconn** - максимальное количество соединений на один процесс;
* **daemon** - запуск процесса как демона.
=== Секция defaults ===
В секции **defaults** описываются параметры по умолчанию для всех других секций, следующих за данной. В файле конфигурации может быть несколько секций **defaults**, в этом случае параметры, описанные в данной секции, будут переопределены в следующей, и будут применяться к секциям, идущим за ней.
В нашем примере указаны следующие параметры:
|defaults
log global
mode http
retries 3
option httplog
option redispatch
maxconn 2000
contimeout 2000
timeout http-request 10s
timeout queue 1m
timeout connect 10s
timeout client 1m
timeout server 1m
timeout http-keep-alive 10s
timeout check 10s
|
* **log** - указывает в какой лог вести запись (//global в данном случае означает, что используются параметры, заданные в секции global//);
* **mode** - устанавливает протокол взаимодействия, принимает одно из значений: ''tcp'', ''http'', ''health'';
* **retries** - количество попыток соединения с сервером в случае отказа;
* **option httplog** - формат лога, в случае использования **HAProxy** для проксирования HTTP-запросов (//рекомендуется включить данную настройку//);
* **option redispatch** - разрешает программе разорвать и переназначить сессию в случае отказа сервера;
* **contimeout** - максимальное время ожидания успешного соединения с сервером.
В примере я использую параметры ''timeout'', которые позволяют более гибко настроить поведение балансировщика. Подробно с доступными параметрами можно ознакомиться в документации к **[[https://cbonte.github.io/haproxy-dconv/1.9/configuration.html|HAProxy]]**
=== Секция frontend ===
Укажем **HAProxy** какие запросы он должен обрабатывать, для этого задаем секцию **frontend** с именем ''https-in'':
|frontend https-in
log /dev/log local0
mode tcp
option tcplog
bind *:443
default_backend backend-https-servers
|
Параметр **bind** со значением ''*:443'' говорит о том, что **HAProxy** должен принимать все запросы на 443-й порт. Ещё раз напомню, что в данном примере я использую режим ''SSL Pass-Through'', поэтому настройка **SSL** на самом **HAProxy** не выполняется.
Параметр **default_backend** указывает, какие сервера будут обрабатывать эти запросы. В данном случае - **backend-https-servers**, именно так необходимо назвать секцию **backend**.
=== Секция backend ===
В этой секции мы задаем алгоритм балансировки (//параметр balance//) и список серверов-обработчиков (//server//). В качестве алгоритма балансировки указываем **roundrobin**.
**HAProxy** имеет несколько алгоритмов балансировки:
* ''roundrobin'' - каждый сервер получает запросы пропорционально своему весу, при этом веса серверов могут меняться на лету;
* ''static-rr'' - то же, что и **roundrobin**, только изменение весов на лету не даст никакого эффекта;
* ''leastconn'' - выбирает сервер с наименьшим количеством активных соединений;
* ''first'' - выбирает первый сервер с доступными слотами для соединения **source** - на основе хэша IP-адреса отправителя запроса и весов серверов назначается сервер для соединения;
* ''uri'' - сервер выбирается на основе адреса (без параметров) страницы;
* ''url_param'' - сервер выбирается на основе GET-параметров запроса;
* ''hdr'' - сервер выбирается на основе заголовков запроса;
* ''rdp-cookie'' - сервер выбирается на основе cookie (если они не установлены, то применяется обычный **roundrobin**);
При перечислении серверов используется следующий формат: ключевое слово **server**, имя сервера, IP-адрес, дополнительные параметры (//в данном случае - проверка статуса хоста и Proxy Protocol, которые позволяет перенаправлять реальные IP-адреса клиента с HAProxy на веб-сервер//).
|backend backend-https-servers
mode tcp
balance roundrobin
option ssl-hello-chk
server nginx01 10.0.1.3:443 check send-proxy
server nginx02 10.0.1.4:443 check send-proxy
|
==== Просмотр статистики HAProxy ====
Для включения расширенной статистики **HAProxy** необходимо в конфигурационный файл добавить секцию:
|listen stats
bind :10001
stats enable
stats uri /haproxy_stats
stats auth admin:password
|
* ''bind :10001'' - **HAProxy** будет ожидать запросы к порту 10001;
* ''stats enable'' - включить отчёты со статистикой;
* ''stats uri'' - установка адреса страницы с отчётом;
* ''stats auth'' - логин и пароль для авторизации на странице со статистикой;
В секции ''listen'' указываем **HAProxy**, что он должен показывать статистику на странице ''/haproxy_stats'' на порту 10001 после ввода логина ''admin'' и пароля ''password''.
=== Проверяем. ===
Переходим по адресу **HAProxy** (//IP-адрес или хостнйем//) и просто обновляем страницу. В зависимости от выбранного балансировщиком сервера будем получать ответ ''This is server #1'' либо ''This is server #2''.
Проверяем статистику. Переходим по адресу ''SITE_NAME:10001/haproxy_stats''
[[https://fatalex.cifro.net/lib/plugins/ckgedit/fckeditor/userfiles/image/nginx/001.png|{{https://fatalex.cifro.net/lib/plugins/ckgedit/fckeditor/userfiles/image/nginx/001.png?nolink&}}]]
На этом всё. Выше рассмотрен самый простой метод балансировки. Более сложная настройка требует грамотно составленного ТЗ и технических данных проекта. **HAProxy** очень удобный и гибкий в настройке инструмент с помощью которого можно выполнить балансировку и других сервисов, к примеру почтовый сервер, **Memcached**, **Redis** и пр.