Ключевые слова:balance, bandwidth, perlbal, perl, heartbeat, linux, (найти похожие документы)
From: Андрей Синицын
Date: Mon, 23 Oct 2010 17:02:14 +0000 (UTC)
Subject: Построение отказоустойчивого балансировщика нагрузки на базе Perlbal/Heartbeat
Оригинал перевода: http://boombick.org/blog/posts/48
Оригинал на английском: http://howtoforge.org/setting-up-a-high-availability-load-balancer-with-perlbal-heartbeat-on-debian-etch
В этой статье описывается процесс настройки отказоустойчивого двухузлового балансировщика
нагрузки с активной/пассивной конфигурацией, поддержкой сессий и механизма 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. Лучший способ это
сделать - скачать последнюю версию с [4]http://code.google.com/p/perlbal/downloads/list,
распоковать архив и обратить внимание на поддиректории 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 отличается всего одной строчкой!
/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:
/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:
/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:
/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
Have a lot fun!