«Битрикс24» — продукт, который позволяет клиентам удобно управлять бизнес-процессами и эффективно использовать доступные данные для глубокой аналитики. В последнем особенно помогает «BI Конструктор» — внутреннее решение, с помощью которого можно реализовывать даже самую сложную аналитику и прозрачно контролировать все метрики.

Меня зовут Александр Сербул. Я руководитель больших данных, высоконагруженных систем и машинного обучения «Битрикс24». В этой статье я расскажу, как мы строили «BI Конструктор»: какие требования предъявляли к решению, как решали возникающие задачи и что получили в результате.

Статья подготовлена по мотивам моего доклада на VK Cloud Conf 24. Вы можете посмотреть его здесь.

Контекст и исходные требования

Чтобы удовлетворять запросы каждого клиента и предоставлять более широкую функциональность, мы хотели дать пользователям возможность выполнять бизнес-аналитику на данных внутри портала «Битрикс24». 

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

  • BI-аналитика на данных внутри портала «Битрикс24» и быстрое открытие дашбордов;

  • возможность пересборки дашборда и фильтрации данных на лету;

  • наличие типовых дашбордов и возможности быстрого создания своих;

  • возможность объединения данных разных сущностей, например лиды, товары, суммы и другие;

  • наличие подробной документации и возможность развития BI-инструмента независимо от «Битрикс24»;

  • отсутствие рисков внезапного закрытия или недоступности из-за санкций и других ограничений.

Декомпозиция по целям как способ удовлетворить все запросы

Анализ рынка показал, что готовых коробок, способных закрыть все потребности «здесь и сейчас», просто нет. Поэтому, чтобы удовлетворить все запросы, нам требовалось разделить задачу на подзадачи и решать их независимо.

  • BI-аналитика на данных портала «Битрикс24». Чтобы предоставить клиентам возможность BI-аналитики, мы стали отдавать из портала «Битрикс24» через BI-коннектор JSON-файлы с нужными сырыми данными в формате простой и понятной таблицы с колонками и строками.

  • Быстрое открытие дашбордов. MySQL и подобные решения не могут обеспечить оперативное открытие дашбордов. Поэтому нам требовался быстрый кластерный OLAP-движок для BI. Причем готовый, Open Source.

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

  • Наличие типовых дашбордов и возможности быстрого создания своих. Чтобы дать возможность гибко работать с существующими и новыми дашбордами, у «BI-мордочки» должно быть API. Примечательно, что многие доступные решения под эти задачи либо неоправданно дорогие, либо дают очень ограниченные возможности.

  • Возможность объединения данных разных сущностей. Для удовлетворения этого требования важно, чтобы ВI-OLAP-движок умел джойнить данные из разных источников. 

  • Наличие подробной документации и возможность развития BI-инструмента независимо от «Битрикс24». Соответственно, нужны Open-Source-компоненты с развитым и активным комьюнити.

  • Отсутствие рисков внезапного закрытия или недоступности из-за санкций и других ограничений. Эта боль закрывается размещением Open Source в облаке российского провайдера.

Подобная декомпозиция задачи позволила нам выделить основные векторы реализации BI-инструмента. Но на этом всё не закончилось — помимо технических требований, у нас были и запросы от бизнеса. Так, нам было важно:

  • обеспечить быстрое масштабирование BI-системы на десятки тысяч компаний в России;

  • реализовать продукт за полгода — релизный цикл.

Это, очевидно, существенно осложняло задачу, но вариант отказа от создания BI-сервиса мы даже не рассматривали. Поэтому мы решили строить решение на базе готовых компонентов и приступили к реализации.

От требований к реализации

Эффективная отдача данных с портала «Битрикс24»

В первую очередь мы начали с оптимизации отдачи JSON-данных с портала «Битрикс24».

Здесь примечательно, что сейчас тренд — не централизованное, а разрозненное хранение данных, при котором данные лежат в той системе, к которой относятся. Чтобы следовать тренду, мы изначально проработали:

  • поддержку выбора и отдачи отдельных колонок данных — можем отдавать данные выборочно;

  • поддержку фильтрации данных по дате и выбор колонки применения фильтра по дате;

  • поддержку LIMIT — можем передавать по запросу нужное количество строк;

  • поддержку фильтрации колонок по логическим предикатам.

Таким образом, мы обеспечили возможность забирать только нужные данные из MySQL, в котором портал «Битрикс24» хранит данные. 

Trino с плагином как read-only OLAP

Чтобы обеспечить быстрое открытие дашбордов, нам нужен был быстродействующий кластерный BI-движок OLAP. 

После поиска и изучения доступных вариантов мы остановились на Trino. Среди причин выбора именно этого инструмента были ориентированность на бизнес, поддержка традиционного ANSI SQL, быстрое оперирование запросами и данными. Кроме того, сервис активно используют крупные компании для OLAP-аналитики.

В итоге мы написали к Trino плагин на Java, который ходит за JSON к BI-коннектору, и получили read-only OLAP-решение под свои задачи.

Apache Superset — легкая «BI-мордочка»

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

Под эти задачи мы выбрали Apache Superset — активно развивающийся Open Source BI-проект, который позволяет строить легкий семантический BI-слой с Drag&Drop вместо программирования. 

Среди прочего нам было важно, что Apache Superset поддерживает интерактивную работу с графиками (React), а также может работать с Trino и десятками других SQL-хранилищ. Соответственно, с помощью этого сервиса мы смогли закрыть потребность в гибком интерфейсе.

Одновременно с выбором Apache Superset мы также нативно закрыли запрос на кастомизацию дашбордов. Здесь помогло то, что у Apache Superset есть большое API, благодаря которому можно не только использовать готовые (типовые) дашборды, но и загружать новые. 

Собственно, так мы и сделали — настроили импорт ролей, прав и типовых дашбордов из портала «Битрикс24» в Apache Superset через его API.

Стоит отметить, что на каждого клиента мы выделяем свою инсталляцию Apache Superset с 512 МБ оперативной памяти. 

«Пересечения» BI-данных

Далее стал вопрос обеспечения возможности консолидации данных, чтобы «собирать конструктор» из нужных данных из разных таблиц. 

Изначально у нас был запрос на ВI OLAP-движок, способный выполнять JOIN данных. 

Чтобы достичь этого, мы решили комбинировать возможности уже выбранных компонентов. Так, в нашей реализации:

  • для JOIN мы применили Trino (Apache Superset не умеет объединять данные). При этом Trino не хранит данные, а только запрашивает их, выполняет SQL-операции и отдает результат;

  • Apache Superset сохраняет подзапросы с JOIN как «виртуальные датасеты» для дашбордов на его основе.

В результате мы получили удобный и быстрый механизм джойна данных из разных источников. 

No vendor lock 

Наряду с остальными аспектами нам было важно, чтобы выстраиваемая BI-система могла развиваться независимо от «Битрикс24» и была защищена от рисков Vendor lock-in. 

Вместе с тем в нашей реализации эти потребности закрывались нативно:

  • Trino, Apache Superset, Java — открытые и развиваемые сообществом инструменты с документацией и открытым кодом, на которые можно переселиться.

  • Мы развернули решение на мощностях облачного провайдера VK Cloud: подняли на платформе виртуальные машины, используем облачное S3-совместимое хранилище и другие сервисы.

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

От реализации к первым вызовам

После получения реализации и даже ее демонстрации бизнесу мы убедились, что проект работает успешно и закрывает все запросы потенциальных клиентов. Но одновременно мы неожиданно столкнулись с тем, что решение работает ограниченно — исключительно на ноутбуке разработчика :) С масштабированием BI-системы на всех пользователей возникали трудности.

Проблема оказалась в том, что Apache Superset «не запускается без контейнера»: чтобы установить Apache Superset на сервер, нужны сложные и не всегда очевидные зависимости в библиотеках, что делало инсталляцию затруднительной, если не невозможной.

В итоге после недель безрезультатных попыток мы решили попробовать запустить Superset в Docker-контейнере и, к счастью, получили ожидаемый результат — всё заработало успешно. Аналогично решили поступить с Trino — его тоже успешно подняли и запустили в Docker-контейнере. Следом проделали то же самое с MySQL. В результате мы получили Docker Compose на 10 контейнеров, в котором всё работает стабильно и прогнозируемо — убедиться в этом помогло нагрузочное тестирование внутри Docker Compose: MySQL, Nginx, Redis (для кэша), Superset, Trino (с плагином), портал «Битрикс24».

Контейнеры в запущенном Docker Compose

Развертывание в облаке, или жизнь после Docker Compose

После «оборачивания» всех компонентов конфигурации в контейнеры мы фактически получили готовый продукт. Далее нам предстояло масштабировать решение на всех клиентов «Битрикс24», то есть надо было развернуть его в облаке. Здесь мы столкнулись с тем, что с Docker Compose реализовать подобную задачу сложно, особенно без глубокой экспертности в этом вопросе. 

Поэтому мы сначала перенесли Docker Compose на Minikube, а потом и вовсе решили перейти к «полноразмерному» Kubernetes. 

Более того, после изучения литературы, курсов и других доступных материалов мы поняли, что нам нужен не «чистый» K8s, работа с которым подразумевает «копание под капотом», а управляемый Kubernetes, за поддержку, функционирование и обновление которого будет отвечать вендор. 

Мы выбрали облачный управляемый Kubernetes в VK Cloud (Cloud Containers). Выбор в пользу такой реализации позволил нам оставить в своей зоне ответственности только верхнеуровневое администрирование, снизить порог входа в работу с K8s и сократить любые потенциальные издержки.

Архитектура решения внутри VK Cloud

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

  1. Сейчас у нас поднят в VK Cloud управляемый Kubernetes на более 25 000 подов и более 200 серверов. Внутри каждого пода контейнер Superset (512 МБ оперативной памяти) и Redis (64 МБ памяти кэша).

  2. MySQL для контейнеров Superset мы держим снаружи: хранить БД внутри K8s — не лучший вариант (хотя приходит понимание, что это утверждение тоже становится архаизмом и БД в K8s запускают все чаще).

  3. Для подключения клиентов мы выполняем установку helm-приложения со своими конфигами. При этом, по рекомендации опытных инженеров K8s VK Cloud, релизы helm мы перенесли в Postgres-бэкенд, поскольку со временем они просто перестали помещаться в память внутреннего хранилища K8s на базе etcd. 

  4. В Ingress-контроллере вместо стандартного аддона ingress-nginx мы используем contour-envoy. Такой переход был обусловлен тем, что ingress-nginx при добавлении нового клиента по умолчанию обновляет полностью весь конфиг, и уже на 5000 клиентов это стало значительной проблемой. С переходом на contour-envoy алгоритм действий при добавлении клиентов изменился (конфиг не перечитывается, а просто и быстро меняется в памяти, регулярно автоматически сохраняясь на диск), и проблема была решена.

  5. Управляющее внутреннее API у нас реализовано на python/flask. Мониторинг Kubernetes мы осуществляем с помощью аддона kube prometheus stack, а мониторинг приложения — используя экспорт метрик Prometheus из Flask API, Prometheus, Grafana.

  6. Что касается аддонов. Нам удобно пользоваться стандартными аддонами K8s от VK Cloud — они созданы и поддерживаются провайдером и быстро решают возникающие бизнес-задачи. Вместе с тем мы всегда можем поменять их на более кастомизированное решение, как мы и сделали, заменив ingress-nginx на contour-envoy.

Итоговый алгоритм работы с компаниями-клиентами

После создания и вывода в прод новой BI-системы «Битрикс24», мы выстроили следующий порядок работы с клиентами продукта.

  1. Каждая компания-клиент получает персональный под с уникальным доменным именем. Внутри пода — Apache Superset и Redis.

  2. Обновление конфигов клиента выполняется через helm upgrade.

  3. Для экономии ресурсов мы отключаем «недавно» неактивных клиентов с помощью установки нулевого значения числа подов в деплойменте Apache Superset = 0. При этом в случае необходимости мы можем легко вернуть клиенту BI-конструктор, указав в деплойменте Apache Superset = 1 после анализа логов балансеров с помощью fluent--bit.

  4. Давно неактивные клиенты удаляются из Kubernetes (helm uninstall), но могут быть восстановлены в K8s из MySQL.

  5. Для масштабирования мощностей с учетом фактической нагрузки мы используем штатный аддон, автоскейлер VK Cloud.

Вместо выводов

Создание BI-системы — большой шаг в развитии такого продукта, как «Битрикс24». Но наш опыт показал, что «съесть можно даже слона, если делать это последовательно, небольшими частями и с пониманием своих возможностей». 

Именно поэтому мы пошли по пути декомпозиции задачи, частичного делегирования задач вендору VK Cloud и выстраивания реализации из готовых компонентов. Благодаря этому при довольно скромных затратах сил и времени мы получили полнофункциональный эффективный продукт, который успешно помогает вести бизнес десяткам тысяч клиентов «Битрикс24».

Комментарии (0)