Два канала вместо одного: балансировка и автоматический переход на Linux без дорогого железа
Клиент дорос до двух провайдеров - ADSL и резерв. Настроили балансировку исходящего трафика и автопереход на живой канал при падении одного. Дёшево, на Linux.
балансировка между двумя интернет-каналами становится практичной на обычном железе
Когда у клиента был один интернет-канал, разговор про отказоустойчивость был простым: если упадёт - позвоним провайдеру. Когда появился второй - разговор усложнился. Потому что иметь два канала и нормально ими пользоваться - это не одно и то же.
Схема у клиента сложилась такая: основной ADSL от крупного провайдера, плюс резервный канал от другого, поменьше и подешевле. Резерв взяли именно на случай если основной падает - что, по статистике прошлого года, случалось раза три. Ненадолго, но неприятно.
Первое время резервный канал просто висел незадействованным. Технически - живой, оплачен, воткнут в роутер. Фактически - в ящике стола. Когда основной падал, кто-то шёл к роутеру и руками переключал маршрут по умолчанию. Это работало, но занимало минут десять, а иногда и больше, если нужного человека не было в офисе.
Что мы хотели получить
Задача сформулировалась из трёх частей:
- Автоматический переход. Если один канал умер - трафик уходит в живой, без вмешательства человека.
- Возврат на основной. Когда основной восстановился - переключаемся обратно, тоже автоматически.
- Нормальное использование обоих, пока оба живы. Не держать резервный канал мёртвым грузом.
Дорогих специализированных балансировщиков у клиента не было и покупать не планировалось. Бюджет на железо - ноль, потому что вопрос закрывался переконфигурацией того, что уже есть.
Linux как шлюз с двумя интерфейсами
Шлюз у клиента уже стоял на Linux - обычный Debian, поднятый год назад, когда мы связывали офисы через ШПД. На нём уже крутился NAT, файрвол, ничего экзотического. Два сетевых интерфейса, два провайдера, два шлюза по умолчанию - звучит просто, но у Linux тут есть нюанс.
Стандартная таблица маршрутизации не умеет держать два маршрута по умолчанию с разумным поведением. Если прописать два default gateway - ядро выберет один и будет его использовать, про второй забудет. Для балансировки нужен iproute2 с его таблицами политик маршрутизации.
Идея следующая. Создаём две дополнительные таблицы маршрутизации - по одной на каждого провайдера. В каждой таблице прописан свой шлюз. Дальше с помощью ip rule указываем: если пакет пришёл из подсети провайдера A - ответ отправить через A, если из B - через B. Это решает проблему асимметричной маршрутизации, когда ответные пакеты уходят не тем интерфейсом, через который пришёл запрос, и сессия рвётся.
Для исходящего трафика из локальной сети используем ip route с параметром nexthop - можно задать два шлюза с весами. Мы поставили соотношение примерно три к одному в пользу основного канала: большая часть трафика идёт по ADSL, часть - по резервному. Резерв не простаивает, нагрузка размазана.
Проверка живости каналов
Балансировка работает, пока оба канала живы. Когда один падает - ядро этого само по себе не замечает. Маршрут остаётся прописан, пакеты продолжают уходить в никуда.
Поэтому рядом написали простой скрипт на bash, который запускается через cron каждые две минуты. Скрипт пингует по одному надёжному адресу за каждым провайдером - не сам шлюз провайдера, а что-то дальше в интернете, потому что шлюз может отвечать, пока канал в мир уже лежит. Выбрали по паре DNS-серверов, которые стоят за разными магистралями и обычно доступны.
Логика простая:
- Оба живы - балансировка с весами, как обычно.
- Основной упал, резерв живой - весь трафик переключается на резерв, правило с nexthop убирается, остаётся один маршрут.
- Резерв упал, основной живой - симметрично.
- Оба упали - ничего не меняем, ждём следующего цикла.
При восстановлении основного канала скрипт возвращает балансировку. Логика определения «восстановился» чуть аккуратнее - требуем несколько успешных пингов подряд, чтобы не дёргаться из-за единичного отклика в момент, когда канал ещё нестабилен.
О переключениях скрипт пишет в syslog, а мы настроили алерт в Nagios - он следит за последней меткой в логе и орёт, если переключение не отменилось в разумное время. Так что дежурный знает о факте падения, даже если офис уже в интернете через резервный канал и сам не чувствует проблемы.
Что получилось на практике
Первое реальное отключение случилось через несколько дней после запуска - основной ADSL упал примерно на час, провайдер потом сослался на плановые работы, о которых никто не предупредил. Пользователи не заметили ничего: скрипт переключил трафик на резервный канал за следующие две минуты, потом вернул. В логах всё аккуратно записано.
Скорость резервного канала ниже, и это чувствуется на больших скачиваниях - но для рабочих задач, почты и 1С разницы никакой.
Один момент, который выяснился: балансировка по nexthop делит трафик на уровне соединений, а не пакетов, и это правильно. Но если пользователь видит свой внешний IP - он будет разным для разных соединений, пока оба канала активны. Для большинства сервисов это незаметно, но если что-то привязывает сессию к IP - нужно либо прибивать весь трафик к одному каналу для этого сервиса через отдельное правило, либо мириться. Для данного клиента вопрос пока не встал.
По деньгам вся работа уложилась в несколько часов настройки - никакого нового железа, только конфигурация уже работающего шлюза. Два оплаченных канала теперь используются оба, офис не замечает падения одного из них. Именно за такое обслуживание и платит смысл управляемой инфраструктуры - не за реакцию на аварию, а за то, что авария уже не доходит до пользователя.
- Два офиса на одном ШПД: VPN вместо выделенки и модемов · 22 июня 2004
- Nagios: алерты, а не графики · 21 февраля 2005