DBT Core com DataBricks SQL No Serverless

Murilo Belarmino
Warren Tech
Published in
6 min readNov 7, 2022

Por que e como usamos o DBT para transformar nossos dados?
Artigo escrito em conjunto com a Karinne Cristina

Com a crescente popularidade dos data warehouses na cloud, como Snowflake, BigQuery e agora o Databricks entrando nesse mercado, o SQL se tornou a língua franca para transformação de dados, uma vez que esses warehouses são extremamente confiáveis, eficientes em custo, além do SQL possuir uma barreira técnica muito menor do que linguagens como scala ou mesmo pyspark. Neste cenário, o DBT nasce para melhorar e ampliar as capacidades dos pipelines puramente escritos em SQL.

Primeiro, precisamos começar com um disclaimer:

Não, o DBT não é mais uma ferramenta plug-and-play de dados com um logo colorido que se encaixa em uma data stack, mas sim uma das fundações da stack.

Aqui na Warren, utilizamos desde sempre SQL para nossas tasks de transformação, antes com o EMR da AWS + Airflow utilizando PySpark SQL, e agora com o Databricks SQL + Databricks Workflows em conjunto com o DBT para desenvolvimento e orquestração das transformações.

Sim, o DBT nos ajuda a definir dependências entre modelos (arquivos SQL são chamados de modelos em um projeto usando DBT), o que é muito mais fácil do que criar uma task para cada script no Apache Airflow. Para isso, nós só temos que utilizar uma função de referência, e nossa dependência entre modelos é criada. Por exemplo, se tivermos um modelo chamado ‘my_first_dbt_model’ que consome dados de nossas fontes (camada silver do delta lake) e um segundo modelo que depende deste, podemos referenciá-lo da seguinte forma:

--script do segundo modeloselect * from {{ ref('my_first_dbt_model') }}

Automaticamente, esta dependência é criada e, ao executarmos nosso projeto, podemos ver que a ordem de execução é seguida corretamente:

Além de nos ajudar na execução do pipeline, o DBT também nos é muito útil para documentar nossos projetos e transformações, além de gerar um lineage entre modelos que nos ajuda a entender de forma visual a modelagem de dados feita. Acredite, o lineage ajuda horrores na manutenção do pipeline!

Para os modelos exemplo citados anteriormente, o lineage ficaria assim:

Este print acima é retirado diretamente da documentação do projeto, que é outro ponto incrível do DBT. É possível gerar uma documentação bem completa e modular, basta apenas configurar os arquivos .yml corretamente, assim como o próprio DBT labs recomenda.

Por último, o DBT nos permite fazer uma separação de ambientes de forma muito simples. Utilizando o jinja e configurando corretamente o arquivo profiles.yml, conseguimos executar nosso projeto em dev ou stage apenas alterando um parâmetro:

dbt run --target dev #execução em devdbt run --target stg #execução em stg

Temos também parâmetros que nos permitem executar o downstream e upstream do pipe, além de executar um modelo individualmente ou por pastas: a escolha vai a gosto do freguês.

DataBricks SQL No Serverless

A seguir, vamos mostrar como trabalhamos com o DBT no DataBricks e quais foram os desafios enfrentados durante o desenvolvimento. O único pré-requisito é que você tenha um conhecimento prévio utilizando o SQL warehouse e os workflows do DataBricks.

Para mais detalhes de tudo que vai ser explicado daqui em diante, consulte a própria documentação

Hora de botar a mão na massa

Para começar, vamos criar um job do tipo DBT:

Precisamos informar o nome da task, o tipo de job e o source, que é o repositório onde está o seu projeto. Para o nosso exemplo vamos utilizar o github.

Agora, vamos escolher quais os comandos do DBT queremos executar (podemos adicionar parâmetros também).

A própria documentação do DataBricks recomenda a utilização do SQL warehouse, que, resumidamente, é um recurso de computação que permite executar comandos SQL e onde vamos testar e consultar os resultados gerados pelo DBT.

E é nesse ponto que nos deparamos com o nosso maior desafio. Lendo a documentação e durante os primeiros testes, observamos que, na hora de selecionar as opções de warehouses, o aviso é bem claro “Apenas o SQL Warehouse Serverless é suportado”. E você deve estar se perguntando: qual o problema há nisso?

No databricks temos 2 tipos de SQL Warehouse:

  • Classic: A inicialização do cluster leva em média cerca de 5 a 7 minutos.
  • Serverless : O tempo de inicialização do cluster é instantâneo.

Olhando apenas para essas diferenças, não teríamos nenhum problema de escolher a segunda opção, pelo contrário, ganharíamos tempo. Porém, nem tudo são flores, e esse ganho de tempo tem um custo bem significativo.

No modelo pay-as-you-go premium na AWS, a classic compute custa $0.22 / DBU, enquanto a serverless compute custa $0.70 / DBU (na região US east — N.Virginia).

Resumindo, o serverless custa aproximadamente 4 vezes mais do que a classic, e, conversando com algumas pessoas da comunidade, esse é o principal ponto que pesa na hora de utilizar o DBT no DataBricks, inclusive para nós na Warren.

Solução:

Junto ao aviso, temos uma outra opção: None (Manual), que na documentação está descrita como uma opção mais avançada para executar todo SQL gerado pelo DBT com um único cluster. E mais uma vez você deve estar se perguntando: beleza, mas como isso resolve o problema do SQL warehouse serverless?

Aqui começa de fato a solução do nosso problema:

1º — Precisamos criar um SQL warehouse (não vou detalhar esse passo a passo aqui, mas essa documentação pode ajudar).

2º — Basicamente, ao escolher a opção None (Manual), precisamos criar um arquivo profiles.yml na raiz do nosso projeto no git com a seguinte estrutura:

Exemplo do arquivo profiles.yml

Onde:

  • <schema> -> vai ser o nome do esquema para as tabelas do projeto
  • <http_host> -> o hostname do SQL warehouse.
  • <http_path> -> o path HTTP do SQL warehouse.

Todas essas informações você encontra nos detalhes de conexão do SQL warehouse que você criou no primeiro passo. O token não precisa ser informado, porque ele será preenchido automaticamente em tempo de execução com base nas informações fornecidas anteriormente.

Voltando para o passo a passo, agora só precisamos informar o caminho onde se encontra o arquivo profiles.yml

Dessa maneira, conseguimos passar as configurações de qualquer warehouse e contornar um dos pré requisitos, que era ter SQL Warehouse Serverless.

Pra finalizar, só falta escolher as configurações do cluster e as dependências.

Não podemos afirmar que essa solução vai funcionar para todo mundo, mas, para o nosso caso de uso até o momento, não encontramos nenhuma limitação. O único ponto de atenção é que todas as tarefas do DBT vão executar em um único cluster e, quanto mais tarefas, mais tempo esse cluster vai ficar ligado. Por isso, ter uma configuração de cluster coerente ajuda a não ter surpresas com os custos.

Próximos passos:

Nos exemplos mostrados até o momento, utilizamos a interface do DataBricks, que é uma das maneiras de criar jobs. É uma maneira bem simples, mas não é escalável, à medida que o número de workflows aumenta. No próximo artigo, vamos falar um pouco mais da nossa arquitetura e como utilizamos o terraform para gerenciar nossos jobs.

--

--