В двух датацентрах хостятся одинаковые web-сервисы (Microsoft Exchange 2016) на нескольких серверах (в ДЦ каждом по два сервера).
Запросы к web-сервисам могут приходить как от процессов в одном из датацентров (пользователи VDI), так и из внешнего интернета.
Датацентры неравноправны. Один из них - основной (постоянно обслуживает основную массу запросов), второй - резервный (постоянно обслуживает меньшую часть запросов).
Зачача - настроить отказоустойчивый опенсорсный балансировщик, который бы мог бы пережить следующие дизастеры:
Функционал high reliability реализуется с помощью демона, реализующего протокол VRRP, например - keepalived. Демон следит за состоянием нод кластера и если активная нода выходит из строя, то переключает нагрузку (передает IP-адрес) на запасную (пассивную) ноду.
Кроме keepalived можно использовать heartbeat.
keepalived попроще, а heartbeat пофункциональнее и имеет несколько иное назначение.
Будем настраивать active-passive связку из двух haproxy + keeapalived.
На каждой ноде будет практически однаково настроен haproxy. В конфигурациях backend-серверов будут прописаны серверы, находящиеся в одном датацентре с нодой балансировщика.
В конфигурации keepalived на каждой ноде балансировщика будет прописан скрипт, проверяющий состояние процесса haproxy и состояние сервиса. Нода балансировщика может считаться здоровой, если жив процесс haproxy и сервис доступен через балансировщик.
haproxy - балансировщик. Осуществляет проверку состояния backend-серверов, балансирует нагрузку на них (в соответствии с кинфигурацией) и предоставляет к ним доступ через frontend.
Установка:
sudo apt-get update && sudo apt-get -y install haproxy
Вот пример настройки haproxy (/etc/haproxy/haproxy.cfg):
global log /dev/log local0 log /dev/log local1 notice chroot /var/lib/haproxy stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners stats timeout 30s user haproxy group haproxy daemon ######## Default values for all entries till next defaults section defaults option dontlognull # Do not log connections with no requests option redispatch # Try another server in case of connection failure option contstats # Enable continuous traffic statistics updates option logasap retries 3 # Try to connect up to 3 times in case of failure timeout connect 5s # 5 seconds max to connect or to stay in queue timeout http-keep-alive 1s # 1 second max for the client to post next request timeout http-request 15s # 15 seconds max for the client to send a request timeout queue 30s # 30 seconds max queued on load balancer timeout tarpit 1m # tarpit hold tim backlog 10000 # Size of SYN backlog queue mode tcp #alctl: protocol analyser option tcplog #alctl: log format log global #alctl: log activation timeout client 300s #alctl: client inactivity timeout timeout server 300s #alctl: server inactivity timeout default-server inter 3s rise 2 fall 3 #alctl: default check parameters frontend ft_exchange_tcp bind *:443 name https #alctl: listener https configuration. maxconn 100000 #alctl: connection max (depends on capacity) default_backend exchange_2016_backend #alctl: default farm to use backend exchange_2016_backend balance roundrobin # maximum SSL session ID length is 32 bytes. stick-table type binary len 32 size 30k expire 10s acl clienthello req_ssl_hello_type 1 acl serverhello rep_ssl_hello_type 2 # use tcp content accepts to detects ssl client and server hello. tcp-request inspect-delay 5s tcp-request content accept if clienthello # no timeout on response inspect delay by default. tcp-response content accept if serverhello # SSL session ID (SSLID) may be present on a client or server hello. # Its length is coded on 1 byte at offset 43 and its value starts # at offset 44. # Match and learn on request if client hello. stick on payload_lv(43,1) if clienthello # Learn on response if server hello. stick store-response payload_lv(43,1) if serverhello fullconn 100000 option httpchk GET /ews/healthcheck.htm "HTTP/1.0\r\nHost: exch2016.domain.com" server exch_server1 exch1.domain.com:443 maxconn 100000 check check-ssl verify none server exch_server2 exch2.domain.com:443 maxconn 100000 check check-ssl verify none email-alert mailers mta email-alert level info email-alert from haproxy-alert@domain.com email-alert to admin@domain.com mailers mta mailer smtp1 smtp.domain.com:25 frontend stats bind *:8080 mode http stats enable # stats auth admin:adminpassword stats uri /
Тут настраивается единственный frontend для единственного backend в режиме tcp.
Балансировка - round-robin.
Прописан session sticking, чтобы клиент не прыгал по серверам в пределах одной сессии.
Проверка состояния backend-серверов осуществляется с помощью запроса:
option httpchk GET /ews/healthcheck.htm "HTTP/1.0\r\nHost: exch2016.domain.com"
Если ответ 200, то backend-сервер считается живым.
Для второй ноды конфигурация такая же, но список backend-серверов другой:
server exch_server3 exch3.domain.com:443 maxconn 100000 check check-ssl verify none server exch_server4 exch4.domain.com:443 maxconn 100000 check check-ssl verify none
keepalived следит за состоянием нод в пределах виртуального роутера (нод keepalive с одинаковым параметром virtual_router_id) и с заданным интервалом вычисляет приоритет (priority) ноды (в зависимости от результатов выполнения скрипта). Если приоритет ноды меняется - происходят выборы новой master-ноды. Если backup-нода обнаруживает недоступность master-ноды - она становится master-нодой.
Установка keepalived:
sudo apt-get update && sudo apt-get install keepalived
Вот конфигурация основной (master) ноды (/etc/keepalived/keepalived.conf):
global_defs { notification_email { admin@domain.com } notification_email_from haproxy-alert@domain.com smtp_server smtp.domain.com:25 smtp_connect_timeout 30 } vrrp_script chk_haproxy { script "/usr/bin/killall -0 haproxy && /usr/bin/curl -k 'https://localhost/ews/healthcheck.htm'" interval 2 weight 2 } vrrp_instance VI_1 { state MASTER interface ens160 virtual_router_id 101 priority 101 advert_int 1 smtp_alert authentication { auth_type PASS auth_pass superpassword } virtual_ipaddress { 172.30.129.131 } track_script { chk_haproxy } }
Тут прописаны секции:
Вот конфигурация резервной (slave) ноды:
global_defs { notification_email { admin@domain.com } notification_email_from haproxy-alert@domain.com smtp_server smtp.domain.com:25 smtp_connect_timeout 30 } vrrp_script chk_haproxy { script "/usr/bin/killall -0 haproxy && /usr/bin/curl -k 'https://localhost/ews/healthcheck.htm'" interval 2 weight 2 } vrrp_instance VI_1 { state MASTER interface ens192 virtual_router_id 101 priority 100 advert_int 1 smtp_alert authentication { auth_type PASS auth_pass superpassword } virtual_ipaddress { 172.30.129.131 } track_script { chk_haproxy } }
Для подключения клиентов:
https://www.digitalocean.com/community/tutorials/how-to-set-up-highly-available-haproxy-servers-with-keepalived-and-floating-ips-on-ubuntu-14-04
https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/load_balancer_administration/ch-initial-setup-vsa
https://tecadmin.net/setup-ip-failover-on-ubuntu-with-keepalived/