![](http://talkpad.ru/static/img/logo.png)
Прошел почти год после публикации первой вводной статьи о TalkPad. В процессе эксплуатации и развития сервиса мы столкнулись со многими технологическими проблемами, часть из которых успешно преодолели. Сегодня мы хотим рассказать вам о том, как устроена серверная сторона TalkPad.
Напомню что TalkPad — это сервис, который предоставляет возможность позвонить на городские и мобильные телефоны прямо из браузера, установив плагин.
Итак, как же все-таки может быть устроен бэкенд высоконагруженного сервиса телефонии?
TalkPad построен на нескольких протоколах передачи данных. Мы используем SIP (Session Initiation Protocol) и SDP (Session Description Protocol) для установления сессии между пользователями и передачи метаданных, а для передачи непосредственно голосовых данных используется RTP (Real-Time Transport Protocol). Есть и другие протоколы для задачи установления соединения (Jingle, H.323, …), но SIP в настоящее время наиболее популярен.
1. Определение местоположения пользователей
В проекте мы используем высокопроизводительный программный SIP-коммутатор OpenSIPS, который помимо прочего обсуживает базу регистраций.
Для того, чтобы сервер знал, куда именно отправлять входящие звонки, каждый клиент отправляет серверу SIP-сообщение REGISTER, в котором сообщает свой сетевой адрес и порт. Чтобы пользователь не смог принять чужие звонки в SIP-регистрации необходима аутентификация и авторизация.
База регистраций обслуживается в памяти каждого сервера OpenSIPS с периодическим сбрасыванием (по таймеру) состояния в локальный PostgreSQL (о том как синхронизируются данные в памяти чуть ниже).
2. А если пользователь за NAT-маршрутизатором?
Почти все пользователи находятся за домашними/офисными/публичными роутерами (NAT-маршрутизаторами). В этом случае клиент не знает свой внешний сетевой адрес. Для решения этой проблемы существует протокол STUN (Session Traversal Utilities for NAT). STUN-клиент пользователя просто посылает запрос STUN-серверу (один из модулей OpenSIPS), а сервер отвечает ему информацией с какого сетевого адреса пришел пакет. Комбинируя различные STUN тесты пользователь может определить свой тип NAT.
Тип NAT, который мы определили, записывается в SIP-сообщения REGISTER и INVITE. В общем случае голосовой трафик идет между клиентами напрямую в режиме P2P. Однако, в случае, если тип NAT одного из пользователей был определен как симметричный, мы не можем этого сделать. Для этого OpenSIPS переписывает SIP сообщения таким образом, чтобы трафик между пользователями направился через RTPProxy-сервер (модуль OpenSIPS). По статистике TalkPad голосовой трафик через сервер проходит примерно для 28-30% пользователей.
3. SBC & Биллинг
Для того, чтобы пользователи TalkPad могли общаться не только между собой, но и звонить на городские и сотовые телефоны, мы сотрудничаем с операторами местной телефонной связи, общение с которыми происходит так же по протоколам SIP и RTP.
Чтобы корректно считать расход денежных средств пользователя, недостаточно просто проксировать SIP-сообщения пользователя оператору, так как в этом случае мы потеряем контроль за ходом звонка. Более подходящим решением является установление новой SIP-сессии с оператором, но таким образом, чтобы RTP трафик все еще направлялся напрямую между пользователем и оператором (или через сервер в случае, если необходимо выполнить перекодирование голоса).
Эти функции выполняет Session Border Controller (или B2BUA). В последних версиях OpenSIPS уже встроен модуль B2BUA. Кроме того, можно использовать B2BUA от Sippy Software. Однако для TalkPad мы остановились на использовании YATE — классической ATC компании Null Team, которая естественно сочетает в себе PBX и SBC функционал.
Одно из преимуществ YATE — это модуль Extmodule, который позволяет легко писать свои расширения на языке Python. В качестве движка для обработки асинхронных событий используется Twisted. Именно таким образом мы написали биллинг для TalkPad, который позволяет контролировать баланс пользователя с секундной точностью, причем даже в случае нескольких одновременных звонков. Это выгодно отличает наш биллинг от решений на базе протокола RADIUS.
4. Failover
TalkPad сочетает DNS-балансировку с CARP-отказоустойчивостью как изображено на картинке.
OpenSIPS может проксировать как в режиме stateless proxy, так и statefull proxy, в зависимости от используемых модулей. В нашем случае это statefull и поэтому нам нужно чтобы SIP-клиент (voip-плагин) общался с одним и темже OpenSIPS на протяжении сессии. Таким образом SIP-клиент должен отрезолвить DNS-запись 1 раз при старте и использовать до конца сессии.
![image](http://talkpad.ru/static/img/talkpad-schema.png)
Каждый OpenSIPS сервер реплицирует REGISTER на соседний сервер, дописывая себя в заголовок Path. Это нужно для того чтобы другой OpenSIPS знал с какого адреса нужно ответить клиенту в случае необходимости.
Что же произойдет в случае падения OpenSIPS-Server#1?
В этом случае интерфейс CARP1 на Server#2 автоматически перейдет в положение Master, и оба IP-адреса DNS-записи уже будут роутится на Server#2. Нагляднее всего это изображено на картинке:
![image](http://talkpad.ru/static/img/talkpad-schema-server1fail.png)
В случае падения одного из YATE серверов модуль loadbalancer в OpenSIPS эту ситуацию распознает и будет использовать только второй сервер, причем упавший будет периодически проверяться на предмет того, не ожил ли он.
Схема когда просто два пользователя отрезолвили два разных IP и говорят через браузер:
![image](http://talkpad.ru/static/img/talkpad-user1touser2.png)
5. Базы данных
В проекте мы используем PostgreSQL и приложения из open-source комплекта Skytools (от Skype): пулер соединений pgbouncer и менеджер репликации walmanager.
В настоящей статье мы кратко упомянули основные моменты эксплуатации TalkPad. В следующий раз мы расскажем об особенностях кросс-платформенной разработки VoIP-плагинов для браузеров.
Пользуясь случаем, хотим сообщить, что команда TalkPad активно ищет талантливых продавцов, партнеров, которые бы хотели встроить телефонию в свой сервис, и инвесторов.