Привет! Меня зовут Владислав Кучинский. Я начинал свой карьерный путь в IT с разработки на С++ и Java, а сейчас являюсь руководителем группы Platform Event Management в компании Bercut.
Сегодня я расскажу историю создания платформы Business Rules Engine (BRE) Bercut – системы обработки событий в реальном времени. Поделюсь опытом удачных и не очень решений, которые в итоге все же стали удачными. К моменту начала разработки BRE я был руководителем отдела и осуществлял различные роли: был аналитиком, архитектором, сам что-то кодировал, внедрял, тестировал.
Итак, под катом – история преодоления сложностей, с которыми мы столкнулись во время проекта, и выводы, к которым пришли.
2016-2018 год. Начало
Чтобы был понятен контекст появления платформы Business Rules Engine, приведу несколько ключевых фактов о нашей компании, партнерах\заказчиках.
Компания Bercut образца 2016 года ориентировалась в первую очередь на рынок телекома и, в частности, на операторов сотовой связи. Среди основных клиентов были операторы «большой четверки». Это накладывало дополнительные требования на работу Компании и прежде всего это были требования по SLA (Service Level Agreement, Соглашение об уровне предоставления услуги). Требования довольно жесткие, вот некоторые из них:
Доступность абонентских сервисов, реализованных на нашем ПО, должна составлять 99,999%.
«Авария А0» - в случае применения этого подхода решение по проблеме должно предоставляться в течение одного часа в любое время дня и ночи, в противном случае в силу вступают штрафные санкции.
Поэтому одним из столпов нашей разработки всегда было резервирование и масштабирование сервисов, а также возможность максимальной поддержки стека технологий, на котором мы вели разработку. Кстати, в этот момент соотношение C++/Java составляло 50%/50%. Операторам сотовой связи требовались промышленные решения, способные выдерживать высокую нагрузку. Например, сервис «Проверка баланса» - это 2000-3000 запросов от абонентов в секунду, и это не самый простой сервис. В его рамках осуществляется взаимодействие с десятком подсистем заказчика, т.к. вместе с балансом сотовый оператор передает дополнительную информацию абоненту по его тарифному плану. Ко всем прочему, требования по SLA выдвигаются сотовыми операторами не только к компаниям-поставщикам, но и к командам внутри самих операторов. Это приводило к консервативной технической политике и минимизации «зоопарка» в IT-ландшафте. Для каждой новой системы должен был быть выделен новый специалист, который бы отвечал за нее и мог самостоятельно решить большую часть проблем без обращения к поставщику.
Исторически сложилось, что в Bercut был разработан собственный фреймворк, на базе которого строятся все наши решения и сервисы. Фреймворк должен был обеспечивать быструю разработку продуктов Компании, поддержку SLA и высокую производительность.
Для повышения надежности и отказоустойчивости мы практически полностью отказались от использования open source в критичных сегментах фреймворка, т.к. неоднократно упирались в вопросы, связанные с производительностью, или потребностью расширения функциональных возможностей. Включая в свой проект open source, мы берем ответственность за него на себя.
С чего началось развитие платформы BRE
Нашему партнеру был нужен продукт Welcome SMS/Bonvoyage – система информирования абонентов об изменении условий обслуживания при регистрации в сети другой страны. В целом сервис простой; вопросы, связанные с получением данного события, мы не рассматриваем в этой статье. Но было необходимо учесть требование партнера гибко настраивать тексты SMS оповещений в зависимости от атрибутов профиля абонентов (по сути, включить таргетированную рекламу).
Было важно быстро и просто на уровне «бизнеса» вносить изменения в условия формирования текстов SMS.
Надо сказать, в упрощенной форме, что внесение изменений в продуктивную систему на тот момент происходило следующим образом: бизнес-заказчик в свободной форме пишет, какие изменения хочет, и формирует заявку в системе типа service desk, эту заявку проверяют и согласовывают ответственные сотрудники, формируют наряд на ночные работы, технический специалист выходит на работу в ночную смену, и вносит изменения в БД или в параметры системы. Далее бизнес заказчик проверяет результат, и, если что-то пошло не так, цикл повторяется. У технических специалистов есть слоты времени, и ближайший слот для ночных работ может быть через неделю. В итоге это приводило к тому, что внесение простых изменений занимало 1-2 недели.
У нас возникла идея разработать универсальную систему, которая бы могла принимать поток событий на вход и давала бы возможность бизнес-пользователям настраивать правила обработки этих событий.
Создавая платформу BRE, мы зафиксировали базовые принципы, в дальнейшем определявшие вектор ее развития:
основные пользователи системы — это бизнес-пользователи, являющиеся экспертами в своей области, без дополнительных технических скиллов;
четкое разделение функции технического специалиста (отвечающего за работу HW и компонентов) и бизнес-пользователя, который отвечает за логику продукта;
MVP (minimum viable product) подход. Количество рабочих рук на проекте было ограничено, поэтому надо было делать сразу то, что даст максимальный результат;
универсальность платформы. Мы изначально старались создать платформу без привязки к конкретному продукту и заказчику, чтобы в будущем BRE можно было использовать в других продуктах и у других заказчиков;
самодокументированность - все артефакты системы, с которыми работает бизнес-пользователь, имеют понятные названия и снабжены развернутым описанием.
Первое название платформы – Event Management, с отсылкой к тому, что система призвана управлять потоком событий.
Напомню, что первую версию Event Management мы делали для Welcome SMS, т.е. реакция на одно-единственное событие о смене страны пребывания абонента сводилась к формированию текста SMS по определенным правилам. Первая версия представляла собой BackOffice на Java (web-интерфейс на GWT/SmartGWT), который в свою очередь генерировал “скрипты” (в нотации BPEL) для «движка» из состава нашего фреймворка. Сами правила фиксировались в Excel-файле специального формата, который загружался в BackOffice.
Важным аспектом в обработке событий является необходимость получения дополнительных данных из внешних систем для принятия решений. Для этой цели был внедрен механизм, позволяющий получать данные через дополнительные модули. В то время все говорили о «микросервисной архитектуре» и за дополнительными модулями закрепилось название «микросервисы». По факту, эти «дополнительные модули» выполняли роль оркестраторов на языке BPEL между системой Event Management и внешними системами. «Микросервисы» обеспечивали приведение ответов от внешних систем к упрощенному виду и оставляли только те параметры, которые были необходимы и понятны бизнес-пользователям. Такой подход позволял снизить порог вхождения в BRE для разработчиков и для бизнес-пользователей. Разработку «микросервисов» на BPEL мог выполнять любой джун.
Первый релиз превзошел ожидания
Несмотря на всю простоту MVP решения, были закрыты основные потребности заказчика. Во-первых, time-to-market сократился практически 5 раз, т.е. до 1-2 дней, а технические специалисты были исключены из бизнес-процесса. Во-вторых, за счет гибкости правил появилась возможность «тонкой настройки» текстов SMS, что сразу значительно увеличило доход от продукта Welcome SMS - мы стали попадать «в потребности» конкретных абонентов.
Таким образом, отправной точкой развития проекта стала первая версия, выпущенная 23 декабря 2016 года.
Стало понятно, что идея и подход рабочие, но также появился пласт вопросов и проблем, которые требовали скорейшего решения.
2018 год. Версия 2.x
Процесс разработки продолжился, мы закрывали потребности различной важности. Команду временно переключили на другие проекты. И, как часто бывает, «пилотный» проект, рассчитанный на небольшую нагрузку и ограниченное количество правил, немного разросся.
К середине 2018 года количество правил приблизилось к 1000, размер одного сгенерированного BPEL приближался к 50mb (нормальный размер BPEL - до 50kb). Чтобы выдерживать нагрузку 200-300tps в тот момент требовалось 50 Solaris Zone с утилизацией CPU 60-70% (тогда мы еще работали на процессах Sun Sparc). Платформа BRE и «движки» трещали по швам из-за таких больших BPEL.
«Так дальше нельзя»
Мы приняли решение отказаться от генерации BPEL и перейти к своему «движку» обработки правил. Сами правила (сценарии) из Excel переехали БД Postgres, на базе компонента SLES, являющегося частью фреймворка, мы реализовали собственную логику на Java для обработки правил. По совпадению, в этот момент полностью сменилась команда разработки.
Перед нами стояла задача в короткие сроки реализовать «движок» правил и обеспечить полную обратную совместимость, чтобы переход от версии 1 к версии 2 для заказчика прошел максимально прозрачно.
В этот момент мы сделали полное покрытие автотестами самого ядра.
К делу подключился маркетинг: «если формируются тексты сообщений, значит это – не Event Management, а Notification System». Так система первый раз поменяла свое название. (Кажется, можно написать отдельную статью про то, как называть системы. Мое убеждение, что системе надо давать собственные имена, а «ярлыки» от маркетинга уже вешать где-то сбоку). Если старые названия системы используются в аббревиатурах, именах артефактов и интерфейсах, то изменение этих названий может оказаться невозможным или слишком дорогостоящим.
И снова релиз оказался успешным
Благодаря вышеописанным действиям (и я не про изменение название системы), 50шт Solaris Zone превратились в 4шт с утилизацией CPU 30-40%. Тут можно вспомнить разные поговорки «как сделать человеку хорошо…» и «создать проблему, а потом ее героически решить», но победителей не судят. Отказ от генерации BPEL освободил нам руки, и первое, что было сделано, это детальное и наглядное логирование выполнений правил (аудит), которое в разы сократило время на отладку и поиск ошибок в сценариях бизнес-пользователями.
Изменение архитектуры:
Появился еще один базовый принцип/цель:
система должна быть самодостаточной и закрывать весь спектр потребностей бизнес-пользователя в рамках системы (жизненный цикл правил, тестирование, логирование, статистику и т.д.).
2019 год. GWT - так дальше нельзя и здравствуй, Kafka
В процессе взаимодействия с партнером наш акцент был сосредоточен исключительно на обсуждении требований и сроков. Очные встречи рабочей группы значительно упрощали процесс выявления и формулирования требований, что, в свою очередь, улучшало скорость и эффективность наполнения релизов.
Еще один факт про Bercut - самой сильной стороной нашей разработки была разработка backend-логик, в то время как web-разработкой занимался только одна выделенная команда в Компании.
Перед командой BRE возникла задача по развитию web-интерфейса. Разработку новой версии web-интерфейса на Angular мы отдали на аутсорс. Этот первый опыт с внешними ресурсами оказался полезным, подчеркнув необходимость четкого и подробного тех. задания для сторонних специалистов. И хотя в начале возникли трудности, мы извлекли из них уроки, которые впоследствии учли в будущих проектах.
В итоге мы смогли создать новый web-интерфейс. Мы оставили часть интерфейса на GWT. От аутсорса было решено отказаться в пользую развития собственных web-разработчиков.
В этот момент шел тренд на использование Apache Kafka, и Заказчик стал активно внедрять его как основной брокер сообщений, т.е. именно в Kafka стали попадать события, связанные с жизненным циклом абонента.
Появилось идея, что, если Notification System обрабатывает события, почему бы в нее не завернуть поток сообщений из Kafka. Тут надо сказать, что наш фреймворк построен на SOA архитектуре, и все интерфейсы должен быть описан на WSDL/XSD. К моменту, когда мы включились в гонку за обработку событий из Kafka, количество разнотипных сообщений было уже внушительным. Делать под каждый тип сообщений свой WSDL/porttype не хотелось, да и технических возможностей для этого не было. Для имплементации porttype использовался свой кодогенератор, простого доступа к динамической имплементации porttype на тот момент у нас не было. Мы научились через WSDL передавать произвольные структуры данных (XSD Any Type), и это положило начало для «универсальных адаптеров».
Появился еще один базовый принцип:
простая интеграция, т.е. возможность быстро и без кодирования интегрироваться в окружение партнера (принцип MVP).
«Универсальные адаптер» — это подход, когда для подключения нового события надо сделать его описание в формате XSD, а также написать mapping, какие поля и откуда (json, xml, текст) должны приземлиться на поля XSD.
Первые «универсальные адаптеры» появились для Kafka. Kafka Consumer и Kafka Producer. Когда мы начинали работу с Kafka, мы думали: «Ну чего там? прочитал из очереди и передал дальше». В итоге у нас ушел где-то год, чтобы разобраться в нюансах работы Kafka и решить возникающие вопросы. Вопросы касались высокой нагрузки и пропускной способности, а также нештатным ситуаций, возникающих в процессе работы Kafka. Разрабатывая первую версию, мы даже не знали, что в Kafka есть партиции.
И снова релиз… ну вы поняли:)
В системе стал доступен поток различных событий, связанных с абонентом. У заказчика появилась возможность самостоятельно создавать простые продукты/сервисы и не привлекать нас как поставщика. Снова уменьшился time-to-market, заказчик смог самостоятельно, без нашего участия, «заворачивать» новое событие на Notification System.
Из чего появился еще один принцип:
максимально передать на сторону заказчика инструменты для интеграции. Мы как поставщик решения занимаемся только разработкой нового значимого функционала.
Забавный момент: система формирует тексты сообщений, у нас уже был свой простой шаблонизатор, и его возможностей стало не хватать. Мы взяли Apache FreeMarker как новый шаблонизатор.
В этот момент происходит перепозиционирование системы: благодаря тому, что у нас появилась возможность обрабатывать разные сообщения, функция системы сводится не только к формированию текстов сообщений, но и к выполнению каких-то «действий» над абонентским профилем, например, подключения услуг. Так впервые прозвучало название «Business Rules Engine».
В ходе перепозиционирования было принято решение выделить автономную систему «Communication Layer», ответственную за реализацию функционала коммуникаций с абонентами.
Архитектура системы:
2020 год. Трек на интеграцию «no code»
Систему все больше вместо Notification System называют Business Rules Engine, BRE (под таким именем она уже числится в реестре российского ПО).
Тему с универсальными адаптерами продолжаем разгонять, принципы все те же, теперь мы умеем без кодирования интегрироваться с HTTP/REST и RabbitMQ.
Внезапно возникает потребность работать с большими массивами данных, такими как список абонентов. В системе появляется функционал «группы значений»: по сути, это списки значений, не ограниченные длиной. Для этих целей мы используем Postgres (помним, что телеком - консервативная среда). Для целевой нагрузки нам недостаточно производительности одного экземпляра Postgres, и мы решаем задачи, связанные с шардированием.
Также в периметре системы появляется возможность обработки отложенных событий (когда «пришло» событие, но мы хотим произвести действие над абонентским профилем спустя какое-то время). Происходит очередной виток по созданию Заказчиком еще более сложной логики продуктов на базе BRE.
Продукты на базе BRE становятся все сложнее, а time-to-market остается на том же отличном уровне. Чтобы было понятно, реализация одного запроса от заказчика к поставщику может занимать от двух месяцев. Тут же за месяц своими силами заказчик делает простые и не очень сервисы/продукты для апробирования подходов.
Архитектура системы:
У партнера есть система, назовем ее система X, отвечающая за формирования рекламных предложений для абонентов. Механизм работы этой системы аналогичен нашему BRE. На данном этапе BRE обрабатывает преимущественно «технические» события.
2020-2021 год. Транзакционность и Microservice Core
Очередной вехой развития платформы стало решение по созданию библиотеки и набора «микросервисов». В чем суть? Было реализовано порядка 20 «действий», которые могут быть использованы в BRE и совершены над профилем абонента.
BRE все чаще используется для коммерческих запросов и становится центральным элементом продуктов Компании. Заказчик продолжает быстро и тонко настраивать логику своих продуктов, даже без нашего участия.
С появлением Библиотеки в BRE была добавлена поддержка распределенных транзакций, т.к. последовательность действий по событию стала усложнятся, появились потребности «откатывать» часть действий, если все действия нельзя выполнить.
Мы продолжаем расширять функциональность системы и стремимся охватить все аспекты ее работы, которые могут быть полезны бизнес-пользователю. Чтобы пользователи могли отслеживать ключевые показатели работы системы, мы создали управление разграничением доступа и отчетность. Подсистема отчетности представляет собой встроенный агрегатор, который по заданным пользователем правилам собирает ключевые показатели. С ростом количества продуктов и сценариев добавляются гибкие механизмы для поиска и анализа созданных сценариев.
Мы перестраиваем работу с хранением аудита и начинаем проповедовать смешанный подход (реляционный и nonsql подход). Основные структуры данных находятся в реляционной модели, динамические данные храним как JSONB. Реализуем SQL-конструктор для выгрузки данных из аудита: пользователь может гибко задать, по каким запросам и по каким микросервисам он хочет увидеть аудит. Объем хранимого аудита составляет порядка 15Тб в продуктивном окружении на одном экземпляре Postgres:
2022 год. JSON
В 2022 году компания-поставщик системы Х, с которой ранее мы работали параллельно, выводит бизнес из России. Срок действия лицензий системы Х приближается к концу.
В самые сжатые сроки, буквально за 3 месяца смогли договориться о требованиях с новым подразделением партнера, обучили технических специалистов использованию BRE, провели многодневный интенсив для бизнес-пользователей. Провели бесшовную интеграцию, реализовали недостающий функционал и на опережение сдали релиз, смогли встроиться в контур без изменения интерфейсов в других системах, но миграцию данных было невозможно провести автоматически, и коллеги делали это ударными темпами в ручном режиме.
Релиз получился непростым, но принес системе значительный функциональный прорыв. Теперь на уровне пользовательского интерфейса мы научились работать с JSON, что еще более упрощает интеграцию с внешними системами. JSON полученные через «универсальные адаптеры» теперь могут проходить до ядра BRE. На уровне бизнес-пользователя в web-интерфейсе можно указывать, какие именно нужны поля из JSON.
Выше я упоминал FreeMarker. В 2022 году FreeMarker просочился в систему и стал подобием «формул в Excel», т.е. любые операции - по преобразованию данных, по извлечению данных из JSON, арифметические операции, - сейчас выполняются на FreeMarker. Выглядит это, возможно, необычно, но заменить его на что-то более подходящие и отвечающие текущим задачам уже проблематично. Одна из задач, которую пока мы не можем решить полностью из-за специфики устройства FreeMarker, это определение всего списка переменных, которые используются в FreeMarker шаблонах до начала обработки шаблона.
Я люблю новых участников в проекте, то, что называют «свежая кровь», когда новые люди привносят идеи. Новые участники в проекте помогают взглянуть на него под другим углом. Например, новое подразделение заказчика предложили развернуть BRE в K8s. До этого мы активно не пользовались K8s, исключительно использовали Docker для внутреннего тестирования. Теперь запуск BRE в минимальной конфигурации в K8s занимает всего 10 минут.
2023 год. Вместо заключения
Текущая архитектура системы:
Наблюдая за развитием продукта в разрезе семи лет, меняется взгляд на некоторые из ранее принятых технических решений. Очевидно, но факт: сфера и среда развития продукта принципиально влияют на развитие системы.
Некоторые потребности вызревают годами, и это кажется нормально, когда мы как поставщик решений предлагаем идею, и через полгода или год к нам приходят с запросом на реализацию этой идеи. Скорее всего, если бы мы текущую систему принесли в 2016 году и показали бизнесу, нам бы ответили «Ой, это все слишком сложно, нам такое не надо».
Зафиксирую ключевые моменты, которые помогали и помогают нам развивать систему:
Наличие базовых принципов построения системы и подходов. Когда все участники проекта разделяют и принимают их, работа и принятие решений становятся намного проще и комфортнее.
У системы/проекта должен быть «хозяин» или лидер. По большому счету не так важен уровень компетенции данной роли, главное, чтобы человек горел проектом и хотел его развивать, остальное дело наживное. Я видел не один проект, который имел потенциал, но когда лидер покидал проект, проект переставал развиваться.
Ответственно подходить к выбору framework’ов.
Создание условий, позволяющих партнерам самостоятельно, на местах, производить интеграцию наших решений. Это ускоряет процесс внедрения. А мы как поставщик могли заняться развитием своей системы.
В нашей сфере нам удалось найти баланс между разработкой и настройкой. Задачи, для которых раньше требовалось кодирование, теперь решаются настройками.
Успешное развитие продукта связано с наличием базовых принципов, лидерства и ответственного подхода к выбору технологических решений.
За семь лет был пройден тернистый, но интересный путь развития и усовершенствования Business Rules Engine . Были сложности, белые пятна в работе, но мы искали решение проблем, использовали системный подход, и усилиями небольшой команды создали продукт с возможностями, которые делают BRE мощным инструментом для улучшения маркетинговых кампаний, персонализации взаимодействия с клиентами и обработки больших объемов данных.
Может быть интересно по теме:
sstv
Спасибо за статью!
Я ведь правильно понимаю, что правила создаются общего вида и чтобы понять нужно ли выполнить действие, мы должны событие прогнать каждое событие по всем правилам в системе?
Отсюда вопрос: как решаете проблему с большим потоком событий при большом объеме правил?
Например если в системе заведено 20 тысяч правил и поток событий скажем 1000 в минуту, то это означает, что при однопоточной обработке, мы должны успевать обрабатывать 16 событий в секунду (прогоняем в сумме 320к правил в секунду) или 60 мс на 1 событие на прогон 20к правил.
У вас написано что вы еще куда-то в сеть ходите чтобы принять решение, в условиях такой нагрузки и объема работы, кажется нереальным куда-либо по сети ходить :) если поставщик данных зависнет на пару секунд - накопится очередь. Понятно что можно поднять пару десятков подов, побольше партиций в кафке. Правила держать в памяти пода и обновлять фоново из бд раз в N минут... :) хочется более фундаментального решения проблемы :)
Возможно Вы как-то предварительно фильтруете какие правила нужно применить (чтобы зря не жечь CPU) или они не универсальные и заточены под конкретное событие?
Спасибо.