В этой статье описывается процесс настройки отказоустойчивого двухузлового балансировщика нагрузки с активной/пассивной конфигурацией, поддержкой сессий и механизма Failover на базе Perlbal/Heartbeat под управлением Debian. Балансировщик работает между конечным пользователем и двумя backend-серверами, которые отдают некий контент. (В нашем примере это два сервера с установленным Apache). Балансировщик не только проксирует запросы к бэкэнду, он еще и проверяет состояние бэкэнда и, в случае отказа, перенаправляет запросы к другому серверу (failover). Вдобавок, ведется постоянный мониторинг бэкэнд-серверов при помощи Heartbeat и, если master-сервер “лежит”, то slave автоматически становится мастером. Ваши пользователи не заметят сбоев в работе сервиса. Perlbal поддерживает механизм сессий, так что вы можете использовать ПО, завязанное на них (например форумы, онлайн-магазины etc)
Наша конфигурация
Мы используем следующую конфигурацию:
- Узел балансировки 1: lb1.example.com, IP адрес: 192.168.0.100
- Узел балансировки 2: lb3.example.com, IP адрес: 192.168.0.101
- Web-сервер 1: http1.example.com, IP адрес: 192.168.0.102
- Web-сервер 2: http3.example.com, IP адрес: 192.168.0.103
- Также нам понадобится виртуальный IP, который будет объединять узлы балансировки: 192.168.0.99
Вот схематичное изображение нашего кусочка сети:
shared IP=192.168.0.99 192.168.0.100 192.168.0.101 192.168.0.102 192.168.0.103 -------+------------+--------------+-----------+---------- | | | | +--+--+ +--+--+ +----+----+ +----+----+ | lb1 | | lb2 | | http1 | | http2 | +-----+ +-----+ +---------+ +---------+ Perlbal Perlbal 2 web servers (Apache) heartbeat heartbeat
Общий (виртуальный) IP-адрес не является проблемой, если вы сами являетесь администратором своей сети и можете самостоятельно выделять IP-адреса. Если же вы используете публичные адреса, то вам придется найти хостера, который даст вам два сервера (узлы балансировки) в одной подсети. Для общего IP вы можете использовать свободный адрес из той же подсети.
http1
и http2
– это “стандартные” сервера с Debian Etch и установленным Apache. (Конфигурация по умолчанию расположена в /etc/apache2/sites-available/default
. Будьте внимательны, если вы используете другие пути, не забывайте делать на это поправку)
Подготовка бэкэнда
Мы сконфигурируем Perlbal как прозрачный прокси. Т.е. он будет транслировать запросы к бэкэнд-серверам, сохраняя оригинальный адрес клиента в заголовке X-Forwarded-For
Конечно же, мы хотим видеть в логах оригинальные адреса, а не IP наших балансировочных узлов. Поэтому немного поправим конфигурацию логов Apache. Отредактируем файл /etc/apache2/apache2.conf
http1/http2:
[...] #LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined [...]
Затем перезапустим Apache
/etc/init.d/apache2 restart
И на этом настройка бэкэндов закончена. Перейдем к балансировочным узлам.
Установка Perlbal
На момент написания статьи, perlbal не был доступен в репозиториях Debian, поэтому выполним его установку вручную.
Сначала установим необходимые зависимости:
lb1/lb2:
apt-get install build-essential unzip lynx ncftp perl
Затем запустим оболочку Perl
perl -MCPAN -e shell
И выполним в ней три команды
force install HTTP::Date
install IO::AIO
force install Perlbal
Perlbal установлен. Нажмите q
для выхода из оболочки Perl
Настройка узлов балансировки
Конфигурационный файл Perlbal находится в /etc/perlbal/perlbal.conf
, но его еще надо создать :) Создаем директорию и файл, и помещаем туда следующие строки:
CREATE POOL webfarm POOL webfarm ADD 192.168.0.102:80 POOL webfarm ADD 192.168.0.103:80 CREATE SERVICE balancer SET listen = 192.168.0.99:80 SET role = reverse_proxy SET pool = webfarm SET persist_client = on SET persist_backend = on SET verify_backend = on ENABLE balancer
Вероятно, вы захотите узнать больше об опциях конфигурации Perlbal. Лучший способ это сделать – скачать последнюю версию с conf/
и doc/
. Там вы найдете описание параметров и различные примеры конфигурации.
Настройка Heartbeat
Мы настроили Perlbal на прослушивание нашего виртуального IP 192.168.0.99
, но кто-то должен “сообщить” узлам балансировки, что они также должны слушать этот IP. Это сделает Heartbeat. Установим его:
lb1/lb2:
apt-get install heartbeat
Для того, чтобы разрешить Perlbal слушать IP, мы должны добавить в /etc/sysctl.conf
следующую строчку:
[...] net.ipv4.ip_nonlocal_bind=1
И выполнить команду
sysctl -p
Теперь создадим три конфигурационных файла для Heartbeat: /etc/ha.d/authkeys
, /etc/ha.d/ha.cf
, и /etc/ha.d/haresources
./etc/ha.d/authkeys
и /etc/ha.d/haresources
должны быть одинаковыми на lb1
и lb2
, а /etc/ha.d/ha.cf
отличается всего одной строчкой!
vi /etc/ha.d/authkeys
auth 3 3 md5 somerandomstring
somerandomstring – это пароль, который используется heartbeat на lb1
и lb2
для взаимной аутентификации. Задайте ваш собственный пароль. Вы можете использовать три различных механизма шифрования, в данном примере используется md5
/etc/ha.d/authkeys
должен быть доступен для чтения только пользователю root
lb1/lb2:
chmod 600 /etc/ha.d/authkeys
lb1:
vi /etc/ha.d/ha.cf
# # keepalive: how many seconds between heartbeats # keepalive 2 # # deadtime: seconds-to-declare-host-dead # deadtime 10 # # What UDP port to use for udp or ppp-udp communication? # udpport 694 bcast eth0 mcast eth0 225.0.0.1 694 1 0 ucast eth0 192.168.0.101 # What interfaces to heartbeat over? udp eth0 # # Facility to use for syslog()/logger (alternative to log/debugfile) # logfacility local0 # # Tell what machines are in the cluster # node nodename ... -- must match uname -n node lb1.example.com node lb2.example.com
ВАЖНО: В качестве имен узлов (nodenames) используется вывод команды
uname -n
на обоих узлах балансировки.
Опции udpport
, bcast
, mcast
, и ucast
определяют способы коммуникации между узлами и задают параметры определения состояния узла. Вы можете оставить значения udpport
, bcast
и mcast
такими же, как в примере, но опция ucast
очень важна. В ней задается адрес второго узла балансировщика. В нашем примере это 192.168.0.101 (lb2.example.com)
На lb2
все точно также, за исключением опции ucast
, значением для которой должен выступать адрес lb1
lb2:
vi /etc/ha.d/ha.cf
# # keepalive: how many seconds between heartbeats # keepalive 2 # # deadtime: seconds-to-declare-host-dead # deadtime 10 # # What UDP port to use for udp or ppp-udp communication? # udpport 694 bcast eth0 mcast eth0 225.0.0.1 694 1 0 ucast eth0 192.168.0.100 # What interfaces to heartbeat over? udp eth0 # # Facility to use for syslog()/logger (alternative to log/debugfile) # logfacility local0 # # Tell what machines are in the cluster # node nodename ... -- must match uname -n node lb1.example.com node lb2.example.com
lb1/lb2:
vi /etc/ha.d/haresources
lb1.example.com 192.168.0.99
Первый параметр – это вывод
uname -n
Не имеет значения на каком узле вы создадите этот файл. Он указывает на виртуальный IP 192.168.0.99
Теперь запустим Heartbeat на обоих узлах
/etc/init.d/heartbeat start
Затем выполняем
lb1:
ip addr sh eth0
Мы должны увидеть, что хост lb1
слушает наш виртуальный IP
lb1:~# ip addr sh eth0 2: eth0:mtu 1500 qdisc pfifo_fast qlen 1000 link/ether 00:0c:29:a5:5b:93 brd ff:ff:ff:ff:ff:ff inet 192.168.0.100/24 brd 192.168.0.255 scope global eth0 inet 192.168.0.99/24 brd 192.168.0.255 scope global secondary eth0:0 inet6 fe80::20c:29ff:fea5:5b93/64 scope link valid_lft forever preferred_lft forever lb1:~#
Это можно проверить, выполнив команду ifconfig
lb1:~# ifconfig eth0 Link encap:Ethernet HWaddr 00:0C:29:A5:5B:93 inet addr:192.168.0.100 Bcast:192.168.0.255 Mask:255.255.255.0 inet6 addr: fe80::20c:29ff:fea5:5b93/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:63983 errors:0 dropped:0 overruns:0 frame:0 TX packets:31480 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:92604963 (88.3 MiB) TX bytes:2689903 (2.5 MiB) Interrupt:177 Base address:0x1400 eth0:0 Link encap:Ethernet HWaddr 00:0C:29:A5:5B:93 inet addr:192.168.0.99 Bcast:192.168.0.255 Mask:255.255.255.0 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 Interrupt:177 Base address:0x1400 lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:16436 Metric:1 RX packets:56 errors:0 dropped:0 overruns:0 frame:0 TX packets:56 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:3888 (3.7 KiB) TX bytes:3888 (3.7 KiB) lb1:~#
lb2
– это пассивный балансировочный узел. Он не должен слушать виртуальный IP, пока lb1
“жив”. Проверим это:
lb2:
ip addr sh eth0
Вывод должен быть примерно таким:
lb2:~# ip addr sh eth0 2: eth0:mtu 1500 qdisc pfifo_fast qlen 1000 link/ether 00:0c:29:e0:78:92 brd ff:ff:ff:ff:ff:ff inet 192.168.0.101/24 brd 192.168.0.255 scope global eth0 inet6 fe80::20c:29ff:fee0:7892/64 scope link valid_lft forever preferred_lft forever lb2:~#
ifconfig
не должен показать виртуальный IP
eth0 Link encap:Ethernet HWaddr 00:0C:29:E0:78:92 inet addr:192.168.0.101 Bcast:192.168.0.255 Mask:255.255.255.0 inet6 addr: fe80::20c:29ff:fee0:7892/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:75127 errors:0 dropped:0 overruns:0 frame:0 TX packets:42144 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:109669197 (104.5 MiB) TX bytes:3393369 (3.2 MiB) Interrupt:169 Base address:0x1400 lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:16436 Metric:1 RX packets:56 errors:0 dropped:0 overruns:0 frame:0 TX packets:56 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:3888 (3.7 KiB) TX bytes:3888 (3.7 KiB) lb2:~#
Запускаем Perlbal
lb1/lb2:
perlbal –daemon
Конечно же, нам не хочется каждый раз запускать демон руками. Поэтому пропишем его автоматический запуск в /etc/rc.local
#!/bin/sh -e # # rc.local # # This script is executed at the end of each multiuser runlevel. # Make sure that the script will "exit 0" on success or any other # value on error. # # In order to enable or disable this script just change the execution # bits. # # By default this script does nothing. /usr/local/bin/perlbal --daemon exit 0
Для остановки демона выполните команду
killall perlbal
Тестируем
Наш балансировочный узел настроен, запущен и готов к работе.
Вы можете выполнять HTTP-запросы к виртуальному IP 192.168.0.99
(или к тому адресу или доменному имени, с которым работаете вы) и в ответ будете получать контент с бэкэнд-серверов.
Для проверки отказоустойчивости и механизма failover остановите один из бэкэнд-серверов. Все запросы автоматически будут транслироваться к оставшемуся. Попробуйте остановить master-узел балансировщика (lb1
), узел lb2
сразу возьмет на себя роль активного узла. вы можете проверить это, выполнив
lb2:
ip addr sh eth0
Теперь в этом выводе присутствует виртуальный адрес:
lb2:~# ip addr sh eth0 2: eth0:mtu 1500 qdisc pfifo_fast qlen 1000 link/ether 00:0c:29:e0:78:92 brd ff:ff:ff:ff:ff:ff inet 192.168.0.101/24 brd 192.168.0.255 scope global eth0 inet 192.168.0.99/24 brd 192.168.0.255 scope global secondary eth0:0 inet6 fe80::20c:29ff:fee0:7892/64 scope link valid_lft forever preferred_lft forever lb2:~#
Как только узел lb1
будет вновь запущен, он опять будет выполнять функции master-узла.
Поддержка виртуальных хостов в Perlbal
Perlbal поддерживает виртуальные хосты. Допустим, мы хотим чтобы все запросы на *.site.com
обслуживались узлами с адресами 192.168.0.102
и 192.168.0.103
, а запросы на *.example.com
узлами с адресами 192.168.0.104
и 192.168.0.105
. Вот как это будет выглядеть в конфиге /etc/perlbal/perlbal.conf
LOAD vhosts CREATE POOL webfarm1 POOL webfarm1 ADD 192.168.0.102:80 POOL webfarm1 ADD 192.168.0.103:80 CREATE SERVICE balancer1 SET role = reverse_proxy SET pool = webfarm1 SET persist_client = on SET persist_backend = on SET verify_backend = on ENABLE balancer1 CREATE POOL webfarm2 POOL webfarm2 ADD 192.168.0.104:80 POOL webfarm2 ADD 192.168.0.105:80 CREATE SERVICE balancer2 SET role = reverse_proxy SET pool = webfarm2 SET persist_client = on SET persist_backend = on SET verify_backend = on ENABLE balancer2 CREATE SERVICE vdemo SET listen = 192.168.0.99:80 SET role = selector SET plugins = vhosts SET persist_client = on VHOST *.site.com = balancer1 VHOST *.example.com = balancer2 ENABLE vdemo
Постовой
Самая лучшая мебель для ванной комнаты в интернет-магазине www.mebel-vanna.ru.