Как устроена система SMSDirect

imageЗдравствуйте, хабражители!

Прочитав здесь о сравнении смс-сервисов для рассылок, мы решили рассказать вам о своем опыте построении подобной системы, которая верой и правдой служит нам в i-Free несколько лет и постоянно дорабатывается и совершенствуется. Надеемся, наш опыт будет вам полезен. В общем, тем, кому интересно, прошу под кат.

Что представляет собой наша система смс-рассылок? Основная задача системы SMSDirect — рассылка или отправка одиночных смс-сообщений.FrontendСервис представляет целый комплекс, вершиной айсберга которого является клиентская часть — сайт. Это точка входа в систему. Здесь есть личный кабинет (если ты хочешь загрузить базы рассылок вручную), а также набор методов API для создания рассылок и отправки сообщений.Для входа в систему клиент должен зарегистрироваться, а далее воспользоваться либо набором методов API, либо интерфейсом личного кабинета. Здесь реализуются следующие функции: загрузка и хранение пользовательских баз клиента (абонентских списков), а также создание и управление рассылками по этим спискам (или введёнными вручную номерам).

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

МаршрутизацияТак как объем данных у нас очень большой, нам нужно было решить, как осуществлять их обработку, деление и роутинг.После того, как мы разделили весь объем данных по нескольким внутренним подключениям, нам необходимо было добиться, чтобы каждое сообщение попало в необходимый шлюз. Соответственно, сообщения нужно определенным образом распределить по операторам. Такое распределение осуществляется в комплексе маршрутизации, который представляет собой систему приложений, которая занимается направлением миллионов сообщений по тому или иному шлюзу. Деление осуществляется на основе анализа атрибутов сообщения: принадлежность абонента к тому или иному оператору (не просто по коду, а по обслуживающему оператору), тексту сообщения, номеру отправителя, то есть свойства сообщения подвергаются полному анализу и обработке. Тем самым мы решаем задачу распределения сообщений: вроде бы рассылка одна, а сообщения распределяются и уходят разными путями в зависимости от своего оператора (номера абонента) и, например, номера отправителя. Роутингом трафика занимаются несколько выделенных серверов, представляющих часть инфраструктуры за пределами UI и бэкенда.

Внутренняя архитектура a956e31fab1580c077898ed496f0ce8f.jpg

В качестве веб-сервера, который обрабатывает обращения пользователя к UI и запросы API, выступает nginx.Это решение классическое, практически универсальное для подобных задач. Уровнем ниже, логично было бы развернуть веб-сервер Apache, но мы им решили не пользоваться, тем самым экономя ресурсы (весь функционал нам не нужен, а платить полную цену за необходимый нам 1% его возможностей нецелесообразно), а создали собственное ядро на Perl. Это то, что, собственно, и является основой системы.

Почему Perl? Короткий ответ: Так уж вышло Так исторически сложилось.Длинный ответ: Это холиварный вопрос, на самом деле нет никаких особых причин использовать тот или иной язык. Ключевым вопросом в большом и сложном проекте является грамотно спроектированная архитектура, а не язык. У нас есть специалисты, знающие и любящие разные языки, история сложилась так, что при разработке этого проекта наибольшее рвение проявили спецы, знающие Perl:) В то же время, раз уж в итоге выбран Perl, можно отметить плюсы этого языка, важнейшими из которых, несомненно, являются CPAN (читай — готовые решения для любой задачи) и зрелость языка (читай — гарантированная работоспособность кода при обновлениях (тут шпилька в адрес PHP)).

ЯдроЯдро взаимодействует с веб-сервером посредством интерфейса FastCGI, который, во-первых служит для пробрасывания пришедшего к нам запроса и принятого nginx в наше ядро, во-вторых FastCGI и связанные с ним модули представляют механизм запуска ядра в виде нескольких «демонов», то есть ядро запущено всегда.

Само ядро разбито на несколько отдельных «демонов», каждый из которых отвечает за свою часть процессов. Самые основные из них — это сайт с личным кабинетом, набор API, функционал, отвечающий за загрузку файлов от пользователя (абонентские базы), также в ядре предусмотрена сервисная часть, не взаимодействующая, с внешними данными и ориентированная исключительно на внутренние (служебные) процессы. Сама по себе эта часть делится на несколько низкоуровневых функций. Например, когда пользователь загрузил базу абонентов, сначала система видит ее как просто некий файл с данными, не пригодными для работы. После загрузки файла происходит его обработка — проверяются номера абонентов на корректность длины и префиксы, отбрасываются пустые и слишком короткие номера, то есть, «сырой» файл превращается в некоторую стандартную внутреннюю структуру, содержащую номера абонентов, ID, идентификатор региона и некоторые другие служебные параметры.

База данныхЗагружаемые пользователем базы сохраняются на диск и лежат в файловой системе, но после того, как по ним пробежались наши сервисные скрипты, из них извлекается необходимая описывающая информация, которая сохраняется в базу данных. Эта информация структурирована, в ней можно делать запросы с фильтрами по каждому атрибуту.При обработке баз и выделении неких необходимых сущностей из них, либо при обработке полученной статистки, сортировка занимает колоссальный объем. Обычные сортировщики являются малопригодными для такого объёма и сложности сортировок, поэтому для этого мы используем MSORT.

Файловая системаПоскольку пользователь загружает нам большие по объему абонентские листы, их нужно где-то хранить, плюс каждая рассылка генерит огромное количество собственных служебных данных: блок сформированных сообщений по рассылке, статусы, полученные на данные блоки, а также итоговый файл для экспорта. Промежуточные файлы удаляются после того, как рассылка завершается. Например, рассылка на 10 млн. сообщений вызывает по каждому из них по 3–5 сигналов, а это уже 30–50 млн.записей в файл. В общем, у нас генерируются миллиарды записей, которые мы не должны потерять, потому что в любой момент клиенту может понадобиться разобраться в деталях. Для этого к нашему ядру подключено отдельное файловое хранилище.В некоторых случаях возникает острая необходимость найти какую-то конкретную запись в том или ином файле, будь это база номеров или некая другая статистика. Читать его перебором от начала до конца долго и затратно, поэтому в ряде процессов мы используем многими забытое средство — Berkeley DB (BDB). Это своеобразных хэш на диске, который содержит в себе некий идентификатор, который говорит о смещении в файле, с которого необходимо считывать необходимые сведения.

Маршрутизация и доставка информации до операторовЯдро взаимодействует с внутренней системой маршрутизации, которая рассылает смски операторам. Эта часть была разработана i-Free и поддерживается силами инфраструктуры компании.Мы подключены к операторам, и передаём сообщения (смс-сообщения) с помощью нативных средств. Как правило, это SMPP, который выделяет оператор своим поставщикам.

© Habrahabr.ru