ADG Оставить заявку
Блог Интеграции 2 мин чтения

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 на одном сервере и это хоть сколько-нибудь критичная инфраструктура - сопровождение инфраструктуры поможет оценить и выстроить нормальную схему отказоустойчивости.

Контакт

Нужна такая же инженерная работа?

Опишите задачу и контекст. Ответим в течение рабочего дня, при необходимости подпишем NDA.