Как мы смогли обзвонить 1,5 млн абонентов за несколько часов

Kate

Administrator
Команда форума
Сегодня поговорим о создании с нуля платформы, которая дает возможность обзвонить 1 500 000 абонентов всего за несколько часов. В свое время бизнес-отдел поставил такую задачу и нам нужно было ее решить в сжатые сроки. Все самое интересное о решении этой задачи - под катом.

Коротко - об особенностях работы платформы​

Сразу скажу, что мы не изобретали велосипед, создавая свою платформу. Когда появилась задача обзвона тысяч абонентов, мы пошли по пути горизонтального масштабирования.

Главная наша особенность - работа в real-time режиме. Поэтому многие проблемы, которые являются незначительными и не очень заметными в других компаниях, для нас смерти подобны. Простой пример - страничка стала загружаться не за 100 мс, как обычно, а за 200 мс. В обычной ситуации это мало кого волнует - да, проблема есть, но она не критична. Ее замечают и исправляют через несколько часов, а то и дней. А у нас даже в случае очень незначительного увеличения задержки сразу падает качество - вне зависимости от причины проблемы, будь то троттлинг сети или что-то еще.

Для решения подобных проблем мы использовали горизонтальное масштабирование - есть пулы, в них - сервера, которые отрабатывают основной поток данных. Серверов много, мы можем масштабировать производительность системы отрабатывая очень большое количество звонков. Кроме того, у нас две базы данных - одна с быстрыми запросами и относительно небольшим объемом хранимой информации и вторая - относительно "медленная", с большим объемом данных.

Как все начиналось​

Работали мы, недавние девопсы, вдвоем с коллегой. Точнее, начинали разработку вдвоем. Я занимался сборкой CMS, системой управления самой платформой, статистикой и отчетами. Все работы по системному администрированию, деплою и инсталляции выполняли сами. Потом команда увеличилась - взяли девопса, а потом начали набирать людей в команду. Сейчас на фронтенде работает 5-6 человек, на бекенде - 8 человек. Команду набрали примерно за два года.

После того, как платформа была готова, почти сразу запустили пилот на обзвон 10 тысяч клиентов. Запущен он был уже на второй день после готовности первой версии платформы. Тогда мы управляли голосовым потоком, используя FreeSwitch и сторонний MRCP-сервер.

Но почти сразу стало ясно, что так жить нельзя - при использовании стороннего MRCP-сервера бесконечно расширяться было сложно. Нужны были дополнительные лицензии, причем много. А их стоимость нельзя назвать низкой. Если использовать просто сервер - то все отлично, но для наших целей был необходим плагин к серверу. Плагин называется UMS Transcribe Plugin, а нужен он для распознавания речи. Все бы ничего, но стоит он $50 за канал. А когда нужно несколько тысяч каналов, как в нашем случае, то такой вариант не очень подходит.

Приняли решение написать собственный медиасервер, отказавшись от стороннего MRCP-сервера. Если интересуют подробности причин отказа, то об этом можно почитать в другой статье в нашем блоге.

Свою реализацию мы написали за несколько месяцев, разработав сервер с нуля. Недостатки стороннего MRCP-сервера мы превратили в достоинства собственного продукта, который получил:

  • Собственный NLU-алгоритм, способный обучаться на небольшом объеме данных.
  • Короткие паузы в диалогах.
  • Умную систему реагирования на прерывания разговора со стороны собеседника.
  • Возможность создания любого количества каналов.
  • Возможность кастомизации - систему можно подстраивать под нужды любого проекта.
Еще один огромный плюс в том, что в случае появления проблем, ошибок, мы быстро находим причину, поскольку сами все писали и прекрасно знаем архитектуру сервера. Когда использовали стороннее решение, было гораздо сложнее, поскольку не сразу можно было понять, на чьей стороне проблема - нашей или стороннего сервера. А если представить себе ситуацию, что завтра нужно выкатывать решение, а сегодня мы пытаемся решить проблему, то можно себе представить, насколько все это было непросто.

Масштабирование сервиса и основные проблемы​

После того, как была готова уже третья версия платформы, нам неожиданно быстро пришлось масштабироваться. Причина - срочная задача от бизнес-отдела обзвонить 1,5 миллиона абонентов за несколько часов. Мы быстро все масштабировали, но в ходе решения этой задачи возникло несколько проблем:

  • Запросы в базе подвисали на HAProxy, иногда даже на несколько секунд. Этого допускать было нельзя, поскольку обзвон ведется в режиме реального времени, абонент уже снял трубку, а обработка разговора не ведется.
  • Платформа была написана на Python, и из-за особенностей работы многопоточности в питоне возникали сбои в работе платформы. Мы переписали приложения с использованием multiprocessing, вместо threading. Почему именно Python? Мы его хорошо знали, а писать проект нужно было еще вчера, так что на изучение дополнительных технологий времени не было от слова совсем.
  • Сетевая связность. В процессе обзвона десятков тысяч абонентов сначала довольно часто падало качество аудиопотока. Эту причину решили модификацией архитектуры. Где-то объединили микросервисы, где-то, наоборот, разнесли, чтобы снизить нагрузку на сеть.
  • Нелинейная деградация системы. Речь о том, что при увеличении нагрузки на платформу ожидаешь, что задержки будут расти линейно - скажем, повышаться с 10 мс до 20, потом - до 30 и т.п. Но в нашем случае запросы могли выполняться с небольшой задержкой, продолжительностью в мс, а потом, буквально через мгновение - задержка увеличивалась до десятков минут, не секунд. И это при том, что мы выполняли обычное тестирование, затем - нагрузочное. И если на первых порах трафик можно было остановить, то к моменту готовности третьей версии платформы этого было уже нельзя сделать. В итоге проблему побороли, сейчас платформа работает весьма стабильно в соответствии с текущим объемом трафика.
В ходе разработки платформы мы использовали Kubernetes для автомасштабирования нод с медиа серверами под нагрузкой.

Что касается MRCP, то при его создании реализовали распознавание яндекса, гугла, плюс добавили свой ASR. Сейчас у нас еще свои intent-классификатор и другие компоненты. Живет и работает третья версия системы уже несколько месяцев.

Платформа отказоустойчивая, мы используем кластеризацию, компоненты системы разнесены как логически, так и физически. Яндекс разнесли по разным зонам доступности, в каждой из них - масштабирование. Мы проводили стресс-тесты и в их ходе выводили зоны доступности Яндекса из продакшена, но работоспособность системы при этом сохранялась.

В качестве вывода​

В ходе решения поставленной задачи мы вынесли для себя два главных вывода по работе с highload-системами нашего профиля.

Основной - разносить быстрые запросы и БД отдельно от статистики, отчетов и медленных БД. Делать это нужно сразу, а не когда-нибудь потом. Часто разработчики, даже опытные, не обращают особого внимания на потребление ресурсов. Система проходит тесты, нагрузочное тестирование, а потом начинаются проблемы. Решить все это можно, но нервов и ресурсов придется потратить порядочно.

Еще один - использовать горизонтальное масштабирование, а не изобретать велосипед. Этот метод проверен и работает, так что рекомендую использовать именно его.

 
Сверху