VoIP без единой точки отказа: Asterisk 1.8 LTS + corosync/pacemaker
Клиент жалуется на падение IP-АТС в рабочее время. Строим failover-пару Asterisk 1.8 LTS на corosync/pacemaker с DRBD-репликой конфигурации. Переключение за 3 секунды.
FreeSWITCH 1.2 и Asterisk 1.8 LTS - конкуренция IP-АТС с enterprise-функциями в 2011 году
Клиент пришёл с простой жалобой: «у нас падает телефония и это происходит всегда в самый неподходящий момент». Asterisk крутился на единственном сервере, без резерва, без мониторинга нормального, без плана восстановления. Когда сервер уходил в ребут после очередного обновления ядра, офис сидел без телефонов от 10 минут до получаса - пока кто-нибудь это замечал и пока инженер добирался до консоли.
Задача понятная: убрать единую точку отказа. Решение тоже в целом понятное - active/passive кластер с автоматическим переключением.
Asterisk или FreeSWITCH
Перед тем как лезть в детали реализации, немного поспорили о выборе платформы. FreeSWITCH 1.2 сейчас активно набирает аудиторию - архитектура у него другая, более модульная, на больших объёмах каналов он, по отзывам, ведёт себя лучше. Конфигурация в XML поначалу удивляет, но после привыкания выглядит логичнее диалплана Asterisk.
Тем не менее мы выбрали Asterisk 1.8 LTS по нескольким соображениям.
Первое - существующая база. Клиент уже работает на Asterisk три года. Диалплан есть, кастомные AGI-скрипты есть, телефонисты знакомы с интерфейсом. Миграция на FreeSWITCH - это отдельный проект с тестированием и обучением.
Второе - LTS-статус. Ветка 1.8 объявлена долгосрочной поддержкой, что для production-системы важно.
Третье - инструментарий кластеризации. Для Asterisk накоплена практика failover-схем с corosync/pacemaker, включая специфику обработки активных звонков при переключении. FreeSWITCH тоже можно кластеризовать, но у нас с ним меньше опыта в таком сценарии.
Схема кластера
Два физических сервера, один общий плавающий IP-адрес, DRBD для репликации данных между узлами. Corosync держит heartbeat, pacemaker управляет ресурсами.
┌─────────────────────────────┐
│ Плавающий IP (виртуал.) │
└────────────┬────────────────┘
│
┌────────────▼────────────────┐
│ Активный узел (master) │ <- asterisk, DRBD primary
└─────────────────────────────┘
│ DRBD sync
┌─────────────────────────────┐
│ Пассивный узел (standby) │ <- asterisk stopped, DRBD secondary
└─────────────────────────────┘
На DRBD-разделе хранятся /etc/asterisk/ с конфигурацией и /var/spool/asterisk/ с очередями и записями звонков. Каждое изменение конфига на мастере синхронно реплицируется на резервный узел. Pacemaker следит за сервисами: Asterisk, DRBD, плавающий IP.
Что живёт на DRBD
Выбор того, что класть на DRBD, потребовал некоторого обдумывания. Не всё подряд, а только то, что реально меняется и влияет на работу:
- Конфигурация (
/etc/asterisk/) - очевидно. Без этого весь смысл failover теряется. - Voicemail и записи звонков (
/var/spool/asterisk/voicemail/,/var/spool/asterisk/monitor/) - клиент специально попросил не терять записи. - Asterisk database (AstDB,
/var/lib/asterisk/astdb) - там живут состояния, follow-me настройки, parking slots.
Бинарники, логи и временные файлы на DRBD не кладём - нет смысла гонять по сети то, что воспроизводится из пакетов или не нужно после переключения.
Переключение: что происходит за 3 секунды
Heartbeat между узлами идёт по выделенной сетевой связке каждые 100 мс. При потере связи pacemaker ждёт несколько таймаутов, потом принимает решение о failover.
Последовательность действий pacemaker при переключении:
1. Останавливает ресурс Asterisk на мастере (или фиксирует что мастер недоступен). 2. Переключает DRBD на резервном узле в primary-режим. 3. Монтирует DRBD-раздел. 4. Поднимает плавающий IP на резервном узле. 5. Стартует Asterisk.
Всё это укладывается в 3-4 секунды при живом, но зависшем Asterisk, и в 8-10 секунд при полном отказе железа (pacemaker выжидает таймаут подтверждения что мастер точно мёртв - не хочет DRBD split-brain). SIP-клиенты с нормально выставленным registration expiry переregистрируются сами и большинство пользователей ничего не замечает - разве что короткая пауза в активном звонке.
Активные разговоры в момент переключения обрываются - тут уж ничего не поделаешь при active/passive схеме. Для непрерывности звонков нужна другая архитектура с разделяемым медиа-шлюзом, это уже другой масштаб задачи.
Нюансы, на которые потратили время
DRBD split-brain - самый неприятный сценарий, когда оба узла считают себя primary. Для телефонии это катастрофа: два одновременно работающих Asterisk с одним IP - звонки идут не туда, конфиги разъезжаются. Защита - явная политика split-brain в конфиге DRBD (after-sb-0pri, after-sb-1pri) с автоматическим дискардом меньшего узла. Плюс fencing через IPMI: pacemaker при сомнениях стреляет в мастер и убеждается что тот точно выключен.
Тайминги SIP registration. Телефоны Yealink и Grandstream у клиента по дефолту имели expiry 3600 секунд. После переключения IP они ждут час до следующей регистрации. Поправили на 60 секунд - после failover телефоны подхватываются в течение минуты.
Asterisk reload vs. restart при конфигурационных изменениях. При asterisk -rx "reload" на мастере DRBD честно реплицирует изменённые файлы на резервный. Но если инженер правит конфиг напрямую на резервном узле (по старой памяти), при следующей синхронизации изменения потеряются. Прописали в документации: конфиг правим только через мастер.
Мониторинг
Без мониторинга кластер - кот в мешке. Настроили Zabbix на проверку:
- Статус DRBD-ресурса (оба узла должны быть в нормальном состоянии синхронизации)
- Состояние кластерного сервиса через
crm_mon - Доступность Asterisk AMI на активном узле
- Лаг репликации DRBD
Про мониторинг в связке с логами писали раньше - подход к централизованному сбору событий здесь тоже применим, хотя Asterisk-специфичные события удобнее тащить через AMI напрямую.
Итог
Схема работает. За три недели после внедрения кластер уже один раз отработал в боевых условиях - плановая перезагрузка мастера после обновления ядра, Asterisk переехал на резервный узел пока мастер загружался, потом вернулся обратно. Офис не позвонил с жалобами.
Если у вас Asterisk на одном сервере и это хоть сколько-нибудь критичная инфраструктура - сопровождение инфраструктуры поможет оценить и выстроить нормальную схему отказоустойчивости.