Новый L4 Load Balancer с нативной реализацией SRV record service discovery и Docker API service Discovery

Как все начиналось


В ходе работы с микросервисами мы неоднократно сталкивались с проблемами сервис дискавери при автоскелинге, схлопывании лишних нод.


Были перепробованы почти все решения существовавшие или существующие на данный момент, но как водится — ничего не ложилось идеально на наши динамичные окружения (десятки остановок/запусков однотипных контейнеров в час). Наиболее близкое решение было NGINX+Consul+Consul templates, но оно было некрасивым, требовало перезапуска, не давало возможности использовать внешние хелсчеки иначе как через Consul.


В общем, как всегда бывает — было принято решение написать свое решение. В процессе обсуждения всплыли десятки вещей, которые хорошо было бы реализовать, из них были выбраны самые критичные для нас и интересные для общественности.


Заложенный функционал на первую итерацию


Типы балансировки:


Iphash
Leastconn
Roundrobin
Weight


Дискавери (определение пула бекендов для каждого фронтенда):


Static — просто список серверов в конфиге.
Docker — запрос в докер Docker / Swarm API фильтрованные по label и внутренним портам контейнера.
Exec — инициирование запуска внешнего скрипта, чтение из stdout и его разбор по регулярке (пока прописана жестко).
JSON — запрашивает через http-запрос URL и разбирает его по паттернам (поддерживает многоуровневый JSON).
Plaintext — запрашивает через http-запрос URL и разбирает его по заданному в конфиге регулярному выражению.
SRV — запрашивает у заданного DNS SRV записи по имени сервиса.


Хелсчеки


Так как изначально было совершенно понятно, что мы просто не потянем имплементировать хелсчеки в объеме того же haproxy, было принято решение отделаться малой кровью и сделать всего 2 типа хелсчеков.


Ping — простой TCP ping;
Exec — запуск произвольного бинарника с передачей ему параметров и чтение из stdout вывода.


Примеры использования


SRV Discovery


У нас есть произвольные сервисы, регистрирующие себя, к примеру, в Consul. Будем использовать Consul dns для определения пула серверов.


image


В этом примере мы определили тип балансировки как "srv", так же определен DNS-сервер и его порт, на который будут идти запросы на сервис дискавери. Определена частота обновления списка серверов, а так же немаловажная переменная — политика для случая, когда DNS-сервер не ответил. Для максимальной консистентности окружения нужно ставить failpolicy="setempty". В таком случае при отсутствии ответа от DNS весь пул бекенд серверов будет обнулен, а входящие соединения будут сбрасываться. В противном случае нужно использовать failpolicy = "keeplast", тогда балансировщик будет использовать последние данные, пришедшие до сбоя соединения с DNS.


toml
[servers.sample2]
bind = "localhost:3001"
protocol = "tcp"
balance = "weight"

  [servers.sample2.discovery]
  failpolicy = "keeplast"
  kind = "srv"
  srv_lookup_server = "66.66.66.66:8600" # dns server and port
  srv_lookup_pattern = "api.service.ireland.consul." # SRV service pattern 

  [servers.sample2.healthcheck]
  fails = 1                      
  passes = 1
  interval = "2s"                
  kind = "ping"
  timeout = "500ms" 

Docker / Swarm Балансировка.


По сути различий в API и способе настройки для Docker/Docker Swarm нет. Мы можем одинаково работать и с Docker хостом, и с Docker Swarm кластером. Рассмотрим работу с ними в одном примере.


image


Сейчас мы будем балансировать определенными сервисами, используя Docker Swarm, как более общий пример. Все нижеописанное работает и для отдельного Docker хоста. В данном примере мы определяем тип дискавери как "docker", определяем базовый docker url, лейблы и внутренний порт докер контейнера (со стороны сети самого контейнера) по которым балансировщик будет делать выборку, из которых формируется пул бекенд серверов.


Для данного примера мы будем использовать более "продвинутый" тип хелсчеков, а именно exec-хелсчеки. Помимо параметров частоты запуска чеков есть еще время отработки скрипта. Время между запусками должно быть больше времени отработки скрипта, чтобы не было "набегов". Команда запуска данного хелсчека формируется как /path/to/script [ip] [port]. После отработки скрипта, он должен выводить в stdout строку, которая сравнивается с положительным и отрицательным предполагаемым результатом.


[servers.sample3]
bind = "localhost:3002"
protocol = "tcp"
balance = "weight"

  [servers.sample3.discovery]
    interval = "10s"
    timeout = "2s"
    kind = "docker"
    docker_endpoint = "http://localhost:2377"  # Docker / Swarm API    
    docker_container_label = "api=true"  # label to filter containers
    docker_container_private_port = 80   # gobetween will take public container port for this private port

[servers.sample3.healthcheck] 
kind = "exec"
interval = "2s"  
exec_command = "/etc/gobetween/checks/exec_healthcheck.sh"
exec_expected_positive_output = "1"           
exec_expected_negative_output = "0"           
exec_timeout_duration = "1s"             

В последующих статьях я планирую привести несколько примеров более сложного использования других видов дискавери. Также будет описана специфика конфигурирования и установки под Windows.


Поделиться публикацией

Похожие публикации

Комментарии 19

    0
    шикарно! спасибо за интересный проект!
    если есть результаты перформанс тестов / сравнение по перформансу с другими балансировщиками — не стесняйтесь публиковать ;)
      +2
      Спасибо за отзыв, но если внимательно глянуть в ссылки после статьи есть те самые тесты производительности:
      Сравнивали с Haproxy и Nginx

      https://github.com/yyyar/gobetween/wiki/Performance-tests-results
        0
        простите, был невнимателен :) спасибо
    • НЛО прилетело и опубликовало эту надпись здесь
        0
        мы не сможем гарантировать консистентность списка. в единицу времени при нескольких докер эндпоинтах.
        если небольшой рассинхрон это ок то можно об этом подумать.
        Хотя как по-мне проще и лучше использовать Dokcer Swarm. есть вариант когда на менеджмент ноде сворма прописывается статик лист докер нод.
        Тогда на сами докер ноды устанавливать ничего не нужно. А уж менеджмент ноду использовать как эндпоинт для ЛБ.
          0
          Прикрутите Raft и будет вам консистентность…
        0
        В ходе работы с микросервисами мы неоднократно сталкивались с проблемами сервис дискавери при автоскелинге, схлопывании лишних нод.

        А вы пробовали Kubernetes? Там round-robin load balancing + service discovery из коробки.
          0
          На кубернейтсе не заканчиваются контейнеры, а уж тем более микросервисы. Тут более общий подход. Посмотрите вики проекта. Там намного больше способов дискавери чем описано в данной статъе.
          • НЛО прилетело и опубликовало эту надпись здесь
              0
              для того чтоб заменить cube proxy нужно:
              1) Поддержка UDP которой пока нет
              2) Api которое только начинает имплеменрироваться.

              Всему свое время.
              • НЛО прилетело и опубликовало эту надпись здесь
            0
            Если есть consul и нужен service discovery с планировщиком и гарантией состояний — надо было внедрять nomad.

            Нужно понимать что есть CRDT, а есть консенсус на Raft/Paxos…
            Вот в случае с Consul'ом для Health Check используется CRDT c Serf'a.
            В статье шла речь о том что вам нужен консенсус и планировщик для гарантий синхронизации — надо было использовать Nomad для этого.

            В общем эт уже разработано, надо было чуть глубже вникать в стэк HashiCorp.
            Kubernetes тоже прокатит — там Raft вроде как.

            Советую ознакомится со способами решения задач синхронизации в распределённых средах и как они ложатся на САР теорему.
              0
              Было желание сделать простое и гибкое решение с кастомизацией. Оттуда и возник exec, json и plaintext discovery.
              Смотрите на это проект как на балансировщик с плюшками, позволяющими решить множество задач быстро и просто.
                0
                Там просто когда таких балансировщиков с плюшками десяток запущено и нужно что бы у них одни и те же состояния были — начинаются проблемы, эти проблемы решаются с помощью решения задачи принятия консенсуса, в случае с тем же Nomad/Kubernetes.
              0
              Интерестно бы было увидить в тестах traefik.

              Пробовали с аффинити/so_reuseport запускать?
                0
                а какой смысл сравнивать HTTP балансер с l4 балансером?
                Если у меня TCP (в будущем и UDP) сервис базирующийся на протоколе, который к HTTP и HTTPS не имеет никакого отношения, чем мне поможет traefik?
                Тесты на одинаковые кейсы сделаем позже, но это разные инструменты с частично пересекающимеся сферами использования.
                  0
                  L4 там вопрос времени исключительно — (https://github.com/containous/traefik/issues/10). Но перф ядра былобы интерестно сравнить.

                  А что про аффинити/so_reuseport?
                    0
                    Вот когда будет- сравним.
                    А пока что провел тест на простейшем варианте настройки traefik. Как и следовало ожидать чистый L4 быстрее

                    traefik Gobetween
                    Req/Sec 10591 14540
                    mb/s 8.35 11.9

                    Хотя неправильно проводить тесты на ЛБ работающих на разных леерах.
                0
                https://habrahabr.ru/post/304096/
                продолжение

                Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                Самое читаемое