UMGUM.COM 

CARP ( Доступность узла через избыточность с помощью утилиты Ucarp. )

26 марта 2010  (обновлено 15 августа 2016)

Эта публикация отнесена в архив. Она неактуальна.

OS: Linux Debian Lenny/Squeeze.
Application: CARP, Bash, networking.

Итак, мы имеем функционирующие первичный (primary) и вторичный (secondary) серверы с полностью настроенными web-сервисами "зеркалируемые" от первичного ко вторичному по ряду конфигураций и основному массиву данных. Теперь займёмся обеспечением работы системы слежения за доступностью базовых сервисов и автоматического переключения на "живой" сервер.

Сделаем это по простому (как и все, что делалось ранее), так чтобы отключение упомянутого сервиса по минимуму повлияло на работу других сервисов. Слежение за доступностью узла обеспечение таковой реализуем с помощью протокола CARP (Common Address Redundancy Protocol - протокол избыточности общего адреса).

Основная задача протокола - дать возможность различным хостам в локальной сети использовать общий IP-адрес. CARP является широковещательным протоколом; он группирует несколько сетевых интерфейсов вместе под одним или более виртуальными адресами. Из них, один интерфейс - "мастер" и отвечает на все пакеты предназначенные для группы, другие интерфейсы действуют как горячее резервирование. CARP является свободной и безопасной альтернативой протоколам VRRP (Virtual Router Redundancy Protocol) и HSRP (Hot Standby Router Protocol).


Договоримся в этой инструкции о следующих именованиях:

ip_host_primary   - IP-адрес постоянного интерфейса первичного web-сервера;
ip_host_secondary - IP-адрес постоянного интерфейса вторичного web-сервера;
ip_virtual_access - IP-адрес виртуального интерфейса предназначенного для приёма запросов к web-сервису как таковому (этот IP-адрес будет инициироваться CARP по заданным далее правилам).

Устанавливаем утилиту "ucarp" реализующую для Linux протокол CARP:

# aptitude install ucarp

В ядрах Linux, начиная с версии 2.4, механизм CARP включён по умолчанию и нам нет необходимости его каким либо образом инициализировать. В других операционных системах или индивидуальных сборках возможно придётся проделать магические "пассы" для инициализации механизма - поисковые сервисы в помощь.

Первым делом ознакомим операционные системы серверов: первичный и вторичный - с новыми виртуальными сетевыми интерфейсами:

# cat /etc/network/interfaces

....
# The virtual network interface (CARP)
auto eth0:0
iface eth0:0 inet manual
....

Я предпочитаю не давать операционной системе возможности инициировать виртуальный интерфейс и просто объявляю о его наличии для дальнейшего использования с помощью скриптов, которые будут написаны следом. Кстати, вовсе не обязательно привязывать виртуальный интерфейс к "Ethernet"-интерфейсу; я везде стараюсь использовать агрегирование и вместо "eth0:0" в некоторых случаях работаю с "bond0:0".

В этом же конфигурационном файле "/etc/network/interfaces" первичного и вторичного серверов, в параметрах несущего сетевого интерфейса, размещаем команду запуска "ucarp", исполняемую при инициализации несущего интерфейса - несколько отличающуюся для каждого из серверов.

Инициализации CARP для первичного сервера:

# cat /etc/network/interfaces

....
# The primary network interface
auto eth0
iface eth0 inet static
  address ip_host_primary
....
  up ucarp --interface=$IFACE --srcip=ip_host_primary --vhid=1 --pass=mypassword --addr=ip_virtual_access --advbase=1 --daemonize --preempt --upscript=/usr/local/etc/network/eth0.0.up.sh --downscript=/usr/local/etc/network/eth0.0.down.sh
....

Инициализация CARP для вторичного сервера:

# cat /etc/network/interfaces

....
# The primary network interface
auto eth0
iface eth0 inet static
  address ip_host_secondary
....
  up ucarp --interface=$IFACE --srcip=ip_host_secondary --vhid=1 --pass=mypassword --addr=ip_virtual_access --advbase=50 --daemonize --upscript=/usr/local/etc/network/eth0.0.up.sh --downscript=/usr/local/etc/network/eth0.0.down.sh
....

Использованные выше ключи раскрываются следующим образом:

"--vhid"       - "Virtual host ID", идентификатор группы CARP. Целое число от 1 до 255;
"--pass"       - пароль для шифрования всех пакетов рассылаемых ucarp в пределах группы (SHA1);
"--interface"  - физический интерфейс принадлежащий группе (здесь "$IFACE" - переменная инициируемая в среде исполнения системой сетевой конфигурации, она несёт в себе имя сетевого интерфейса, отрабатываемого в данный момент);
"--srcip"      - IP интерфейса, на котором работает CARP, нужен бы для обеспечения доступа к серверу в любом режиме работы (не меняется в процессе смены статуса);
"--addr"       - IP виртуального интерфейса, общий для группы CARP, обеспечением доступности сервисов которого мы и занимаемся;
"--advbase"    - параметр указывающий на то, как часто рассылаются уведомления в группе (по умолчанию 1, допустимые значения от 1 до 255; выставили у вторичного сервера значение существенно превышающее значение первичного мы достигнем того, что при появлении первичного сервера IP группы будет передан ему);
"--advskew"    - необязательный параметр, указывает на то, насколько может изменяться величина advbase, на основе величин advbase и advskew происходит выбор мастера в группе: чем меньше advbase, который может использовать хост, тем выше у него приоритет (по умолчанию 0, допустимые значения от 0 до 254);
"--upscript"   - скрипт, исполняемый при получении узла роли мастера;
"--downscript" - скрипт, исполняемый при потери узлом роли мастера;
"--daemonize"  - указание ucarp запустится в режиме фоновой службы;
"--preempt"    - указание на то, что именно этот узел будет иметь роль мастера при прочих равных условиях (опция применяется только на одном, первичном сервере).

Теперь напишем скрипты реакции на получение и потерю статуса "master":

# mkdir -p /usr/local/etc/network
# touch /usr/local/etc/network/eth0.0.up.sh
# touch /usr/local/etc/network/eth0.0.down.sh
# chmod ug+x /usr/local/etc/network/eth0.0.up.sh /usr/local/etc/network/eth0.0.down.sh

Приведем скрипт реакции на получение статуса CARP "master" к следующему виду:

# cat /usr/local/etc/network/eth0.0.up.sh

#!/bin/bash

# Указываем имя виртуального интерфейса (CARP)
IFACE="eth0:0"
# Указываем IP-адрес и маску сети виртуального интерфейса (ip_virtual_access), предназначенный для обеспечения доступа к web-сервисам (CARP)
IFADDR="10.10.2.26"
IFMASK="255.255.255.0"

# Инициируем интерфейс (ip_virtual_access) с заданными параметрами
ifconfig ${IFACE} ${IFADDR} netmask ${IFMASK} up

# Ждём применения новых параметров
sleep 3

# Запускаем web-сервисы
/etc/init.d/apache2 start
/etc/init.d/nginx start
/etc/init.d/mysql start

exit 0

Приведем скрипт реакции web-сервисов на потерю статуса "master" к следующему виду:

# cat /usr/local/etc/network/eth0.0.down.sh

#!/bin/bash

# Указываем имя виртуального интерфейса (CARP)
IFACE="eth0:0"

# Останавливаем виртуальный интерфейс (ip_virtual_access), предназначенный для обеспечения доступа к web-сервисам
ifconfig ${IFACE} down

# Ждём применения новых параметров
sleep 3

# Останавливаем web-сервисы, незадействованные в работе вторичного сервера "горячего резерва"
/etc/init.d/apache2 stop
/etc/init.d/nginx stop
/etc/init.d/mysql stop

exit 0

Вышеописанные скрипты реакции на изменение статуса одинаковы для всех серверов.

Ограничиваем доступ к скриптам для непривилегированных пользователей:

# chown -R root:root /usr/local/etc/network
# chmod -R go-rwx /usr/local/etc/network

Вот и все, базовое конфигурирование завершено. Теперь, если мы отключим несущий сетевой интерфейс "eth0" на первичном сервере (хотя бы даже и вынув кабель из Ethernet разъёма), на вторичном инициируется интерфейс "eth0:0" (аналогичный тому, что до отключения работал на первичном сервере), запустятся необходимые web-сервисы (при том, что на первичном они будут автоматически остановлены) и для удалённого пользователя сервис будет недоступен не более пяти-десяти секунд. При последующем "включении" интерфейса "eth0" на первичном сервере произойдет обратное: на первичном сервере запустятся web-сервисы, а на вторичном они будут выключены, как и сетевой интерфейс "eth0:0".

В журнальном файле "/var/log/syslog" можно найти строки фиксирующие эти события подобные следующим:

....
ucarp[2872]: [WARNING] Switching to state: MASTER
ucarp[2872]: [WARNING] Spawning [/usr/local/etc/network/eth0.0.up.sh eth0 10.10.2.26]
....

Нужно понимать, что в нашей, простейшей, конфигурации вторичный сервер будет исполнять роль web-сервиса только на время отсутствия в сети первичного сервера. Как только первичный сервер станет доступным, вторичный потеряет роль основного и все данные, что были накоплены за время его замещения первичного, будут перезаписаны с первичного в процессе "зеркалирования". Если смена статуса произошла на время запланированной перезагрузки первичного сервера, минут на пять, то с потерей данных за этот период вполне можно смирится (мы не ставили себе задачу создать супер-сверх-надёжный сервис с ответственностью за сохранение каждого байта), а вот потеря данных за три-пять часов уже весьма неприятна. Да и сама по себе ситуация со сменой статусов серверов - ненормальна, о ней нужно информировать всех имеющих отношение для принятия соответствующих мер (например, для сохранения всей наработанной на вторичном сервере информации за время его функционирования в роли основного). Информировать будем простым и достаточно эффективным способом - электронным письмом. В конец скриптов включающих и выключающих виртуальные интерфейсы на вторичном сервере размещаем команду отправки сообщения на определённые почтовые ящики с уведомлением о произошедшем событии.

Корректировка скрипта инициализации виртуального интерфейса на вторичном сервере "/usr/local/etc/network/eth0.0.up.sh" (добавляем в конец скрипта):

....
echo -e "Content-Type: text/plain; charset="utf-8"\nSubject: Changing the status of the secondary web-server.\nThe secondary web-server has acquired the status of the master. Вторичный web-сервер приобрел статус основного." | sendmail -F`cat /etc/hostname` admin@example.net
....

Корректировка скрипта выключения виртуального интерфейса на вторичном сервере "/usr/local/etc/network/eth0.0.down.sh" (добавляем в конец скрипта):

....
echo -e "Content-Type: text/plain; charset="utf-8"\nSubject: Changing the status of the secondary web-server.\nThe secondary web-server lost its status as the master. Вторичный web-сервер утерял роль основного." | sendmail -F`cat /etc/hostname` admin@example.net
....

В использовании CARP есть важный нюанс. Работать эта схема будет только в пределах одной подсети, без прохода трафика через маршрутизатор между участниками группы CARP. Так же, необходимо обеспечить на коммутирующем группу устройстве возможность динамической смены таблицы ARP по широковещательному запросу ("gratuitous ARP"; от участников группы, меняющих свои статусы и получающих соответствующие адреса).

Напрашивается вывод: использовать CARP наиболее эффективно для организации отказоустойчивых групп из устройств буквально "стоящими в одной стойке" для обеспечения гарантии работоспособности сервисов в случае выхода из строя оборудования поддерживающего работу упомянутых сервисов.


Заметки и комментарии к публикации:


Оставьте свой комментарий ( выразите мнение относительно публикации, поделитесь дополнительными сведениями или укажите на ошибку )