Статьи

Кластеризация серверов Tomcat с высокой доступностью и аварийным резервом

В последнее время много говорят о высокой доступности и кластеризации. Большинство разработчиков не заботятся, и почему они должны? Эти функции должны быть прозрачны для архитектуры приложения и не должны беспокоить разработчиков этого приложения.
Но знания никогда не причиняют вреда, поэтому я очутился в мире балансировки нагрузки, пульса и виртуальных IP-адресов. И знаешь, что? В следующий раз, когда нам понадобится такая инфраструктура, я могу, по крайней мере, сесть с ребятами из отдела инфраструктуры и, по крайней мере, знать, о чем, черт возьми, они говорят.

Так что же такое кластерная инфраструктура высокой доступности (HACI, как я буду называть ее теперь)? По сути, это должна быть инфраструктура с нулевым временем простоя (или, по крайней мере, воспринимаемая конечным пользователем как таковая, что означает никогда не возвращать страницу браузера 404 по умолчанию), способная к горизонтальному масштабированию, когда в этом возникает необходимость, и без единой точки. неудачи. Это мечта автора SLA. Базовая настройка HACI выглядит следующим образом:

Пользователи вводят через виртуальный IP-адрес, назначенный одному из двух балансировщиков нагрузки. Активен только один из балансировщиков нагрузки (активный мастер, LB1), другой присутствует в случае сбоя LB1 ((LB2, пассивный подчиненный). Два балансировщика нагрузки являются избыточными, т. Е. Имеют точно такую ​​же конфигурацию Балансировщики нагрузки перенаправляют весь трафик на реальные серверы. Это можно сделать с помощью циклического перебора или с помощью других средств, таких как липкие сеансы, когда один и тот же пользователь перенаправляется на один и тот же сервер каждый раз в течение сеанса. добавляется в любой момент и настраивается на балансировщиках нагрузки. В идеале конфигурация балансировщика нагрузки учитывает спецификацию оборудования и соответствующим образом балансирует нагрузку, но это выходит за рамки данной статьи (она включает в себя добавление весов).В случае сбоя всех серверов, сбалансированных с помощью балансировщика нагрузки, следует использовать резервный сервер для перенаправления всего трафика, поступающего от балансировщика нагрузки. Это может быть очень легкий сервер, целью которого является только предоставление пользователю разумной страницы с ошибкой (что-то вроде «Извините, мы выполняем техническое обслуживание»). Опять же, восприятие и немедленная обратная связь с пользователем является ключевым. Вы не хотите показывать пользователю простую страницу 404. Конечно, если сервер резервного копирования тоже выходит из строя, у вас проблемы (естественно, к тому времени предупреждающие сигналы должны были срабатывать на каждом уровне иерархии).Опять же, восприятие и немедленная обратная связь с пользователем является ключевым. Вы не хотите показывать пользователю простую страницу 404. Конечно, если сервер резервного копирования тоже выходит из строя, у вас проблемы (естественно, к тому времени предупреждающие сигналы должны были срабатывать на каждом уровне иерархии).Опять же, восприятие и немедленная обратная связь с пользователем является ключевым. Вы не хотите показывать пользователю простую страницу 404. Конечно, если сервер резервного копирования тоже выходит из строя, у вас проблемы (естественно, к тому времени предупреждающие сигналы должны были срабатывать на каждом уровне иерархии).

Так как же добиться этого с минимальными усилиями? Если вы хотите попробовать это, я предлагаю вам начать с установки виртуальной машины, такой как VirtualBox или VMWare. Таким образом, вы можете попробовать конфигурацию самостоятельно. В этом примере я буду балансировать нагрузку на 3 серверах Tomcat, используя липкие сеансы с использованием 2 балансировщиков нагрузки в активно-пассивном режиме. Я предполагаю, что все 3 сервера Tomcat имеют одинаковую конфигурацию оборудования, поэтому они могут обрабатывать одинаковое количество трафика каждый. Я также добавляю резервный сервер на случай, если все 3 сервера Tomcat выйдут из строя (обслуживая пользовательскую страницу 503, любезно информирующую пользователя о катастрофическом сбое, вместо того, чтобы сбросить стандартную бомбу 404).

Вы хотите начать с назначения IP-адресов серверам. Это сделает вашу жизнь немного проще. Нам понадобится 7 адресов: 3 для сервера Tomcat, 1 для сервера резервного копирования, 2 для балансировщиков нагрузки и 1 виртуальный IP-адрес, который будет распределен между балансировщиками нагрузки (и который будет точкой входа для ваших пользователей). Итак, наше задание будет:

Virtual IP   10.0.5.99     www.haci.local
LB1 10.0.5.100 lb1.haci.local #MASTER
LB2 10.0.5.101 lb2.haci.local #SLAVE
WEB1 10.0.5.102 web1.haci.local
WEB2 10.0.5.103 web2.haci.local
WEB3 10.0.5.104 web3.haci.local
BACKUP 10.0.5.105 backup.haci.local

Настроить веб-серверы легко. Вы просто устанавливаете Tomcat на каждом сервере и создаете простой файл JSP для обслуживания пользователей (внесите небольшое изменение, например, цвет фона, на каждом сервере, чтобы различать серверы). Я не буду рассказывать о репликации сеансов между серверами Tomcat, поскольку это зайдет слишком далеко. При желании вы можете настроить соответствующую репликацию и хранилище сеанса (например, с помощью многоадресной рассылки или JDBC).

Сервер резервного копирования, который я использую, является базовым сервером LAMP, который возвращает простую страницу 503 при каждом полученном запросе. Код ошибки 503 важен, потому что он отражает текущее состояние системы: в данный момент недоступен.

Для балансировщиков нагрузки я буду использовать 2 приложения: HAProxy и keepalived. HAProxy будет обрабатывать балансировку нагрузки, в то время как keepalived будет обрабатывать аварийное переключение между двумя балансировщиками нагрузки.

Во-первых, мы собираемся настроить HAProxy для LB1 и LB2. Установить HAProxy довольно просто в системе Ubuntu. Просто выполните sudo apt-get install haproxy, и все готово. После установки сделайте резервную копию текущей конфигурации HAProxy и начните редактирование.

 

cp /etc/haproxy.cfg /etc/haproxy.cfg_orig
cat /dev/null > /etc/haproxy.cfg
vi /etc/haproxy.cfg

 

Содержимое конфига, отражающее нашу настройку, должно выглядеть примерно так (тот же конфиг на LB1 и LB2):

 

global
log 127.0.0.1 local0
log 127.0.0.1 local1 notice
#log loghost local0 info
maxconn 4096
#debug
#quiet
user haproxy
group haproxy

defaults
log global
mode http
option httplog
option dontlognull
retries 3
redispatch
maxconn 2000
contimeout 5000
clitimeout 50000
srvtimeout 50000

frontend http-in
bind 10.0.5.99:80
default_backend servers

backend servers
mode http
stats enable
stats auth someuser:somepassword
balance roundrobin
cookie JSESSIONID prefix
option httpclose
option forwardfor
option httpchk HEAD /check.txt HTTP/1.0
server web1 10.0.5.102:80 cookie haci_web1 check
server web2 10.0.5.103:80 cookie haci_web2 check
server web3 10.0.5.104:80 cookie haci_web3 check
server webbackup 10.0.5.105:80 backup

 

После этого включите HAProxy на LB1 и LB2, отредактировав / etc / defaults / haproxy

 

# Set ENABLED to 1 if you want the init script to start haproxy.
ENABLED=1
# Add extra flags here.
#EXTRAOPTS="-de -m 16"

 

Пока что для конфигурации HAProxy. Мы пока не можем запустить его, поскольку LB1 и LB2 еще не прослушивают виртуальный IP-адрес.

Далее мы настроим аварийное переключение балансировщиков нагрузки с помощью keepalived. Установить его на Ubuntu так же просто, как и для HAProxy: sudo apt-get install keepalived. Но его конфигурация немного отличается на обоих балансировщиках нагрузки. Во-первых, нам нужно настроить оба сервера, чтобы иметь возможность прослушивать общий IP-адрес. Добавьте следующую строку в /etc/sysctl.conf:

 

net.ipv4.ip_nonlocal_bind=1

 

И беги

 

sysctl -p

 

Теперь мы настраиваем keepalived таким образом, чтобы LB1 был настроен в качестве основного балансировщика нагрузки и связывался с общим IP-адресом, в то время как LB2 находится в режиме ожидания и готов к работе, когда LB1 выходит из строя.

Конфигурация для LB1 выглядит следующим образом (edit /etc/keepalived/keepalived.conf):

 

vrrp_script chk_haproxy {           # Requires keepalived-1.1.13
script "killall -0 haproxy" # cheaper than pidof
interval 2 # check every 2 seconds
weight 2 # add 2 points of prio if OK
}

vrrp_instance VI_1 {
interface eth0
state MASTER
virtual_router_id 51
priority 101 # 101 on master, 100 on backup
virtual_ipaddress {
10.0.5.99
}
track_script {
chk_haproxy
}
}

 

Запустите keepalived и проверьте, прослушивает ли он виртуальный IP-адрес.

 

/etc/init.d/keepalived start
ip addr sh eth0

 

Он должен вернуть что-то вроде этого, указывая, что он прослушивает виртуальный IP-адрес

 

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 10.0.5.100/24 brd 10.0.5.255 scope global eth0
inet 10.0.5.99/32 scope global eth0
inet6 fe80::20c:29ff:fea5:5b93/64 scope link
valid_lft forever preferred_lft forever

 

Далее настраиваем LB2. Конфигурация практически одинакова, исключение составляет приоритет.

 

vrrp_script chk_haproxy {           # Requires keepalived-1.1.13
script "killall -0 haproxy" # cheaper than pidof
interval 2 # check every 2 seconds
weight 2 # add 2 points of prio if OK
}

vrrp_instance VI_1 {
interface eth0
state MASTER
virtual_router_id 51
priority 100 # 101 on master, 100 on backup
virtual_ipaddress {
10.0.5.99
}
track_script {
chk_haproxy
}
}

 

Запустите keepalived и проверьте сетевой интерфейс.

 

/etc/init.d/keepalived start
ip addr sh eth0

 

Он должен вернуть что-то вроде этого, указывая, что он не слушает виртуальный IP-адрес

 

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 10.0.5.101/24 brd 10.0.5.255 scope global eth0
inet6 fe80::20c:29ff:fea5:5b93/64 scope link
valid_lft forever preferred_lft forever

 

Теперь запустите HAProxy на LB1 и LB2.

 

/etc/init.d/haproxy start

 

Теперь вы можете отправлять запросы на номер 10.0.5.99 (или www.haci.local), который переходит на LB1, который, в свою очередь, будет балансировать нагрузку на запрос к WEB1, WEB2 и WEB3. Вы можете проверить балансировку нагрузки, отключив WEB1 (или сервер, на котором вы сейчас находитесь). Вы также можете сделать резервную копию сервера, включив все основные веб-серверы (WEB1, WEB2 и WEB3). И вы можете проверить отказоустойчивость нагрузки, отключив LB1. В этот момент LB2 включается и действует как мастер, балансируя все запросы. Когда вы снова включите LB1, он снова возьмет на себя роль мастера. HAProxy позволяет очень легко добавлять дополнительные серверы, перезагружая конфигурацию, не прерывая существующие сеансы. См. Документацию HAProxy для получения дополнительной информации или о ServerFault. (Http://serverfault.com/questions/165883/is-there-a-way-to-add-more-backend-server-to-haproxy-without-restarting-haproxy).

Дешево и эффективно. В то время как большинство корпоративных магазинов имеют аппаратные балансировщики нагрузки, которые также имеют эти и другие возможности, если у вас ограниченный бюджет или вам необходимо моделировать среду HACI для целей разработки (урок здесь: всегда симулируйте свою производственную среду при тестировании во время разработки), это может быть вменяемым вариантом.

В заключение я быстро объясню, как настроить сервер резервного копирования (простой сервер LAMP).

Создайте конфигурацию vhost на apache для www.haci.local или любого другого домена, указывающего на виртуальный IP-адрес, и настройте для него mod_rewrite:

 

RewriteEngine On
RewriteCond %{REQUEST_URI} !\.(css|gif|ico|jpg|js|png|swf|txt)$ [NC]
RewriteConf %{REQUEST_URI} !/503.php
RewriteRule .* /503.php [L]

 

Затем создайте файл 503.php и добавьте его вверху:

 

<?
header('HTTP/1.1 503');
header('Retry-After: 600');
?>
<html>
   <head><title>Unavailable</title></head>
   <body><p>Sorry, our servers are currently undergoing maintenance. Please check 
back with us in a while. Thank you for your patience.</p></body>
</html>

 

Вы можете украсить файл 503.php любым удобным вам способом. Вы даже можете использовать CSS, JavaScript и файлы изображений в файле php.

Теперь вернемся к моей IDE. У меня симптомы отмены.