Привет, Хабр! Меня зовут Илья Волынкин, я CTO платформы МТС Exolve. Когда мы говорим про VoIP-телефонию, первая ассоциация — Asterisk. Это open-source ПО захватило рынок, и его аналоги не так популярны. На True Tech Day я рассказал про наш опыт с FreeSwitch — инструментом, решающим гораздо более масштабные задачи.
Благодаря ему мы смогли построить платформу, которая позволяет реализовывать сложные сценарии, добавлять разные модули (например, с AI под капотом), и собирать себе системы телефонии по принципу Lego. Под катом — рассказ про то, как сейчас усложнилась инфраструктура для звонков, какие есть варианты реализации VoIP и как это может развиться в будущем.

Зачем вообще нужен «управляемый телеком»?
Когда говорят о звонках через интернет, чаще всего вспоминают виртуальные АТС. Хотя на практике самый распространенный кейс — совсем другой. Сегодня почти все пользуются разного рода on-demand-сервисами: доставками, такси и так далее. Во всех этих случаях базовой АТС не хватает — нужны TelecomAPI-платформы.
Для больших и сложных систем требуется не просто инфраструктура для звонков, а полноценный инструмент, который позволяет быстро строить сложную логику, маршрутизировать соединения и интегрировать их с другими внутренними системами.
Кроме этого, бизнес хочет видеть, что происходит с коммуникациями: кто с кем общается, где узкие места. Ему нужны метрики, контроль, сценарии и — особенно — возможность внедрять цифровых ассистентов. Не просто «человека на линии», а автоматизацию с участием голосовых роботов. Я про это писал в «Анатомии виртуального сотрудника: от смысла до каналов»: сегодня люди общаются не только с людьми, но и с ботами, которые могут обмениваться информацией между собой.
Традиционно корпоративные АТС создаются на базе Asterisk. Это прекрасный продукт для небольшой и средней компании, но он не справится, когда у вас миллион звонков. Для масштабирования и настройки разных сценариев требуется обвязка, растет количество задействованных API — общая сложность системы возрастает, ей требуется мониторинг. И приходится искать аналоги.
На чем сейчас можно построить сложную инфраструктуру для управления звонками
Начинали мы, как и многие, с Asterisk. Семь лет назад, когда мы запустили телеком API, все работало вполне сносно. Проектов было немного, кейсы — без особых нагрузок, так как крупных клиентов еще не было.
Но постепенно количество звонков начало расти, а с ним — всплывать ограничения. На тот момент архитектура Asterisk, созданного на рубеже 2000-х, уже ощущалась устаревшей. У нее оказался вполне конкретный потолок: как только мы начали серьезно масштабироваться, резко выросло потребление ресурсов. Плюс всплыли задержки речи, а даже небольшие лаги в пару сотен миллисекунд сильно бьют по восприятию. Возникает эхо, отставание, ломается сам принцип живого общения. Особенно это критично в прикладных сценариях, вроде доставки или вызова такси.
В тот момент стало понятно: нужен другой фундамент. Начали копаться в том, что вообще существует на рынке. И оказалось — не так уж и много. Из open-source решений по сути всего два крупных игрока: Asterisk и FreeSwitch.
Можно вспомнить и корпоративных монстров — Cisco, Avaya, но в наших условиях они неактуальны. Еще есть небольшие решения на Go, Python, JavaScript, которые можно использовать для сборки простых звонилок, автоответчиков, тестовых стендов. Но это все — уровень вспомогательной логики, а не полноценной архитектуры для масштабного сервиса.
Кроме этого, вокруг классических SIP-решений сложилась своя инфраструктура. У Asterisk есть целая обвязка: Kamailio, OpenSIPS, различные RTP-прокси и балансировщики. Эти инструменты позволяют масштабировать сигнальный трафик, управлять медиа-потоками, развязывать логику маршрутизации.
Asterisk vs Freeswitch

Это два ключевых игрока на рынке. Один — старый и проверенный, второй — заметно моложе, экзотичнее, но архитектурно куда свежее. Мы стали смотреть именно в его сторону.
Основной критерий — модульность. Кейсы, с которыми мы работаем, уже давно вышли за рамки телефонии. Это не просто «позвонил — поговорил». Это голосовые ассистенты, конференц-связь, интеграция с ML-моделями, которые на лету трансформируют голос, переводят, распознают, синтезируют. Все это — тяжелые вычислительные блоки, активируемые по запросу.
Мы пробовали идти по пути «давайте воткнем все сразу в голосовое ядро». И, надо признать, это было даже интересно, но слишком затратно. Когда ты включаешь всю обвязку на каждый звонок — получается дорого и бессмысленно. 80% вызовов не требуют ничего, кроме обычной маршрутизации и простой обработки. А в real-time голосовых потоках нет возможности отложить выполнение на потом или поставить в очередь — там все должно происходить мгновенно.
И вот здесь FreeSwitch — это то, что нужно. Да, он написан на Lua, который мне совсем не заходит. Но FreeSwitch изначально строился с расчетом на highload, и это модульное решение с большим количеством модов — его можно по-разному расширять и собирать свои, достаточно интересные сборки.
Из минусов — никто не умеет с ним работать. Это сложный и довольно редкий инструмент. В отличие от Asterisk, к нему очень мало документации и примеров, поэтому нужно идти по граблям самостоятельно. Чем мы и начали заниматься.
Внедрение FreeSwitch

Важно понимать, что сейчас есть разные модификации FreeSwitch. Базовая сборка — это вполне работающее стандартное решение, которое можно чуть оптимизировать. Под наши задачи она не очень подходила, так как хотелось не просто заменить один монолит на другой, а обеспечить гибкость, масштабируемость и эффективное потребление ресурсов.
Мы начали искать альтернативы и нашли пару интересных вариантов Docker-образов, которые, опять же, слабо отличаются от стандартной сборки. В итоге сделали несколько своих кастомных сборок под разные модели использования: убрали лишние или вынесенные в обвязку функции. Так мы на четверть уменьшили нагрузку на процессор (самый дорогой ресурс) и увеличили RPS на 18%.
Упаковка FreeSwitch в Kubernetes

Готовую сборку нужно упаковать во что-то, позволяющее масштабировать, держать отказоустойчивость и нормально работать под нагрузкой. Kubernetes на этом этапе выглядел логичным выбором, хотя и не без подводных камней.
Голосовой трафик — особая история. Он работает в стандартной телекомовской схеме, где есть control plane и data plane: управляющий поток и медиа. Они живут на разных портах и с разной логикой. Чтобы засунуть их в Kubernetes, надо решить ряд проблем.
С Docker все было бы относительно просто, а вот с Kubernetes — нет. SIP-протокол предполагает динамическую маршрутизацию: «передавай поток на один порт, принимай с другого». Kubernetes такие истории не любит, поэтому нам пришлось убрать несколько слоев Kubernetes-обвязки, обеспечив прямое сопряжение и работу с внешними потоками.
Из интересных решений: MetalLB на уровне L2/BGP для балансировки трафика на внутренние контейнеры. Плюс — связка из двух контейнеров по схеме sidecar: один отвечает за регистрацию и управление, второй обрабатывает голос. Сделали также headless-сервис, чтобы обойти Kubernetes NAT и пробрасывать адреса напрямую.
Так появилась финальная high-level конструкция. На границе — SBC (Session Border Controller). Он принимает внешние запросы, передает их в FreeSwitch и обеспечивает сквозной mapping медиапотоков.
Архитектура получилась гибкой. Внутри FreeSwitch можно запускать сценарии под разные классы SIP-запросов — по сути, собирать кастомные связки под конкретные кейсы.
Итог:
горизонтальное масштабирование под нагрузку;
+30% по CPS;
и главное — отсутствие лишних элементов между SIP-клиента и FreeSwitch позволило встраивать любые обработчики медиа без переделки всей системы.
Kubernetes дал не только масштаб, но и надежность: можно спокойно строить кластеры с резервированием. Получилась устойчивая архитектура, которую удобно развивать дальше.
SDK для сложных сценариев
Одной только работающей системы мало — ей еще нужно управлять. Мы начинали с того, что внутри сначала было огромное количество низкоуровневых API. Платформа Exolve вообще позиционируется как телеком-API, поэтому для нас это была знакомая архитектура.
У этого подхода есть одна серьезная проблема: при большом количестве сценариев и взаимосвязей возникают сложности с эксплуатацией, поддержкой, регрессионным тестированием после изменения даже маленьких модулей.
В итоге мы внедрили другой подход: вместо инкапсуляции бизнес-логики в отдельных сервисных слоях мы вынесли ее в SDK, через который продуктовые сервисы уже дергают низкоуровневые API. Да, это кажется небезопасным, но это можно исправить с настроенных правил. Также важно понимать специфику клиентов, работающих с телеком API: это крупные компании с которыми идет взаимодействие на высоком уровне доверия. Им в первую очередь важна производительность, скорость работы, качество соединения и масштабируемость.
Наш SDK представляет собой модуль, через который можно реализовать практически любой кейс: собрать корпоративную АТС, настроить динамическую переадресацию на виртуальные номера, сделать голосового робота, соединить звонки в телеконференцию. Все это использует одни и те же базовые сборки FreeSwitch и взаимодействует между собой в рамках одного ядра.
Куда это все движется
Понятно, что финиша тут нет: как только что-то построил — уже пора переделывать. И уже видны новые направления работы, например, Edge-SIP. Сейчас наша платформа централизована. Есть дата-центр, в который стекаются все звонки, откуда они маршрутизируются дальше.
Но по факту коммуникации часто ведутся внутри одного региона, города, а то и здания. То есть звонок из соседнего офиса сначала уходит в Москву, а потом возвращается назад — привет, лишняя нагрузка на сеть. А теперь добавим в картинку AI — у нас появляется еще один жирный канал трафика, который тоже тащится туда-сюда. Дорого. Долго. Бессмысленно.
И вот тут появляется концепция Edge-SIP: перенос обработки как можно ближе к месту события, в идеале — прямо на базовую станцию. Звоните с мобильного телефона — включение ассистента, обработка голоса и распознавание речи происходят максимально близко, без переездов в дата-центр и обратно. Это не только разгружает магистраль, но и сильно сокращает задержки — особенно чувствительно, если вы не в пределах МКАДа, а где-нибудь во Владивостоке. Локальная обработка открывает двери к новым сценариям.
Второе важное направление — AI в аудиопотоках. Мы уже умеем подгружать ассистентов и AI-модули в архитектуру. Сейчас проверяем, какие из них действительно полезны для клиентов. Один из кейсов, который уже почти в проде — шумоподавление на лету, прямо в канале: чтобы во время разговора у абонента был чистый человеческий голос без фонового шума.
Еще мы экспериментируем с коррекцией речи. Есть модели, которые сглаживают дикцию, темп, интонации. В итоге с той стороны ты звучишь как топ-менеджер на TED, даже если на самом деле только что проснулся.
Более прикладная задача — автоматический перевод. Вы звоните китайскому партнеру и говорите по-русски, он слышит по-китайски в режиме реального времени.
И, наконец, самое для нас интересное — открытие всей этой конструкции конечным пользователям. Сейчас у нас имеется SDK, но есть идея пойти дальше и дать возможность клиентам самим собирать себе телефонию. Нажал пару кнопок, подключил нужный модуль — и все работает. Настроил свой голосовой сценарий без единой строчки кода. Телеком, который можно собирать как Lego. Вот туда и движемся.
Gansterito
Сертификат на средство связи есть?