Хочу рассказать вам еще об одном способе балансировки нагрузки. Про Pacemaker и IPaddr (ресурс-агент) и настройке его для Active/Passive кластера сказано уже и так достаточно много, но информации по организации полноценного Active/Active кластера, используя этот модуль я нашел крайне мало. Постараюсь исправить эту ситуацию.


Для начала расскажу подробнее чем такой метод балансировки примечателен:


  • Отсутсвие внешнего балансировщика — На всех нодах в кластере настраивается один общий виртуальный IP-адрес. Все запросы отправляются на него. Ноды отвечают на запросы на этот адрес случайно и по договоренности между ссобой.
  • Высокая доступность — Если одна нода падает ее обязаности подхватывает другая.
  • Простота настройки — Настройка осуществляется всего в 3-5 команд.

Вводные данные


Давайте посмотрим на картинку в начале статьи, мы увидим следующие устройства:


  • Gateway — IP: 192.168.100.1
  • HostA — IP: 192.168.100.101
  • HostB — IP: 192.168.100.102
  • HostC — IP: 192.168.100.103

Клиенты будут обращаться на внешний адрес нашего шлюза, тот будет перенаправлять все запросы на виртуальный IP 192.168.100.100, который будет настроен на всех трех нодах нашего кластера.


Подготовка


Для начала нам нужно убедиться в том, что все наши ноды могут обращаться друг к другу по single hostname, для надежности лучше сразу добавить адреса нод в /etc/hosts:


192.168.100.101    hostA
192.168.100.102    hostB
192.168.100.103    hostC

Установим все необходимые пакеты:


yum install pcs pacemaker corosync #CentOS, RHEL
apt-get install pcs pacemaker corosync #Ubuntu, Debian

При установке pcs создает пользователя hacluster, давайте зададим ему пароль:


echo CHANGEME | passwd --stdin hacluster 

Дальше операции выполняются на одном узле.
Настраиваем аутентификацию:


pcs cluster auth HostA HostB HostC -u hacluster -p CHANGEME --force 

Создаём и запускаем кластер “Cluster” из трех узлов:


pcs cluster setup --force --name Cluster hostA hostB hostC
pcs cluster start --all

Смотрим результат:


pcs cluster status

Вывод
Cluster Status:
 Last updated: Thu Jan 19 12:11:49 2017
 Last change: Tue Jan 17 21:19:05 2017 by hacluster via crmd on hostA
 Stack: corosync
 Current DC: hostA (version 1.1.14-70404b0) - partition with quorum
 3 nodes and 0 resources configured
 Online: [ hostA hostB hostC ]

PCSD Status:
  hostA: Online
  hostB: Online
  hostC: Online

Некоторые шаги были позаимствованы из статьи Lelik13a, спасибо ему за это.


В нашем конкретном случае ни кворум ни stonith нашему кластеру не требуется, так что смело отключаем и то и другое:


pcs property set no-quorum-policy=ignore
pcs property set stonith-enabled=false

В дальнейшем, если у вас появятся ресурсы для которых это необходимо, вы можете обратиться к статье Silvar.


Пара слов о MAC-адресах


Прежде чем мы приступим, нам нужно понимать что на всех наших нодах будет настроен одинаковый IP и одинаковый mac-адрес, по запросу на который они будут поочередно давать ответы.


Проблема в том, что каждый коммутатор работает таким образом, что во время работы он составляет свою таблицу коммутации, в которой каждый mac-адрес связывается с определенным физическим портом. Таблица коммутации составляется автоматически, и служит для разгрузки сети от "ненужных" L2-пакетов.


Так вот, если mac-адрес есть в таблице коммутации, то пакеты будут отправляться только в один порт за которым и закреплен этот самый mac-адрес.


К сожалению, нам это не подходит и нам необходимо удостовериться в том, что бы все наши хосты в кластере одновременно "видели" все эти пакеты. В противном случае эта схема работать не будет.


Для начала нам нужно удостовериться в том, что используемый нами mac-адрес является multicast-адресом. То есть находится в диапазоне 01:00:5E:00:00:0001:00:5E:7F:FF:FF. Получив пакет для такого адреса наш коммутатор будет передавать его во все остальные порты, кроме порта источника. Кроме того, некоторые управляемые коммутаторы позволяют настроить и определить несколько портов для конткретного MAC-адреса.


Также вам вероятно придется отключить функцию Dynamic ARP Inspection, если она поддерживается вашим коммутатором, так как она может стать причиной блокировки arp-ответов от ваших хостов.


Настройка IPaddr-ресурса


Вот мы и добрались до самого интересного.


На данный момент существует две версии IPaddr с поддержкой клонирования:


  • IPaddr2 (ocf:heartbeat:IPaddr2) — Стандартный ресурс-агент для создания и работы виртуального IP-адреса. Как правило устанавливается вместе со стандартным пакетом resource-agents.


  • IPaddr3 (ocf:percona:IPaddr3) — Улучшенная версия IPaddr2 от Percona.
    В эту версию включены исправления ориентированные на работу именно в режиме clone.
    Требуется отдельная установка.

Для установки IPaadr3 выполните эти команды на каждом хосте:


curl --create-dirs -o /usr/lib/ocf/resource.d/percona/IPaddr3     https://raw.githubusercontent.com/percona/percona-pacemaker-agents/master/agents/IPaddr3
chmod u+x /usr/lib/ocf/resource.d/percona/IPaddr

Дальше операции выполняются на одном узле.


Создадим ресурс для нашего виртуального IP-адреса:


pcs resource create ClusterIP ocf:percona:IPaddr3     params ip="192.168.100.100" cidr_netmask="24" nic="eth0" clusterip_hash="sourceip-sourceport"     op monitor interval="10s"

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


  • sourceip — распределение только по IP-адресу источника, это гарантирует что все запросы от одного источника всегда будут попадать на один и тот же хост.
  • sourceip-sourceport — распределение по IP-адресу источника и исходящему порту. Каждое новое соединение будет попадать на новый хост. Оптимальный вариант.
  • sourceip-sourceport-destport — распределение по IP-адресу источника исходящему порту и порту назначения. Обеспечивает наилучшее распределение, актуально если у вас работает несколько сервисов на разных портах.

Для IPaddr2 обязательно нужно указать параметр mac=01:00:5E:XX:XX:XX с mac-адресом из multicast-диапазона. IPaddr3 устанавливает его автоматически.


Теперь склонируем наш ресурс:


pcs resource clone ClusterIP     meta clone-max=3 clone-node-max=3 globally-unique=true

Это действие создаст следующее правило в iptables:


Правило
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
  all  --  anywhere             192.168.100.100       CLUSTERIP hashmode=sourceip-sourceport clustermac=01:00:5E:21:E3:0B total_nodes=3 local_node=1 hash_init=0

Как вы можете заметить, здесь используется модуль CLUSTERIP.


Работает он следующим образом:


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


Подробнее об этом написанно в этой статье.


Давайте еще раз посмотрим на наш кластер:


pcs cluster status

Вывод
Cluster Status:
Cluster name: cluster
Last updated: Tue Jan 24 19:38:41 2017
Last change: Tue Jan 24 19:25:44 2017 by hacluster via crmd on hostA

 Stack: corosync
 Current DC: hostA (version 1.1.14-70404b0) - partition with quorum
 3 nodes and 0 resources configured
 Online: [ hostA hostB hostC ]

Full list of resources:

Clone Set: ClusterIP-clone [ClusterIP-test] (unique)
    ClusterIP:0   (ocf:percona:IPaddr3): Started hostA
    ClusterIP:1   (ocf:percona:IPaddr3): Started hostB
    ClusterIP:2   (ocf:percona:IPaddr3): Started hostC

PCSD Status:
  hostA: Online
  hostB: Online
  hostC: Online

IP-адреса успешно запустились. Пробуем обратиться к ним снаружи.
Если все работает как надо, то на этом настройку можно считать законченой.


Ссылки


Поделиться с друзьями
-->

Комментарии (10)


  1. facha
    25.01.2017 10:29
    +1

    Пожалуйста, расскажите, что произойдет, если одна из нод будет выключена. На ее запросы будет отвечать какая-то одна соседняя нода? Или все оставшиеся вместе? Как (и насколько быстро) кластер поймет, что одна из нод выключилась?


    1. kvaps
      25.01.2017 10:51

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


      Насколько быстро кластер поймет, что одна из нод выключилась?

      Это настраивается в параметре op monitor interval="10s" для вашего ресурса.


  1. rawsik
    25.01.2017 13:15

    Зачем для pacemaker назначать ту задачу, которая ему не свойственна?
    Балансировщик это HAProxy ( nginx) и стоит уже за vIP.

    Задача pacemaker именно в поддержке vIP.

    Отключение кворума при 3-ёх нодах — несколько странно. Т.к. обычно это практикуют при 2-ух и в целях экономии железа. Когда отключаете кворум, нужно чётко понимать зачем это и использовать stonith с fencing'ом. И помним о split brain и его последствиях.

    Если задача только vIP для трёх серверов, pacemaker + corosync это слишком тяжёлое решение имхо.


    1. kvaps
      25.01.2017 13:55

      Зачем для pacemaker назначать ту задачу, которая ему не свойственна?

      Если данная функция реализованна разработчиком, то почему вы считаете что она ему не свойствена?


      Балансировщик это HAProxy ( nginx) и стоит уже за vIP.

      Я не имею ничего против HAProxy, я просто рассказал еще об одном способе балансировки.
      Для кластеров в одном сегменте сети — он наиболее удобен и не требует установки отдельного балансировщика.


      Отключение кворума при 3-ёх нодах — несколько странно

      В данном конкретном случае задача была описать настройку именно clonned IPaddr.
      Для его нормальной работы — ни кворум ни stonich не сделают никакой погоды.
      Кроме того, в статье есть про это оговорка и ссылка на инструкцию по настройке.


      Если задача только vIP для трёх серверов, pacemaker + corosync это слишком тяжёлое решение имхо.

      Подразумевалось, что помимо vIP могут быть и другие ресурсы контролируемые pacemaker, для которых он собственно и настраивается.


      1. rawsik
        25.01.2017 16:41

        Если данная функция реализованна разработчиком, то почему вы считаете что она ему не свойствена?

        как бы сказать помягче, все эти RA это просто скрипты, в них можно засунуть всё что угодно, и управлять чем угодно. Но если в них это добавлено, это не значит что это наиболее оптимальная реализация.

        Подразумевалось, что помимо vIP могут быть и другие ресурсы контролируемые pacemaker, для которых он собственно и настраивается.

        безопасно без кворума и стониса можно использовать только полностью stateless ресурсы

        основной поинт, я за разные решения на pacemaker, если такая балансировка работает — то хорошо.
        но после продолжительного использования pacemaker и corosync, для себя сделал вывод — не стоит усложнять


  1. rino906
    25.01.2017 13:29
    +1

    Я правильно понимаю, что осталось настроить синхронизацию conntrack(если конечно conntrack-tools умеет синхронизацию мастер-мастер) и можно получить маршрутизатор с балансировкой нагрузки?


    1. rino906
      25.01.2017 13:35

      Либо использовать clusterip_hash = sourceip-sourceport-destport


      1. kvaps
        25.01.2017 14:10

        Идея интересная, я думаю, что это должно сработать.


        1. celebrate
          25.01.2017 23:47
          +1

          Вроде как есть такая возможность: http://conntrack-tools.netfilter.org/manual.html#sync-aa


  1. A1estro
    25.01.2017 15:15

    Не так давно приходилось делать то же самое, только с healthcheck'ом веб-сервера и одним IP-адресом на ноду(белые айпишники).