Платформа данных в хранилище Магнит OMNI
Всем привет! Меня зовут Михаил, я руковожу разработкой хранилища данных «Магнит OMNI». Хочу рассказать, как мы решали проблемы его создания: разделение ресурсов хранилища между несколькими большими равнозначными заказчиками; переиспользование кода для оптимизации рутинных задач; развитие платформы DWH в условиях активно растущего бизнеса; навигация в сотнях витрин и соблюдение единообразия расчёта метрик.
Что такое «Магнит OMNI»?
Чтобы лучше понимать, из чего состоит наше хранилище, надо погрузиться в наши бизнес-направления:
Магнит Плюс — мультиформатная система лояльности. В ней участвуют около 70 миллионов пользователей. Средний чек здесь примерно вдвое больше, чем у обычных покупателей. Мы делаем клиентам персональные предложения, анализируем эффективность маркетинговых кампаний и улучшаем опыт пользователя.
Фудтех — наш e-commerce. Всё, что касается доставки еды и товаров на дом. Анализируем процессы заказов, сборки, доставки, работы курьеров и прочего.
Магнит Маркет — маркетплейс. Развиваем его на основе своей сети магазинов и распределительных центров.
OmniApp — платформа, которая объединяет все три бизнес-направления. Идём в гиперприложение, которое известно как «Магнит: акции и доставка», в котором наш клиент может воспользоваться всеми благами предыдущих бизнес-вертикалей.
На чём мы всё это строим?
Ядром нашего хранилища является Greenplum. Наша цель здесь — считать все метрики хранилища в режиме «сегодня за вчера» или в ином пакетном режиме, после чего отдавать в работу аналитикам, BI и т. д.
Clickhouse используем для работы в реальном времени (Clickstream — для журналов касс и прочего), а также для BI-нагрузки (Clickhouse гораздо лучше справляется с большой аналитической портянкой, чем Greenplum).
Airflow и DBT — это основа наших фреймворков для диспетчеризации и шаблонизации типовых решений.
Kafka и Debezium — основной инструмент поставки данных в хранилище. Подключаем Debezium к внешней базе бэкэнда, выгружаем из нее WAL-журналы в Kafka, из Kafka в зависимости от сценария отправляем в Clickhouse (в реальном времени) или в S3 (в пакетном режиме). В Greenplum прокидываем через S3.
Datalens — как основной BI-инструмент.
DBT и OpenMetadata как наш задел каталога данных. С их помощью стараемся решать проблемы data governance.
Проблема первая: несколько заказчиков и одно хранилище
Было так: несколько суперэффективных менеджеров, которые стараются перетянуть на себя ресурсы хранилища. Кто активнее требовал, тот и получал больше ресурсов, чем другие подразделения.
Инженеры от этого страдали, постоянно перепрыгивая по бизнес-контекстам, не решая задачи от начала до конца, не понимая ценности решений и их целей. Искажалось восприятие: «Ну, упало и упало, что от этого поменяется? Просто тасковый Airflow красный, ничего страшного, пойду лучше кофе попью».
Бизнесу, в свою очередь, было совершенно непонятно, как всё это расширять. Накачав хранилище неким количеством средств, он хотел получить взамен ресурсы, но этого не получалось при едином котелке. К тому же всё это ещё и медленно работало.
Решили так: создали один большой ресурс DWH на несколько маленьких подбизнес-доменов. Начали соблюдать наш ключевой OMNI-принцип — customer is the boss. У каждой бизнес-команды есть единый бизнес-заказчик, мы работаем в его интересах, и он понимает, что у него есть выделенный ему ресурс. Теперь инженеры доводят решения от начала до конца, то есть от источника до витрины, и понимают, что и зачем они посчитали, как это влияет на бизнес. И бизнес тоже понимает, что если он выделит хранилищу столько-то денег, то получит столько-то ресурсов.
Недостаток один — получается всё ещё медленно. Но DWH в целом не обеспечивает очень быстрый time to market.
Проблема вторая: зоопарк решений
Разделившись на бизнес-домены, мы начали делать решения изолированно друг от друга. И столкнулись с тем, что возник зоопарк инструментов. В чём это выражается? Как и все технари, мы очень любим изобретать велосипеды под типовую задачу.
Каждый со своим представлением о прекрасном, со своим опытом делает задачку по-своему, потому что «там явно хуже, я сейчас лучше сделаю по-быстрому». В результате становится непонятно, как чинить каждое такое решение. Каждая проблема становится уникальной, просто потому, что нет никакой унификации. Мы подходим к каждому исправлению бага как к новой истории, то есть заново погружаемся в DAG. Даже сам автор уже не помнит, что он сделал год назад, потому что он создал таких инструментов штук 200 уже.
Ещё хуже, когда мы не знаем, что у нас что-то упало. Разрабатывая велосипеды под каждое решение, мы частенько забивали не только на документацию, но и на оповещения. Характерная ситуация: мы спокойно делаем задачи по спринту, и в лучшем случае к нам прибегают аналитики с криком, что всё упало, а в худшем — бизнес.
Наконец, адаптация новичков проходила примерно так:
Приходит новый инженер, он не понимает, какие документации ему смотреть, во что погружаться, есть ли какие-то фреймворки. И начинает изобретать свой велосипед.
Как решили эту проблему: взяли самые лучшие велосипеды, которые были написаны, и унифицировали их под наши паттерны разработки.
В данном случае это связка Airflow и DBT, которая на вход принимает YAML-описание витрины и DBT-модель её расчёта. На выходе динамическая генерация даёт нам единообразный DAG, который идёт по ступенькам:
Сенсоры, которые не позволяют нашей витрине рассчитаться до того, как посчитались все её источники. На этом этапе мы убеждаемся, что расчёт в целом меритократичен и имеет смысл. Есть опция вынести что-то во внешний DAG и запустить это через единый интерфейс, если уж наше решение настолько необычное, что не вписывается в расчёт одной DBT-моделью или целой связкой.
Сам расчёт DBT-модели — это просто dbt-run с аргументами из контекста Airflow DQ. Мы проверяем, насколько это адекватно хотя бы технически, есть ли дубли, есть ли какие-то типовые бизнес-баги.
Группа задач Post_flow позволяет что-то сделать с результатами наших расчётов. Здесь типовой сценарий выглядит так: посчитали витрину в Greenplum, денормализовали что-то большое, готовое к BI или аналитике, экспортировали это в Clickhouse. И можем проверить, насколько правильно экспортировали: Clickhouse у нас legacy, и когда он сбоит из-за неатомарности операций вставки, мы можем не соблюсти правильность переноса. То есть в Greenplum получится меньше строк, чем экспортировалось в Clickhouse, потому что там они просто дублировались.
В результате принятых мер мы почти перестали строить велосипеды и начали больше на них кататься. Нам стало понятно, где и что упало благодаря встроенному во фреймворк оповещению соответствующих команд. Иначе, если ответственны все, то не ответственен никто. Новичкам стало понятно, какую документацию нужно смотреть. И люди теперь понимают, что с помощью документации смогут решить 80% задач от бизнеса.
Проблема третья: развитие платформы DWH
Все эти фреймворки реализовали героические бизнес-команды. Но режим подвига не вечен, из него периодически надо выходить. Начали возникать проблемы, когда непонятно, кому чинить упавший фреймворк. По идее, это должен делать тот, кто его написал. Но у той команды есть текущие задачи, им вообще не до того, что какой-то баг обнаружила другая бизнес-команда. А другая команда не может это чинить, потому что фреймворк написала другая бизнес-вертикаль. Возникает конфликт интересов, распри, кому следить за универсальностью фреймворков для всех бизнес-вертикалей и расшивать их, чтобы они оставались применимыми и не требовали написания новых инструментов. И кому вообще положено делать новые фреймворки?
Вышли из этой ситуации так: платформенная команда теперь сосредоточена на построении платформы данных и не принадлежит ни к какой из бизнес-вертикалей. Её ключевые заказчики — это сотрудники DWH. Команда постоянно сосредоточена на создании и развитии самих фреймворков, то есть развитии DWH как продукта. Теперь, когда у нас появился понятный план, мы начали делать не только run, но и change.
Проблема четвёртая: Data Governance
Разобравшись с тем, кому и на чём делать и кто будет заниматься инструментарием, начали разбираться с тем, что мы вообще считаем. Оказалось, что таблицы в хранилище не были описаны, поэтому никто не знал, что в них лежит. Аналитики тратили кучу времени на поиск данных и меньше занимались анализом. Когда-то кто-то один узнавал подробности, его постоянно дёргали в мессенджерах: «Слушай, а что тут лежит? А точно ли это тут лежит? Давай проверим, сходим, узнаем».
Витрины часто не имели владельца. Поэтому было непонятно, насколько правильно они рассчитывались. К кому обращаться при появлении проблем и вопросов? У какой команды заказывать доработку? Недостаток индивидуальной ответственности в том, что инженеры могут ходить в отпуск или увольняться. Так, в лучшем случае витринами никто не пользуется, а в худшем — они не актуализируются и бизнес делает на их основе ошибочные выводы.
И третье следствие — это описание метрик. Мы достаточно часто спотыкались на разных расчётах одной и той же метрики: бизнес видел в разных дашбордах разные результаты. Он выбирал тот, чей расчёт считал более авторитетным, но не факт, что тот оказывался правильным.
Всё это мы решили так:
Мы зашили в наши merge request проверки, что если есть неописанные или фиксированные, но не актуализированные поля, то merge request не будет добавлен.
Инженеры делают Детальный и Витринный слои в DBT. Получаем code driven data lineage и описанные данные в DWH. Мы не тратим время на ручное связывание одной витрины с другой, всё делается нативно, исходя из референсов в DBT-моделях.
В OMD лежат описанные метрики, а data-продукты помечаются ответственным доменом. Когда метрика согласована с бизнесом, мы начинаем ей верить. Все метрики привязаны к конкретным витринам и владельцам. Если что-то идёт не так, нам понятно, к кому обращаться.
Итоги
Как мы начали работать с несколькими большими заказчиками, которым надо вчера? Разделили команду по доменам. Вопрос о том, что надо вчера, ещё не решили. Но это нормально, бизнес бежит быстрее.
Как переиспользовали решения и оптимизировали рутинные задачи? Взяли самые лучшие наши велосипеды и расшили их для того, чтобы ими можно было покрывать большую долю нашей разработки.
Как развиваем DWH-платформу в условиях активного развития бизнеса? Выделили платформенную команду. Инженеры бизнес-вертикали сосредоточены на том, чтобы приносить бизнесу ценность. Нет делёжки ресурсов и конфликтов.
Как не потерялись в сотнях витрин и не начали считать одно и то же? Активно внедряем Data Governance.
Планы
Хотим внедрить Trino и S3. Мы подняли связку в эксплуатации, но хочется сделать её единым окном для аналитики, потому что Trina за счёт своей гетерогенности доступов снижает когнитивную нагрузку, когда за одной метрикой мне надо в Clickhouse, а за транзакционными данными — в Greenplum.
Хотим развивать знания о нашем DWH. Как ни странно, мы делаем всё для аналитиков, которые делают наш бизнес data driven, но сами такими не являемся. Начинаем развивать мониторинг нашего DWH, чтобы фиксировать технические показатели.
Проводим поведенческую аналитику пользователей в базах данных, чтобы понимать, как нам перепроектировать хранилище, что пользуется спросом, а что просто занимает место у нас на дисках. Идём в сквозное решение базовых метрик: хотим, чтобы DWH полностью считала базовые метрики для бизнеса, от источника до целевого дашборда. Хотим сделать суперверифицированный слой. Пусть медленный, но от DWH.
Самые большие планы — битва с legacy. Исторически сложилось, что у нас есть очень неоптимальный Clickhouse, и мы активно боремся с его падениями. Переезжаем с него на новый кластер с репликацией, новым подходом к распределению таблиц и шардгруппами. Также перевозим реляционную нагрузку от аналитиков на GreenPlum, а для адхоков пускаем в Trino.