====== Балансировка нагрузки с помощью 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** и пр.