Управление сложностью legacy-кода в Big Data проектах с помощью инструмента Datalog

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

Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!

Самый простой Big Data проект сложнее проекта из мира привычного ПО. Имеется ввиду не сложность собственно алгоритмов или архитектуры, но анализа того, что представляет собой проект, как он работает с данными, как собирается та или иная витрина, какие для нее берутся данные.

Например, нужно решить такую задачу:

1. Загрузить таблицу из Oracle;
2. Посчитать в ней сумму по какого-нибудь полю, сгруппировав по ключу;
3. Результат сохранить в витрину в Hive.

Набор инструментов будет выглядеть примерно так:

• Oracle
• Apache Sqoop
• Oozie
• Apache Spark
• Hive

Простая задача неожиданно приводит к появлению проекта, включающего три независимых инструмента с тремя независимыми папками исходных файлов. И как понять – что происходит в проекте?

Если рассмотреть более типичный случай, то набор артефактов простого проекта в Big Data представляет собой:

• SH управляющие файлы;
• Sqoop скрипты;
• набор Airflow Dag или Oozie Workflow;
• SQL скрипты собственно преобразований;
• Исходники на PySpark или Scala Spark;
• DDL скрипты создания объектов.

Также, особенностью является то, что если пользоваться Cloudera или Hortonworks, то среда не предоставляет удобных средств разработки и отладки.

Облачные среды, такие как AWS или Azure, предлагают все делать в их оболочке, объединяющей все требуемые артефакты в удобном интерфейсе.

Вот, например, картинка с сайта Microsoft Azure:



Но это если есть AWS или Azure. А если есть только Cloudera?

Как ответить на вопрос – что, собственно, в проекте написано? При этом этот вопрос крайне интересует и заказчика тоже, так как в случае обычного ПО ему все равно то, как всё устроено внутри, а в случае с Big Data заказчику важно понимать, что данные получаются правильно.
В мире обычного программирования есть набор паттернов, подходов, применение которых позволяет структурировать код. А как структурировать код, представляющий из себя зоопарк независимых SQL-файлов, SH-скриптов вперемешку с Oozie Workflow?

Конечно, обычным решением является ведение подробной документации. Но документация устаревает в момент создания, а в случае авралов, разработка ведется вообще без обновления документов. Хочется автоматически собирать сведения о структуре данных, раскрывая Dataflow проекта.

Еще одним подходом является создание в компании Data Catalog, в котором будет регистрироваться каждый источник данных, и который будет являться единственным источником информации о датасетах, Source of Truth.

Существуют различные инструменты для создания Data Catalog:

• Cloudera Navigator;
• Alation;
• Colibra.

Эти инструменты, например, с помощью Data Crawlers, мониторят события, происходящие в области данных и строят каталог объектов, пытаясь построить Lineage там, где это возможно. Например, подключаются к событиям Spark и вынимают оттуда данные об объектах. Это иногда позволяет не только записать в каталог объект, но и восстановить его Lineage. В результате появляется каталог как единый Source of Truth для данных, что сильно облегчает понимание их структуры и взаимосвязей.

Картинка с сайта Cloudera Navigator:



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

Мы в компании Neoflex разработали и применяем несколько другой подход, который реализовали в инструменте Datalog или, более полно – Data Topology. Инструмент предоставляет возможность раскрывать топологию объектов проекта в разрезе Dataflow, создавая автообновляемую документацию проекта в разрезе диаграм Dataflow на основе исходных кодов.

Проект Big Data представляет собой исходники для самых разных инструментов, но их объединяет одно – общая доменная модель. Имеется ввиду то, что все артефакты проекта – SQL-скрипты, SH-скрипты, исходники Spark и прочее описывают только одно – Dataflow.
Это значит, что если извлечь из артефактов (скриптов и исходников) данные о таблицах, которые используются в каждом из компонентов, то можно построить диаграмму Dataflow проекта. В большинстве случаев этого более чем достаточно, чтобы сделать содержимое проекта прозрачным и доступным анализу.

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

val df = spark.sql(“select * from Table1”) 
val df = spark.sql(“select * from ${source_table}”) 
val df = spark.sql(“${sql}”)


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

Лучше всего это работает для больших Legacy проектов с долгой историей, про которые то, как они целиком устроены, обычно не может сказать ни один человек. Заказчик становится зависим от команды проекта, а после его передачи другим людям ситуация повторяется. В случае нашего подхода достаточно написать несколько простых правил извлечения данных из исходников, и становится возможным построение диаграммы Dataflow.
Как это выглядит на практике?

Допустим есть проект, который представляет из себя последовательность SQL -скриптов, исполняемые через hive и запускаемые через oozie. Сначала три скрипта готовят промежуточные данные, а последний – строит целевую витрину.

Запускающий файл выглядит так:

run-hive.sh:
hive -f $1


SQL -скрипты выглядят так:

insert into targetdb1.table1
select f1, f2
from
sourcedb.table1 t1 inner join sourcedb.table2 t2 on t1.id = t2.id


Есть oozie workflow, запускающая последовательно такие задачи:

1. Три параллельных скрипта, готовящих промежуточные данные;
2. Финальная задача, строящая витрину на основе таблиц из задачи 1

собственно, вот такой workflow:

<workflow-app name="Hive1" xmlns="uri:oozie:workflow:0.5">
    <start to="fork1"/>
    <kill name="Kill" />
<fork name="fork-1"></fork>
<join name="join-1" to="Project2"/>
    <action name="sql1">
        <shell xmlns="uri:oozie:shell-action:0.1">
            <exec>run-hive.sh</exec>
              <argument>project1/sql/sql1.sql</argument>
              <capture-output/>
        </shell>
        <ok to="join-1"/>
        <error to="Kill"/>
    </action>
    <action name="sql2">
        <shell xmlns="uri:oozie:shell-action:0.1">
            <exec>run-hive.sh</exec>
              <argument>project1/sql/sql2.sql</argument>
              <capture-output/>
        </shell>
        <ok to="join-1"/>
        <error to="Kill"/>
    </action>
    <action name="sql3">
        <shell xmlns="uri:oozie:shell-action:0.1">
            <exec>run-hive.sh</exec>
              <argument>project1/sql/sql3.sql</argument>
              <capture-output/>
        </shell>
        <ok to="join-1"/>
        <error to="Kill"/>
    </action> 
    <action name="Project2">
        <shell xmlns="uri:oozie:shell-action:0.1">
            <exec>run-hive.sh</exec>
              <argument>project2/sql/sql1.sql</argument>
              <capture-output/>
        </shell>
        <ok to="end"/>
        <error to="Kill"/>
    </action> 
    <end name="End"/> 
</workflow-app>


Вся папка проекта выглядит так:



После анализа проекта составляются три простых правила извлечения информации о Dataflow:

1. Workflow.xml и SH файл игнорируются, так как в них нет ничего существенного о Dataflow;
2. project1 и project2 транслируются как этапы проекта, которые в терминах in-out передают один другому данные (project1->project2);
3. Файлы SQL, лежащие в project1/ SQL и project2/ SQL транслируются через SQL-парсер.

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

val dataflow = parseSqlFolder(path = "project1/sql/", componentName = "sample.project1")
dataflow ++= parseSqlFolder(path = "project2/sql/", componentName = "sample.project2")


Это что-то типа DSL для описания проекта.

Такая запись утверждает, что все существенное для этого проекта надо искать только в папках с SQL. Для данного проекта этого достаточно.

Вот, что получается на выходе:



Как выяснилось, в проекте строятся две независимые витрины.

Та же самая информация может быть представлена по-другому, если она будет в виде in-out, а именно – какой компонент цепочки какие объекты данных потребляет и кому их дальше передает:



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

Что дает такой подход:

1. Для создания Dataflow диаграмм не требуется переделка процессов у заказчика. Данные извлекаются из существующих проектов. Не нужно создавать каталог данных, можно создавать каталог проектов. Кроме того, для применения этого подхода не нужна разработка какого-то глобального регламента работы с данными, как было бы в случае создания Data Catalog;
2. Построение диаграммы, описывающей проект, опирается только на исходные коды. Это значит, что такая диаграмма может показывать и те этапы, которые не попадают, например, в Data Catalog, так как происходят за границами, скажем, кластера;
3. Полученная диаграмма не устареет, так как опирается на исходные коды проекта и создается заново при открытии;
4. Так как основная работа в Big Data осуществляется через SQL, то простое подключение SQL-парсера (в данном случае Spark Catalyst) решает проблему поиска токенов, и после написания правил подключение второго, третьего и далее проектов происходит очень быстро;
5. Для описания проекта применяются не документация, а ряд правил, помогающих транслятору разбирать проект. Такие правила всегда есть, но обычно остаются в голове разработчика, который отвечает за проект. Здесь же они записаны и сохраняются. Это похоже на DSL того, как переводить проект в описание.

Недостатки такого подхода тоже очевидны:

1. Правила извлечения данных должны эволюционировать вместе с проектом;
2. То, что получается, описывает данный конкретный проект и вряд ли подходит для проектов другой структуры;
3. Это все-таки не Data Catalog, в котором есть много чего еще помимо построения диаграм Dataflow.

Этот проект можно рассматривать как своего рода замену или дополнение Data Catalog, раскрывающие процессы построения данных в разрезе проектов. Лучше всего применение Datalog показывает себя при анализе больших legacy-проектов с многолетней историей.
Источник: https://habr.com/ru/company/neoflex/blog/576034/


Интересные статьи

Интересные статьи

Привет читателям Хабра! Меня зовут Сергей Кузнецов, я руковожу отделом frontend-разработки в компании AGIMA. Сегодня мне бы хотелось поговорить про оптимизацию сайта...
Liquibase — это инструмент управления изменениями в базе данных. С его помощью вы можете отслеживать изменения в базе данных, сделанные с помощью SQL (или XML) скриптов. ...
Наш прошлый перевод про новые функции 15-й версии Node.js был очень хорошо принят читателями «Хабра», поэтому сегодня мы решили продолжить тему и рассказать, как настроить NVM с версией N...
Знакомьтесь, эталонная нота ля первой октавы (440 Гц): Звучит больно, не правда ли? Что еще говорить о том, что одна и та же нота звучит по-разному на разных музыкальных инструме...
Рис. 1. – Внешний вид 4-х ступенчатого термоакустического двигателя с бегущей волной В предыдущих статьях я писал о том, как построить двигатель Стирлинга без поршней, то есть о том, как пос...