Перейти к основному содержимому

Больше времени на кодинг, меньше времени на ожидание: Осваиваем defer в dbt

· 8 мин. чтения
Dave Connors

Представьте себе — у вас огромный проект dbt, тысячи моделей работают, создавая полезные инсайты для ваших заинтересованных сторон. Вам поступает запрос — модель нужно переработать! "Нет проблем," думаете вы, "Я просто внесу изменения и протестирую их локально!" Вы смотрите на свою родословную и понимаете, что эта модель находится на многих уровнях глубоко, погребенная под длинной цепочкой таблиц и представлений.

"Хорошо," думаете вы дальше, "Я просто выполню dbt build -s +my_changed_model, чтобы убедиться, что у меня все построено в моей dev-схеме, и я могу протестировать свои изменения". Вы запускаете команду. Ждете. Ждете еще. Берете кофе и полностью выходите из своего потока разработки dbt. Много времени и денег потрачено впустую, чтобы добраться до точки, где вы можете начать свою работу. Это не годится!

К счастью, функциональность defer в dbt позволяет вам строить только то, что вам нужно, и ничего больше. Эта функция помогает разработчикам тратить меньше времени и денег на разработку, помогая быстрее выпускать надежные продукты данных. dbt Cloud предлагает нативную поддержку этого рабочего процесса в разработке, так что вы можете начать использовать defer без дополнительных затрат!

Defer to prod или предпочесть slog

Многое из магии dbt основывается на элегантности и простоте функции {{ ref() }}, с помощью которой вы можете строить свой граф родословной, и как dbt может запускаться в разных средах — функции {{ ref() }} динамически компилируются в зависимости от настроек вашей среды, так что вы можете запускать свой проект в разработке и производстве без изменения кода.

Вот как простая {{ ref() }} будет компилироваться в разных средах:

-- в models/my_model.sql
select * from {{ ref('model_a') }}

Все это становится возможным благодаря manifest.json в dbt, артефакту, который создается каждый раз, когда вы запускаете команду dbt, содержащему всеобъемлющий и энциклопедический справочник по всем аспектам вашего проекта. Каждому узлу присваивается unique_id (например, model.my_project.my_model), и манифест хранит все метаданные об этой модели в словаре, связанном с этим id. Это включает в себя местоположение в хранилище данных, которое возвращается, когда вы пишете {{ ref('my_model') }} в SQL. Разные запуски вашего проекта в разных средах приводят к записи разных метаданных в манифест.

Давайте вернемся к гипотетической ситуации выше — что если мы воспользуемся производственными метаданными, чтобы читать данные из производства, чтобы мне не пришлось перестраивать все выше по потоку модели, которую я изменяю? Именно это и делает defer! Когда вы предоставляете dbt производственную версию артефакта manifest.json и передаете флаг --defer в вашу команду dbt, dbt разрешит функции {{ ref() }} для любого ресурса выше по потоку от выбранных вами моделей с использованием производственных метаданных — нет необходимости перестраивать то, что вам не нужно!

Давайте рассмотрим упрощенный пример — допустим, ваш проект выглядит так в производстве:

Упрощенный проект dbt, работающий в производстве.Упрощенный проект dbt, работающий в производстве.

И вам поручено внести изменения в model_f. Без defer вам нужно было бы как минимум выполнить dbt run -s +model_f, чтобы убедиться, что все зависимости выше по потоку от model_f присутствуют в вашей dev-схеме, чтобы вы могли начать запускать model_f.* Вы только что потратили кучу времени и денег на дублирование ваших моделей, и теперь ваше хранилище выглядит так:

Весь проект был перестро�ен в dev-схему, что может быть времязатратно и дорого!Весь проект был перестроен в dev-схему, что может быть времязатратно и дорого!

С defer мы не должны строить ничего, кроме моделей, которые изменились и теперь отличаются от их производственных аналогов! Давайте скажем dbt использовать производственные метаданные для разрешения наших ссылок и строить только ту модель, которую я изменил — эта команда будет dbt run -s model_f --defer .**

С использованием defer мы можем построить только одну модельС использованием defer мы можем построить только одну модель

Это приводит к гораздо более компактной сборке — мы читаем данные непосредственно из производственной версии model_b и model_c, и нам не нужно беспокоиться о построении чего-либо, кроме того, что мы выбрали!

* Другой вариант — запустить dbt clone -s +model_f, который создаст клоны ваших производственных моделей в вашей dev-схеме, используя клонирование без копирования, где это возможно. Ознакомьтесь с этим отличным блогом разработчиков от Дуга и Кшитиджа о том, когда использовать clone против defer!

** в dbt Core, вам также нужно указать dbt, где найти производственные артефакты! В противном случае он не знает, к чему откладывать. Вы можете использовать опцию --state path/to/artifact/folder, или установить переменную окружения DBT_STATE.

Встроенная поддержка defer в dbt Cloud

dbt Cloud предлагает бесшовный опыт defer как в dbt Cloud IDE, так и в dbt Cloud CLI — dbt Cloud всегда имеет последние артефакты запуска из вашей производственной среды. Вместо того чтобы проходить через болезненный процесс получения копии вашего последнего производственного manifest.json в вашу локальную файловую систему для defer, и создания конвейера для его постоянного обновления, dbt Cloud делает всю эту работу за вас. При разработке в dbt Cloud последний артефакт автоматически предоставляется вам под капотом, и dbt Cloud обрабатывает флаг --defer за вас, когда вы запускаете команды в "режиме defer". dbt Cloud будет использовать артефакты из среды развертывания в вашем проекте, отмеченной как Production в настройках среды как в IDE, так и в Cloud CLI. Убедитесь, что настроили производственную среду, чтобы разблокировать эту функцию!

В dbt Cloud IDE есть простой переключатель с надписью Defer to production. Просто включив этот переключатель, вы отложите вашу команду в производственную среду, когда вы запускаете любую команду dbt в IDE!

Переключатель defer to prod в IDEПереключатель defer to prod в IDE

В облачном CLI эта настройка включена по умолчанию — вам не нужно ничего делать, чтобы это настроить! Если вы предпочитаете не откладывать, вы можете передать флаг --no-defer, чтобы переопределить это поведение. Вы также можете установить среду, отличную от вашей производственной среды, как среду для defer в ваших настройках dbt-cloud в вашем dbt_project.yml:

dbt-cloud:
project-id: <Ваш id проекта>
defer-env-id: <Id среды>

Когда вы разрабатываете с dbt Cloud, вы можете сразу же использовать defer и полностью избежать ненужных сборок моделей в разработке!

Другие вещи, которые нужно знать о defer

Предпочтение состояния

Одной из основных ловушек в рабочем процессе defer является то, что когда вы находитесь в режиме defer, dbt предполагает, что все объекты в вашей dev-схеме являются частью вашего текущего рабочего потока, и будет отдавать предпочтение этим объектам перед производственными объектами, когда это возможно.

Давайте снова посмотрим на тот пример выше и представим, что некоторое время до того, как мы собирались внести это изменение, мы поработали над model_c, и у нас есть локальная копия model_c, находящаяся в нашей dev-схеме:

Гипотетическая начальная точка, с копией model_c в dev-схеме в начале цикла разработки.Гипотетическая начальная точка, с копией model_c в dev-схеме в начале цикла разработки.

Когда вы запускаете dbt run -s model_f --defer, dbt обнаружит копию model_c в dev-схеме и скажет: "Эй, знаешь, я думаю, что Дэйв работает над этой моделью тоже, и он, вероятно, хочет убедиться, что его изменения в model_c работают вместе с его изменениями в model_f. Поскольку я добрый и великодушный инструмент для трансформации данных, я позабочусь о том, чтобы его функция {{ ref('model_c') }} компилировалась с его изменениями в разработке!" Спасибо, dbt!

В результате, мы фактически увидим такое поведение, когда запустим нашу команду:

С версией model_a в dev-схеме, dbt будет использовать эту версию вместо deferС версией model_a в dev-схеме, dbt будет использовать эту версию вместо defer

Где наш код будет компилироваться из

# в models/model_f.sql
with

model_b as (
select * from {{ ref('model_b') }}
),

model_c as (
select * from {{ ref('model_c') }}
),

...

в

# в target/compiled/models/model_f.sql
with

model_b as (
select * from analytics.analytics.model_b
),

model_c as (
select * from analytics.dbt_dconnors.model_b
),

...

Смешение prod и dev моделей может быть не тем, что мы хотим! Чтобы избежать этого, у нас есть несколько вариантов:

  1. Начинайте с чистого листа каждый раз: Самый простой способ избежать этой проблемы — убедиться, что вы всегда удаляете свою dev-схему в начале новой сессии разработки. Таким образом, единственные вещи, которые появляются в вашей dev-схеме, это те, которые вы намеренно выбрали с помощью ваших команд!
  2. Предпочтение состояния: Передача флага --favor-state вашей команде говорит dbt "Эй, великодушный инструмент, иди вперед и используй то, что ты найдешь в производственном манифесте, независимо от того, что ты найдешь в моей dev-схеме", так что обе функции {{ ref() }} в примере выше указывают на производственную схему, даже если model_c находился там.

В этом примере model_c является реликтом предыдущего цикла разработки, но я должен быть ясен, что по умолчанию использование dev-отношений обычно является правильным курсом действий — как правило, PR в dbt охватывает несколько моделей, и вы хотите координировать свои изменения между этими моделями вместе. Это поведение может просто немного запутать, если вы сталкиваетесь с ним впервые!

Когда я не должен использовать defer to prod

Хотя defer является более быстрым и дешевым вариантом для большинства людей в большинстве ситуаций, defer to prod не поддерживает все проекты. Наиболее распространенная причина, по которой вы не должны использовать defer, это нормативные требования — defer to prod предполагает, что данные разделяются между вашими производственными и dev-средами, так что чтение между этими средами не является проблемой. Для некоторых организаций, таких как компании здравоохранения, существуют ограничения на доступ к данным и их обмен, которые исключают базовую структуру defer, представленную здесь.

Зовите меня Виллем Дефер

Виллем Дефо после использования флага `-—defer`Виллем Дефо после использования флага `-—defer`

Defer to prod — это мощный способ улучшить вашу скорость разработки с dbt, и dbt Cloud делает использование этой функции проще, чем когда-либо! Вы тоже можете выглядеть так круто, экономя время и деньги на разработке ваших проектов dbt!

Comments

Loading