Поиск по сайту

Ищем материалы…

Что хотите найти?

Ищем по текстам, задачам, решениям, результатам, тегам, технологиям и комментариям.

Введите хотя бы 2 символа

Нет соединения. Поиск продолжится, когда связь восстановится.

Пост

Как победить флаппинг в GSLB-баланисровке по причине зависшего ARP при миграции виртуальных IP в кластерах Keepalived

Проблема

«Зомби»-чеки в GSLB и устаревшие ARP-записи

В процессе эксплуатации и плановых переключений ролей (failover/switchover) столкнулся с регулярным рассинхроном разрешения имен изза некорректных результатов проверок здоровья на уровне глобальной балансировки:

  1. Зависание L2/ARP-записей в сетевом периметре:

    Штатно Keepalived при переходе в MASTER рассылает Gratuitous ARP (GARP), уведомляя коммутаторы об обновлении MAC-адреса для виртуальных IP. Однако в комплексной виртуализированной и сегментированной сетевой среде некоторые маршрутизаторы ядра и сетевые экраны периодически игнорировали или задерживали обновление своих ARP-таблиц.

  2. Ложные срабатывания health check в пулах GSLB:

    Поскольку ARP-записи для части виртуальных адресов не обновлялись вовремя, синтетические пробы GSLB продолжали лететь в сторону старого узла (или дропались). В результате GSLB считал сервис деградировавшим и выводил рабочий пул из балансировки, вызывая цепную реакцию и ложные алерты дежурных инженеров.

  3. Отсутствие валидации сетевого стека ядром:

    Keepalived переходит в статус MASTER декларативно. Если из-за гонки процессов или сбоя Netlink ядро Linux не успело вовремя назначить адреса на интерфейс или снять их на резервной ноде, возникало состояние Split-Brain — трафик на один и тот же IP пытались обрабатывать оба хоста.

В ручном режиме проблема временно устранялась «пробитием» L2-связности: требовалось отправить ICMP-пакет в сторону шлюза, явно указав конкретный виртуальный IP в качестве исходящего адреса (ping -I <VIP> <GATEWAY_IP>).

Решение

Автоматический аудит и принудительный прогрев L2 через Keepalived Notify

Чтобы автоматизировать ручные действия и гарантировать мгновенную сходимость сети, необходимо связать события смены VRRP-состояний с скриптом валидации через директиву notify.

Архитектура решения:

  1. Событийная модель Keepalived:

    В конфигурации каждого VRRP-инстанса добавлен хук notify /etc/keepalived/cluster_notify.sh root. Демон передает в скрипт тип объекта, имя группы и новый статус (MASTER, BACKUP, FAULT).

  2. Задержка на применение в ядре:

    В начале сценария выполняется контролируемая пауза (sleep 2), дающая ядру Linux время применить сетевые изменения через Netlink до старта проверок.

  3. Гарантия отсутствия коллизий (Split-Brain Prevention):

    Если узел переходит в BACKUP или FAULT, скрипт инспектирует адреса сетевого интерфейса и убеждается, что ни один VIP из пула группы не остался активным.

  4. Принудительное обновление ARP и сквозная валидация:

    При переходе в MASTER скрипт:

    • Проверяет фактическое присутствие каждого VIP на интерфейсе.

    • Выполняет форсированный пинг шлюза сегмента с привязкой к конкретному VIP-адресу (ping -n -I "$vip" -c 3 -W 2 "$GATEWAY"). Этот шаг гарантированно генерирует исходящий трафик с новым MAC/IP-соответствием, мгновенно актуализирует ARP-таблицы upstream-оборудования и проверяет сквозное прохождение пакетов.

  5. Централизованный аудит:

    Все этапы проверок пишутся в syslog с уникальным тегом vrrp-vip-audit, а итоговый код возврата скрипта сигнализирует мониторингу об успешности применения конфигурации.

Результат

  • Стабилизация пулов GSLB: Исчезли ложные исключения нод из балансировки при плановых технических работах или аварийных переключениях. Зонды GSLB сразу получают ответы от активных адресов без просадок по таймаутам.

  • Автоматическое обновление ARP: Отпала необходимость вручную вмешиваться в сеть и «пробивать» связность для зависших IP - скрипт гарантированно обновляет таблицы коммутации за первые секунды после смены роли.

  • Нулевой риск Split-Brain: Мы защищены от ситуаций, когда адрес одновременно активен на двух нодах из-за проблем с его деконфигурацией при переходе в резервный статус.

  • Прозрачная телеметрия: Процесс миграции VIP-адресов стал полностью прозрачным в журналах SIEM/логов: по каждому виртуальному адресу фиксируется как факт привязки к интерфейсу, так и реальная доступность сети.

Контекст

Представим ситуацию, когда в инфраструктуре отказоустойчивая балансировка сервисов построена на базе пар балансировщиков нагрузки под управлением Keepalived и HAProxy. Чтобы утилизировать ресурсы обеих нод одновременно, используется схема Active/Active: на каждом узле сконфигурированы две независимые VRRP-группы (vrrp_grp_alpha и vrrp_grp_bravo). В штатном режиме Нода-01 держит пул адресов группы Alpha, а Нода-02 — группы Bravo.

Распределение трафика между площадками и дата-центрами регулируется GSLB (Global Server Load Balancing), который непрерывно опрашивает сервисные VIP-адреса через Health Check пробы.

Схема скрипта валидации (cluster_notify.sh):

#!/usr/bin/env bash
# Keepalived notify hook: INSTANCE <group_name> <state> [priority]
set -u
PATH=/usr/sbin:/usr/bin:/sbin:/bin
IFACE="eth0"
GATEWAY="192.0.2.1"
LOGTAG="vrrp-vip-audit"

log() { logger -t "$LOGTAG" -- "$*"; printf '%s\n' "$*"; }

if [[ $# -lt 3 || $1 != INSTANCE ]]; then
    log "ERROR: expected INSTANCE <group> <state> [priority]"
    exit 2
fi

GROUP=$2
STATE=$3

case "$GROUP" in
    vrrp_grp_alpha)
        VIPS=(192.0.2.10 192.0.2.11 192.0.2.12 192.0.2.13 192.0.2.14)
        ;;
    vrrp_grp_bravo)
        VIPS=(192.0.2.20 192.0.2.21 192.0.2.22 192.0.2.23 192.0.2.24)
        ;;
    *)
        log "ERROR: unknown VRRP group: $GROUP"; exit 2
        ;;
esac

case "$STATE" in
    MASTER|BACKUP|FAULT|STOP) ;;
    *) log "ERROR: unknown state: $STATE"; exit 2 ;;
esac

# Ожидание применения адресов ядром
sleep 2

mapfile -t LOCAL_IPS < <(ip -o -4 addr show dev "$IFACE" | awk '{split($4,a,"/");print a[1]}')
has_ip() {
    local candidate=$1 ip
    for ip in "${LOCAL_IPS[@]}"; do
        [[ "$ip" == "$candidate" ]] && return 0
    done
    return 1
}

log "START host=$(hostname -s) group=$GROUP state=$STATE iface=$IFACE gateway=$GATEWAY"
errors=0

for vip in "${VIPS[@]}"; do
    if [[ "$STATE" == MASTER ]]; then
        # 1. Проверяем локальное наличие IP
        if ! has_ip "$vip"; then
            log "ERROR group=$GROUP vip=$vip: missing on $IFACE in MASTER"
            ((errors+=1))
            continue
        fi

        # 2. Форсируем обновление ARP через исходящий ping к шлюзу
        if ping -n -I "$vip" -c 3 -W 2 "$GATEWAY" >/dev/null 2>&1; then
            log "OK group=$GROUP vip=$vip: gateway $GATEWAY reachable"
        else
            log "ERROR group=$GROUP vip=$vip: gateway $GATEWAY unreachable"
            ((errors+=1))
        fi
    else
        # В BACKUP/FAULT адрес должен быть гарантированно снят
        if has_ip "$vip"; then
            log "ERROR group=$GROUP vip=$vip: unexpectedly present in $STATE"
            ((errors+=1))
        else
            log "OK group=$GROUP vip=$vip: absent in $STATE"
        fi
    fi
done

log "DONE host=$(hostname -s) group=$GROUP state=$STATE errors=$errors"
((errors == 0))

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

Опыт применения 0

Попробовали решение в своей задаче? Расскажите, что получилось.

Применил у себя
Пока нет комментариев

Станьте первым, кто прокомментирует эту запись

Комментировать