haproxy на клиентской стороне

26 марта 2019

В настоящее время многие сервисы поддерживают отказоустойчивость из коробки, т.е. могут быть установлены на несколько узлов и (а) сохранять работоспособность при выходе из строя части из них, а также (б) распределять нагрузку между собой, т.е. предоставлять HA/LB — High Availibility и Load Balancing.

Некоторые известные примеры: LDAP, ElasticSearch, Ceph, MySQL (шутка) и т.д.

Проблема заключается в том, что клиентская часть не всегда знает и поддерживает кластерные возможности серверной части. Например, связь с ElastisSearch производится по протоколу HTTP. Если узел кластера, с которым связывается клиентское приложение, становится нерабочим, приложение должно самостоятельно принять решение, что надо обращаться к другому узлу кластера, т.е. использовать другой URL.

Решить данную проблему можно несколькими способами. Перечислим наиболее известные из них:

  • балансировка по IP-адресу;
  • DNS-балансировка;
  • BGP anycast;
  • Frontend — все запросы приходят на приложение-балансировщик (в зависимости от протокола — nginx, haproxy, mysql router и т.д.), которое передаёт их на исправные узлы.

Каждый из этих методов имеет свои недостатки:

  • IP-балансировка требует, чтобы серверы находились в одной подсети.
  • DNS-балансировка практически не используется, т.к. имеет недопустимо большое время задержки, потому что DNS-записи кэшируются на срок от нескольких минут до суток.
  • BGP anycast в публичной сети требует анонсировать блок не меньше /24. Мы рассматриваем случай, когда и сервисы, и клиентская часть являются частью одного распределённого приложения, поэтому допустимо использовать для их связи приватные диапазоны ASnums и IP-адресов, но если сервисы находятся в разных точках сети, то такой BGP сможет работать только поверх VPN. Вряд ли надо пояснять, что в силу громоздкости подобная конструкция способна стать как решением существующих проблем, так и источником новых.
  • Frontend является единой точкой отказа, а его пропускная способность — потенциальным узким местом.

Недостатки последнего варианта можно преодолеть, если переместить балансировщик к клиенту, т.е. вместо одного самостоятельного компонента, обслуживающего многих клиентов, будет много балансировщиков, каждый из которых обслуживает только того клиента, вместе с которым запущен.

На эту роль идеально подходит haproxy — производительный, относительно компактный, с простым файлом настроек, и с возможностью менять настройки на лету.

Доступность сервисов haproxy умеет проверять на двух уровнях:

  • сетевом — отвечает ли TCP-порт на запрос соединения;
  • прикладном — в настоящий момент поддерживаются HTTP, LDAP, MySQL, PostgreSQL, Redis и SMTP.

Например, если приложение должно работать с кластерами ElasticSearch и MySQL, то конфигурация haproxy может выглядеть примерно так:

listen mysql
    bind 127.0.0.1:3306
    mode tcp
    balance roundrobin
    option mysql-check user haproxy_check
    server mysql-cluster-node-1 10.0.0.1:3306 check
    server mysql-cluster-node-2 10.0.0.2:3306 check

listen elastic
    bind 127.0.0.1:9200
    mode http
    balance roundrobin
    option forwardfor
    option httpclose
    option httpchk
    http-check expect status 200
    server es-cluster-node-1 10.0.0.101:9200 check
    server es-cluster-node-2 10.0.0.102:9200 check

listen 0.0.0.0:8080
    mode http
    stats enable
    stats uri /haproxy_stats
    stats auth haproxy_admin:VerySecretPassword

Дополнительным достоинством данной схемы является упрощение установки приложений — теперь от них требуется подключаться к сервисам по адресу 127.0.0.1, т.е. достаточно один раз указать этот адрес при разработке в настройках по умолчанию. За знание фактических адресов сервисов будет отвечать haproxy, настроенный под конкретную конфигурацию кластеров.



← Назад в Блог

Подпишитесь на новые статьи: