Импортозамещение в телекоме: система обработки больших данных, которая превосходит зарубежные продукты

Сегодня речь пойдет о mediation-системах — системах обработки больших данных класса OSS/BSS (Operations / Business Support System). Они получают данные из разнородных источников, обрабатывают в зависимости от требований и передают в нужном формате в другие системы-потребители. Чаще всего их применяют в телеком-сфере: они собирают информацию об абонентском трафике, который условно можно разделить на две группы: голосовой и передача данных (интернет), преобразуют, а затем отправляют в биллинговую систему для выставления счетов. Поэтому такие системы называют предбиллинговыми.

Но их возможности также применяют для автоматизации в логистике, сфере коммунальных услуг или финансов. И вообще везде, где нужно собирать большие объемы разнородных данных, а потом в преобразованном виде отправлять в другие системы. В этой статье поговорим именно о телекоме, а в будущих я расскажу и про стриминг-платформы, и про интернет вещей, и про другие сферы.

ecf411f19be8ed19e6e85511aa42dee0.png

Исторически сложилось, что бОльшую часть российского рынка mediation-систем занимает OpenView Internet Usage Manager от HP (HP IUM). Именно на нем работает большинство телеком-операторов и интернет провайдеров. 

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

HP IUM был разработан пару десятилетий назад и постепенно перестал соответствовать современным требованиям. Телеком-индустрия движется вперед: растут объемы и скорость передачи данных, меняются стандарты и протоколы, инфраструктура обрастает сервисами и становится все сложнее. А объемные монолитные системы предыдущего поколения не успевают за этими изменениями и мешают развитию бизнеса за счет множества ограничений:

  • Они заточены только под вертикальное масштабирование, а попытки масштабировать их в горизонталь упираются в пределы серверных мощностей

  • Обычно у таких систем единая база данных, приложения взаимодействуют с ней синхронно, запросы выполняются последовательно — это снижает скорость обработки данных

  • Весь монолит написан на одном языке, а значит невозможно написать отдельный модуль на другом языке, даже если это выгоднее и актуальнее. 

  • При сбое в любом модуле монолита вся система выходит из строя — в отличие от микросервисных продуктов, где модули меньше влияют на общую работоспособность

  • Да и в целом монолиты не отличаются гибкостью: добавление поддержки нового протокола или изменение логики обработки превращается в масштабные задачи и большие циклы разработки.

  • Еще одна проблема —  устаревший технологический стек и использование закрытых проприетарных компонентов, которые часто уже не поддерживаются и/или не развиваются вендором

  • Отсутствие RESTful API (его просто не существовало, когда эти системы разрабатывали) приводит к сложностями интеграции, мешает связывать разнородные системы и выстраивать качественный ИТ-ландшафт.

  • Вишенкой на торте — неудобный устаревший UI/UX. Во многих легаси-решениях web-интерфейс, если он вообще есть, остался на уровне web 1.0. Но чаще управление осуществляется с помощью десктопных приложений на каждом рабочем месте. Это усложняет поддержку, повышает издержки.

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

Конечно, искать недостатки в чужих решениях и строить концептуальные теории легко. Куда сложнее предложить целостное готовое решение.

Мы в STM Labs с 2011 года занимаемся разработкой, интеграцией и поддержкой mediation-систем и изучили телеком-сферу изнутри. Мы не понаслышке знаем обо всех достоинствах существующих mediation-решений и способах справиться с их недостатками. Поэтому мы создали Pi.One — отечественную платформу предбиллинга, превосходящую зарубежные аналоги.

Функционально Pi.One решает все задачи, присущие mediation-системам:   собирает, преобразует и отправляет данные — быстро, гибко и без потерь. А еще у Pi.One удобный интерфейс и понятная подробная документация. Все это позволяет оптимизировать ресурсы, стандартизировать бизнес-процессы  и сконцентрировать усилия на ключевых задачах бизнеса.

Pi.One внесен в Реестр Российского ПО и имеет сертификат соответствия от Минсвязи. Система успешно применяется в реальных проектах, например — обеспечивает надежность и точность передачи данных в составе mediation-платформы российского телеком-оператора из большой четверки.

На этом переходим к техническим деталям. 

Архитектура системы

a9c94199e07e6d81dfc8a1f65286e847.png

Микросервисная архитектура

Мониторинг, трассировка и логирование

  • Поддержка интеграции с современными системами мониторинга и логирования (Prometheus, Loki и др.) в ландшафте заказчика

Высокая доступность и катастрофоустойчивость

  • Гео-распределенный режим в состоянии Active-Warm Standby

  • Поддерживает масштабирования элементов архитектуры в горизонт для обеспечения высокой производительности и надежности при обработке

  • Сбой в работе одного микросервиса не приводит к сбоям в работе всей системы

Технологии для управления процессами обработки данных

Технологии с открытым исходным кодом

В современных решениях важно использовать проверенные в бою open source компоненты. Они активно развиваются и поддерживаются сообществом и крупными вендорами. 

Pi.One полностью независим от проприетарных решений сторонних вендоров. Используются только проверенные Open Source решения с большим комьюнити.

Поддержка протоколов и интерфейсов 

Из коробки Pi.One работает с протоколами и интерфейсами всех ведущих поставщиков телеком-оборудования: Diameter, HTTP/2, WebSocket, HTTP, TCP/IP, MQTT, FTP, SFTP, FTAM, TCP/IP, SNMP, SMTP, GTP, SCP, SOAP, Radius, Web-сервисы и др

Pi.One может взаимодействовать с брокерами сообщений — такими как Apache Kafka. Также поддерживается взаимодействие с NoSQL базами данных: Redis, CouchBase и др.

Если нужна поддержка других протоколов или дополнительные компоненты, их можно легко добавить благодаря модульной архитектуре решения.

Независимость от внешних форматов данных

Перед обработкой данные, полученные из внешних источников, декодируются во внутренний формат IDR (Internal Data Records), с которым работает вся дальнейшая бизнес-логика. По сути на этапе декодирования данные из внешних источников превращаются в объекты в том виде, в котором они они обрабатываются в блоках бизнес-логики. Для определения формата данных из внешних источников, внутреннего формата, в который эти данные надо преобразовать, а также для описания правил преобразования мы используем Pi.Lang. 

Давайте остановимся на нем подробнее. Pi.Lang — это гибкий инструмент для описания преобразования внешних файлов, описанных в таких форматах, как, например, ASN.1, бинарный формат, AVRO схема, XML, текстовые форматы.

Выглядит файл Pi.Lang примерно так:

38c6cf133bb9c299e77ce3a965916036.png

Запись с типом external описывает внешний формат, запись с типом internal описывает формат, по которому будет создана IDR. 

In_Map описывает правила по которым будет произведено сопоставление записи внешнего формата во внутренний

Decoder/Encoder

После того как IDR поступает в рабочий поток Pi.One, где происходит его обработка согласно бизнес-логике и после этого он снова может быть закодирован во внешний формат (скорее всего отличающийся от входного) для систем потребителей данных.

Таким образом, система способна получать и отправлять данные в любых необходимых внешних форматах, и это не влияет на точность обработки.

b9b9d63117a8ff3c97e22c0514d797d3.png

Два режима обработки данных

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

4232d6f60051e912e4d921b7b3e43d35.png

  1. Потоковая — предполагает работу с данными в режиме реального времени. Когда размер передаваемых данных неизвестен или бесконечен, потоковая обработка может быть предпочтительнее пакетной обработки. В результате потоковая обработка обычно используется в задачах, постоянно генерирующих потоки данных.

125ac45cf9f75d5084ba626e75e33b8b.png

Транзакционная целостностьОбработка данных внутри системы осуществляется в соответствии с механизмом, гарантирующим безопасную и полную обработку данных, без дублирования и потерь. 

Безопасность данных

Встроенная пользовательская ролевая модель предполагает гибкое разграничение доступа к компонентам системы. Поддерживается интеграция с Active Directory, LDAP.

В системе фиксируются и журналируются все действия пользователей, внесенные изменения параметров и результаты обработки данных. Доступны инструменты гибкой настройки аудита обрабатываемых данных.

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

Наглядное построение процесса обработки данных

Вся работа по получению, обработке и доставке данных в Pi.One осуществляется с помощью рабочих потоков. Каждый рабочий поток строится из агентов, которые выполняют определенные задачи: собрать файлы из директории, убрать дубликаты в файлах, агрегировать данные, доставить файлы в папку на удаленном сервере и т.д.

Большая часть бизнес-логики задается с помощью настраиваемых lowcode-агентов, выполняющих операции над данными.

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

Также Pi.One имеет широкие возможности для агрегации данных — в настройках агента агрегации достаточно прописать по каким полям IDR нужно производить агрегацию. Также есть возможность описать дополнительные действия с помощью Groovy-кода, это позволяет отсеять одинаковые записи на уровне файла или файлов (в зависимости от задач), кэшировать уже обработанные данные для дальнейших манипуляций с ними. Например, если в двух разных файлах содержится время начала и время окончания звонка, а нужно посчитать его длительность и сформировать запись в файле для системы потребителя только поступления файла с записью о завершении звонка.

Именно из таких nocode и lowcode-агентов в конструкторе Pi.One наглядно проектируются сложные рабочие потоки с помощью функциональности Drag & Drop. 

Единый веб-интерфейс

Как я упоминал выше, одной из ярких черт легаси-систем является неудобный интерфейс. В современных решениях разработке UX/UI уделяется огромное внимание: вне зависимости от того, насколько сложный бэк у системы, пользователю должно быть удобно ей управлять. 

Именно на этом принципе строится интерфейс Pi.One:

  • Данные представляются в графическом минималистичном виде. На рабочем экране нет лишних элементов и информации.

  • Рабочие потоки и конфигурации распределяются по проектам. Доступ к проектам гибко настраивается для каждого сотрудника.

    9a2855ccd04eb88ab528e88cb10ff076.png
  • Составляющие каждого проекта удобно просматривать и редактировать.

  • Управление и навигация между группами потоков, потоками, библиотеками и другими элементами интерфейса интуитивно понятны.

    3da0030af68443efcfd760ceff802bcf.png

Рабочие потоки можно объединить в группы потоков и гибко настроить расписание и условия для автоматического запуска обработки. В результате после настройки и отладки системы, ее эксплуатация заключается только в мониторинге работы, с которым справится всего один оператор. 

В пакете с системой поставляются материалы для подготовки команды заказчика к работе с Pi.One в кратчайшие сроки: документация, видеоматериалы и поддержка на русском языке. Минималистичная и понятная документация доступна в адаптивной web-версии и формате .pdf. На соответствующие страницы можно перейти через поиск или прямо из интерфейса Pi.One.

Mediation-система, превосходящая зарубежные аналоги

Нагрузочное тестирование на данных Huawei GPRS показывает преимущества Pi.One в скорости обработки данных. Даже в однопоточном режиме при равных ресурсах Pi.One превосходит старый добрый HP IUM в два или более раз, не говоря уже о многопоточности.

Результаты нагрузочного тестирования:

Тип данных: Huawei GPRS

Объем в час: 40,57 гб — 1500 файлов

Объем в сутки: 781,61 гб — 36019 файлов 

Одинаковые ресурсы для обеих систем

Проверяемый функционал:

Сбор/Доставка:   локальная/sFTP
Обработка:   декодирование/кодирование, поиск дублей, валидация, фильтрация CDR

b2cd27bc261c0611557bd3b11e322770.png

  • Сценарий 1: Локальный сбор; без поиска дублей; запись на локальный диск

  • Сценарий 2: Сбор по sFTP; без поиска дублей; доставка по sFTP

  • Сценарий 3: Сбор по sFTP; поиск дублей; доставка по sFTP

Разработка на Pi.One

Но давайте не будем голословными и рассмотрим процесс реализации потоковой обработки данных на Pi.One.

Описание задачи

Нам нужно было сделать что-то для выставки CSTB.Pro.Media 2023. Что-то такое, что покажет возможности Pi.One как платформы. И мы решили сделать телеграмм-бота. 

Что же должен уметь наш бот?  

  • Регистрировать нового подписчика

  • Поддерживать команду пополнения баланса

  • Предоставлять возможность купить контент

  • Предоставлять возможность посмотреть какой контент уже куплен

  • Давать возможность просматривать купленный контент

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

Естественно, мы не стали реализовывать реальную цепочку пополнения баланса и оплаты с использованием банковских систем. Так же, как и не стали реализовывать подключение контента через DRM, а CRM быстро набросали, чтобы отображать красивые графики. Основная суть была показать, что основной каркас приложения для решения такой задачи можно написать за несколько часов. 

В качестве БД мы использовали Postgres, хотя по факту можно было выбрать любую SQL или NoSQL базу данных. Также нам было необходимо два рабочих потока: первый — это бэкенд для нашего бота, второй предоставляет REST API для нашей импровизированной CRM системы.

Разработка

Дисклеймер

Весь код писался максимально быстро, мы знаем, что можно написать лучше. Наша цель была показать возможности системы, а не красоту кода

Создание любого проекта на Pi.One проще всего начинать с создания различных профилей. Вот с них то и начнем.

Создаем файл, где будем хранить данные для подключения к БД и к Minio

31dcbaba9d44052a51109b87652418a7.png

Теперь создаем профиль внешних параметров, чтобы можно было обращаться к данным из нашего файла

ebb15d0629290e253acf36da65b8c832.png

Еще нам потребуется профиль базы данных (с его помощью мы можем работать непосредственно с самой Postgres, и он возьмет на себя все наши заботы по открытию, закрытию соединения, выполнению запросов и прочим вещам, на которые нам не хочется тратить время) и профиль для S3 Minio. Сделаем их.

e3428119758ca10cc0f9505a3820b732.png

Итак, профили готовы, теперь нам нужно описание внутренних форматов данных, с которыми мы будем работать. А поскольку мы решили писать логи в Minio, то нам понадобится и описание внешнего формата, чтобы сохранить все в файл.

61ac21c01bf72ea32ae66f0b43c1a8df.png

Так выглядит описание внешнего и внутреннего формата и правил их кодирования/декодирования на Pi.Lang.

external MessageRegExt определяет формат, в который будут декодированы наши логи. Это текстовый файл формата csv с разделителями строк;.

Каждая строка в файле определяется экземпляром MessageRegExt 

in_map MessageRec_inmap : external(MessageRecExt), target_internal(MessageRec), internal(MessageRec_Helpers) {

    automatic;    

};

Эта запись автоматически создаст внутренний формат, в который автоматически будут включены поля из MessageRecExt и добавлены поля из MessageRec_Helpers

То есть в результате получится вот такой внутренний формат:

internal MessageRec {

    long userId;

    long chatId;

    string username;

    string userFirstName;

    string userLastName;

    string message;

    int sentDate;

    string response;

    list contentList;

    bytearray contentData;

    string contentURL;

   list merchList;   

};

С ним то мы и будем работать в рабочем потоке предоставляющем бэкенд для бота. 

А это формат с которым мы работаем в потоке, предоставляющем REST API для нашей импровизированной CRM:

f49cdccec23653083ca14873245ce8d3.png

Здесь все просто, никаких типов не создается автоматически, все описано здесь. DashboardResponse это, собственно, описание тела нашего ответа. Позднее мы его декодируем в json и отправим в ответ на запрос.

Теперь пришло время для создания рабочих потоков бэкенда телеграм-бота:

9d154358c715fbbf15a5cdaf3eb397e7.png

Коротко пройдемся по тому что есть.

Init — это Pulse-агент, генерирующий импульсы с заданной частотой. Он нам нужен для того, чтобы определить порядок выполнения бизнес-логики и запустить обработку команд от бота. Любой рабочий поток устроен так, что порядок выполнения всех агентов определяется относительно входного агента. Это может быть REST сервер, агент обработки Diameter запросов, агент сбора файлов по SFTP и т.п.

Telegram_Bot — Groovy-агент, принимающий команды от нашего бота. Для реализация взаимодействия с Telegram выбрана библиотека https://github.com/rubenlagus/TelegramBots/tree/master

Вот часть кода этого агента:

d4eefe083598d833002e6f94de8b9382.png

GroovyExectuion — основной класс нашего агента, при добавлении базовый код генерируется автоматически. 

Метод initialize () определяет бизнес-логику при запуске рабочего потока. Выполняется один раз при запуске приложения.

Метод consume () выполняется постоянно во время работы потока.

Метод deinitialize () выполняются при завершении работы потока.

Для отправки данных другим агентам мы используем встроенную функцию idrRoute, принимающую два параметра: объект, который нам надо отправить, и имя пути, по которому эти данные надо отправить. В нашем примере она спрятана в TelegramMessageProcessing. Вот кусок кода из этой функции:

c123644b85e0d9f2ce3004cdbdafd7a8.png

Запрос от пользователя отправляется к другому Groovy-агенту — Processing.

В нем реализована бизнес логика по определению подключенного и доступного контента, определению баланса и реакции на команду, которую ввел пользователь.

Вся бизнес-логика выглядит вот так:

15759ebe9143144381be6e6f420f385d.png

На самом деле весь код вынесен в отдельный groovy-модуль TelegramUtils, да его импорт вы видите в самом начале. Вот кусок кода из этого модуля:

50d673991f88171d7d7800e99fa3d8cd.png

Объект PiTable — это встроенный объект Pi.One, который позволяет работать с таблицами любых БД. Есть множество встроенных функций для работы с БД. 

  • tableCreate, позволяющая создавать таблицу на основании профиля БД,

  • tableLookup для поиска данных в таблицах по определенным условиям,  

  • tableGet для получения данных из таблицы. 

  • также есть функция для выполнения sql запросов в БД — sqlExec, туда достаточно передать имя профиля БД, который мы настраивали в самом начале (в нашем случае это будет «CSTB_Workshop.PRF_DB_Common») и sql запрос, который мы хотим выполнить, если нужно выполнить запрос в рамках транзакции, это решается передачей аргумента enableTransaction в вызове функции sqlExec.

  • если нужно что-то вставить в таблицу, то будет выглядеть все примерно так:

sqlExec( ‘CSTB_Workshop.PRF_DB_Common’, ‘UPDATE myTable SET counter = 5’, true)

Закончили с этим, пишем рабочий поток для REST API нашей CRM. Он будет совсем простым — всего два агента. 

f915bbfc824b9c990294d6fbfb4580ce.png

Агент RestServer — в нем задаем настройки на каком ip-адресе и порту будет поднят наш REST API, в настройках можно настроить TLS и Oauth 2.0 авторизацию. Также есть возможность привязать профиль REST-агента, в котором прописать допустимые URI, при обращении к другим URI-агент автоматически будет возвращать 404 HTTP код  

Выглядит это так:

e55235e3ea7df77b01afedd80e360795.png

Отдаем фронтенду спеку на наше REST API, просим сделать красиво, но быстро, и вот что получается.

Groovy-агент с бизнес-логикой достаточно простой, знакомый нам уже GroovyBase с теми же самыми методами consume и теми же самыми PiTable

d6905760bf481f0ac36835e0b919ad3c.png

Из интересного тут то, что объект RestServer формируется автоматически нашим RestServer-агентом при каждом новом запросе. RestServerRequest содержит данные запроса endpoint, заголовки, тело.

RestServerResponse — еще один встроенный тип в Pi.One. Чтобы отправить ответ клиенту на его запрос, нужно создать новый объект этого типа, выполнить set_response для входного объекта и отправить его назад на наш RestServer-агент с помощью idrRoute.

Вот так мы формируем ответ. Встроенная функция jsonEncodeIdr позволяет одним вызовом превратить объект нашего внутреннего формата в json. Почти как jackson, но без всяких аннотаций

© Habrahabr.ru