Como usar Engenharia de Software, DevOps e Dados para criar um Data Lake na AWS

Nesse artigo, compartilho um projeto onde coloco em prática os meus conhecimentos e habilidades de Engenharia de Software, Dados e DevOps.

Mateus Moura
Data Hackers
11 min readMay 23, 2023

--

Foto de Afif Ramdhasuma na Unsplash

Introdução

Sou apaixonado pela área de tecnologia, tenho experiência nas áreas de Engenharia de Software, DevOps, Cloud e Dados, portanto reuni os conhecimentos de cada área para desenvolver um projeto end-to-end para a construção de um Data Lake na AWS de dados históricos da tabela FIPE. O objetivo do projeto é consolidar os dados de preços históricos de veículos no Brasil e disponibilizá-los em um Data Warehouse, todo o foco do projeto está no backend da aplicação, portanto diversas tecnologias e ferramentas são utilizadas, desde a criação do Web Scraping em Python até a infraestrutura feita com o Terraform.

Nas próximas seções, apresento cada uma delas e como foram utilizadas para tirar o projeto do papel e colocá-lo em produção.

O projeto está sendo disponibilizado no github através do link.

Arquitetura

Uma das primeiras etapas ao criar um projeto do zero é desenhar a arquitetura, é importante colocar todos os recursos que serão utilizados bem como um fluxo de início, meio e fim da aplicação. A figura 1 mostra o diagrama do projeto.

Figura 1: Arquitetura do projeto.

O primeiro passo é realizar um Web Scraping no site da FIPE usando Python e Requests, depois enviamos os JSONs extraídos para um Kinesis Firehose na AWS, que envia os dados para um bucket no S3, criando a primeira camada do nosso Data Lake, a camada bronze. Após a ingestão dos dados para a camada Bronze, os dados são convertidos de JSON para o formato .parquet pelo Glue e são salvos na camada Silver. Então, os dados podem ser consultados pelo Redshift Spectrum usando linguagem SQL ou por alguma ferramenta de BI.

Toda a infraestrutura foi criada por ferramentas de IaC (Infrastructure as Code), sendo elas o Terraform e o Servlerss Framework, além disso, todo o projeto está sendo construído na AWS através de um fluxo de CI/CD, pelo Github Actions.

Web Scraping

A primeira etapa do projeto consiste em obter os dados da tabela FIPE utilizando Python ou outra linguagem de programação. Uma vez que o site não disponibiliza nenhum tipo de API para a extração dessas informações, foi necessário realizar um processo de Web Scraping para consolidar os dados.

Para isso, foram utilizados diversos endpoints pelos quais o site faz requisições para obter os dados dos veículos em formato JSON. Então, uma classe para interagir com esses endpoints foi desenvolvida e o trecho de código abaixo representa parte dos métodos criados. É possível consultar todos os métodos no repositório do projeto no Github.

Por exemplo, para obter todas as marcas registradas no Brasil, pondemos realizar uma consulta HTTP do tipo post no endpoint “veiculos.fipe.org.br/api/veiculos/ConsultarMarcas”, como mostra a figura 2 no Postman.

Figura 2: Consulta de todas as marcas usando o endpoint da tabela FIPE.

Dado que toda requisição nos endpoints retornam os dados em formato JSON, é possível tratá-los usando Python e enviá-los para o Kinesis Firehose da AWS através do Boto3.

O arquivo app/get_car_infos.py contém a lógica principal e é executado por um Lambda na AWS, sendo ele responsável por chamar as classes da tabela FIPE e dos serviços da AWS, que se encontram no diretório helpers do projeto. A figura 3 demonstra uma execução local do código e a extração dos JSONs do site da tabela FIPE.

Figura 3: Exemplo da execução local do Web Scraping.

A lógica para realizar o Web Scraping tem diversos detalhes que não serão apresentados no artigo, já que tomaria muito tempo, porém todo o código está sendo disponibilizado no github e qualquer tipo de sugestão de melhoria, dúvidas ou comentários sobre o código são bem vindas.

AWS Lambda

A aplicação está hospedada no AWS Lambda [1], que é um serviço serverless onde toda a parte de servidor é abstraída e gerenciada pela AWS, facilitando o seu deploy e manutenção.

De maneira geral, a arquitetura de um AWS Lambda está sendo representada pela figura 4. Trata-se de um serviço disparado por eventos, sendo esses de diversos tipos, podendo ser um endpoint do API Gateway, mensagens no SQS ou SNS, um trigger com schedule ou até mesmo novos arquivos em um determinado Bucket, todos esses eventos vão executar o Lambda e uma determinada lógica de programação, podendo ela ser escrita em diversas linguagens, como Java, Go, PowerShell, Node. js, C#, Python, e Ruby [2].

Figura 4: Arquitetura geral do AWS Lambda.

Para interagir com os serviços da AWS, como o Kinesis Firehose, foi utilizado o boto3 [3].

Serverless Framework

Uma das maneiras de criar o AWS Lambda é através do serviço de IaC da AWS, o Cloudformation, onde templates em JSON são gerados para a criação dos diversos serviços [4]. Mas para o Lambda, existe o Serverless Framework do Node.JS onde é possível gerar templates através de arquivos de configurações .yml, como mostra o código abaixo.

Nesse arquivo, declaramos qual é o nome do AWS Lambda, as configurações, como o runtime (Python, Node, Ruby e etc), todas as permissões que a aplicação precisará para interagir com os serviços da AWS e qual arquivo .py deverá ser executado pelo Lambda. No projeto, o arquivo serverless.yml faz a configuração e aponta para a aplicação get_car_infos_api.py, ou seja, sempre que o Lambda ativar, vamos executar a lógica presente no arquivo.

Após ter o arquivo de configuração criado, para fazer o deploy através do framework, basta executar o comando no terminal “sls deploy” (desde que o node e o serverless framework estejam instalados) e acompanhar o deploy, como exemplifica a figura 5.

Figura 5: Exemplo do deploy do Lambda usando Serverless Framework

A figura 6 mostra o AWS Lambda após finalizar o deploy. Portanto, toda a aplicação para extração dos dados da tabela FIPE foi criada em Python e está em produção na AWS.

Figura 6: AWS Lambda Console

Como a AWS e seus recursos foram utilizados para a construção do projeto

A AWS é um provedor de computação em nuvem, que oferece diversos serviços e recursos como servidores com a EC2, armazenamento com o S3, Machine Learning com o Sagemaker, funções lambdas para a construção de microsserviços serverless e etc [5].

No projeto, usamos algum desses serviços, o objetivo não é explicar em detalhes cada um deles, portanto referências serão deixadas para uma leitura mais aprofundada.

AWS S3

O S3 é um serviço de armazenamento da AWS onde podemos armazenar objetos, podendo ser arquivos estruturados, semiestruturados e não estruturados, como CSV, JSON, áudio, imagem, textos e etc.

No projeto, o S3 foi utilizado para a construção do Data Lake, sendo dividido em duas camadas, a camada Bronze e a Silver. Na Bronze, criamos o bucket “fipe-project-bronze-layer“ para o armazenamento dos dados extraídos do site da FIPE no formato JSON, que são enviados através do Kinesis Firehose, representado na figura 7.

Figura 7: Camada Bronze do Data Lake.

Uma vez que os dados raw estão na camada Bronze, criamos um Job no Glue que converte os arquivos para o formato .parquet, a fim de aumentar a performance de leitura dos arquivos por parte do Redshift, como mostram as figuras 8 e 9.

Figura 8: Fluxo da ingestão de dados no Data Lake.
Figura 9: Camada Silver do Data Lake.

Kinesis Firehose

O Kinesis Firehose é um serviço de Extração e Carregamento (ETL — Extract, Transform and Load) de dados para um Data Lake, seu pipeline pode ser representado pela figura 10 [6]. No projeto, a etapa de ingestão é executada pelas funções lambdas que realizam o web scraping e enviam os dados no formato JSON para o Kinsesis Firehose, sendo responsável por agregá-los e carregá-los na camada bronze do Data Lake.

Figura 10: Fluxograma geral do Kinesis Firehose.

Glue

O Glue é um serviço utilizado no projeto para realizar o ETL entre a camada Bronze e Silver, onde sua principal função é converter os dados do formato CSV para o formato Parquet, a fim de aumentar a performance de leitura dos arquivos JSON [6].

Redshift

O Redshift é um Data Warehouse gerenciado pela AWS onde é possível realizar queries em SQL para analisar os dados de um Data Lake. No projeto, foi utilizado o Redshift Spectrum, que é capaz de se conectar com a camada Silver do Data Lake e realizar consultas nos arquivos .parquet usando SQL.

Infraestrutura como Código — Terraform

Toda a infraestrutura do projeto, exceto a etapa do Glue, foi criada usando o Terraform, trata-se de uma ferramenta de IaC (Infrastructure as Code) onde podemos automatizar a construção de recursos nos provedores de computação em nuvem usando código [7]. A linguagem do Terraform é do tipo declarativa, onde declaramos blocos de objetos de cada recurso e, no momento da execução do Terraform, ele interage com as APIs de integração dos provedores como a AWS, Azure e GCP para criar os serviços.

A vantagem de usar uma ferramenta como essa está na mitigação de falhas manuais, pois uma vez que os serviços de Cloud estão declarados por códigos, o desenvolvedor consegue criar diversos recursos iguais (com pequenas diferenças, como o nome ou tags) de forma automatizada, isso mitiga a possibilidade de falha humana, já que a chance de se esquecer alguma etapa ao criar o recurso é mínima. Outra vantagem é a de escalabilidade, já que é possível replicar toda a infraestrutura em contas, projetos ou escopos diferentes, trazendo dessa forma uma segurança maior no processo de deploy da infraestrutura do projeto.

O Terraform funciona por linhas de comandos, e devemos executá-los para criar a infraestrutura, os principais comandos são:

terraform init: Para inicializar o Terraform de acordo com o provedor declarado;

terraform plan: Esse comando gera um plano de execução dos recursos que o Terraform pretende criar;

terraform apply: Executa a ação de criar os recursos na nuvem;

terraform fmt: Esse comando formata o código dos arquivos .tf de acordo com a convenção da linguagem, como alinhar os sinais de igual (“=”).

Além da execução dos comandos, é necessário criar alguns arquivos iniciais para trabalhar com a ferramenta, por exemplo, declarar o tipo de provedor que vamos usar, como mostra o código abaixo.

Boas Práticas

O Terraform é uma das minhas ferramentas preferidas para se trabalhar e daria para criar um artigo falando só dela e de suas vantagens, porém, é importante escrever sobre as principais boas práticas do Terraform.

Terraform Backend

Sempre que criamos a infraestrutura com o Terraform, o arquivo terraform.tfstate será gerado. Basicamente, esse arquivo é um JSON que contém a “foto” dos recursos criados na AWS, isso permite que a ferramenta identifique mudanças nos arquivos com a extensão .tf e gere um plano de execução com as ações de criar, atualizar ou deletar os recursos, por exemplo: ao declarar um objeto em algum arquivo .tf com os parâmetros de um bucket no S3, o Terraform consulta o arquivo de estado e identifica que o bucket é um recurso novo a ser construído, portanto ele gera um plano de execução, preservando os demais recursos e retorna uma ação de criar o bucket em questão.

Porém, não é uma boa prática compartilhar esse arquivo com outros desenvolvedores, por isso podemos usar o backend remoto do Terraform, que nada mais é que um bucket na AWS onde vamos armazenar esse arquivo de estado. Dessa forma, sempre que algum desenvolvedor precisar mexer na infraestrutura, basta executar o comando terraform init que o arquivo será baixado para a máquina da pessoa e será possível fazer atualizações na infraestrutura. Um exemplo de como declarar esse arquivo está representado no código abaixo.

Uso de variáveis

Uma das vantagens de se usar o Terraform é criar variáveis que serão utilizadas por todos os recursos ao longo do código. O código abaixo exemplifica um bloco do tipo locals onde podemos declarar as tags que todos os recursos terão em comum, como por exemplo o departamento, projeto e Owner.

Fluxo de Deploy com o Github Actions (CI/CD)

Construir um projeto do zero é sempre um desafio, já que diversos recursos, códigos e integrações precisam ser criadas e testadas, uma maneira de fazer todo o build do projeto de maneira automatizada é usar alguma ferramenta de CI/CD (Continuous Integration/Continuous Delivery) como o CircleCI, Jenkins, Github Actions e etc. No projeto, foi utilizado o Github Actions já que todo o código fonte está hospedado Github.

A vantagem de se usar uma ferramenta de CI/CD é que conseguimos fazer o deploy de diversas aplicações e infraestruturas de maneira automatizada, mitigando dessa forma, possíveis erros humanos, além de ser fácil de replicar para outros projetos.

Como usamos o CI/CD do github Actions

Para usar o CI/CD do github actions, basta criar um diretório .github/workflows na raiz do projeto e declarar o fluxo de deploy em arquivos de configuração do tipo .yml. No projeto, temos um arquivo para fazer o deploy do Lambda na AWS “serverless_application.yml”, nele usamos uma imagem Docker com Node.js, instalamos o serverless framework e depois realizamos o deploy com o comando sls deploy.

No arquivo “terraform_infrastructure.yml”, temos o deploy da infraestrutura do projeto usando o Terraform, e para isso, usamos uma imagem Docker com o Terraform instalado e executamos os comandos de deploy da ferramenta.

Em ambos os casos, a execução do pipeline só acontece quando for realizado um merge na branch main.

Resultados

Com todos os recursos criados e em produção, podemos consultar os dados na camada Silver do Data Lake usando o Redshift Spectrum. Como exemplo, podemos executar a seguinte query no próprio console do Redshift Spectrum para analisar a evolução do preço de algum veículo, por exemplo, o Renault Kwid.

O gráfico da evolução do preço do Kwid está sendo representado pela figura 11.

Figura 11: Preço do Renault Kwid

Além disso, é possível analisar outras métricas, como por exemplo contar o número de marcas distintas presentes na tabela FIPE ou até mesmo selecioná-las, como mostra a figura 12.

Figura 12: Marcas registradas na tabela FIPE.

Conclusão

Desenvolver um projeto end-to-end usando Engenharia de Software, Dados e DevOps não é uma tarefa simples, pois envolve muitos detalhes em cada etapa, porém o aprendizado é muito grande, já que podemos aplicar na prática nossos conhecimentos e ter contato com ferramentas nunca utilizadas antes, por exemplo o Github Actions, AWS Glue, Kinesis Firehose e Redshift, que precisei aprender a usar do início, sendo que com alguns tutoriais e seguindo a documentação, pude aprender a usar as ferramentas e integrá-las no projeto.

Em suma, o projeto mostra o um pouco de como construir um data lake, criar uma aplicação em Python para fazer o web scraping, como usar o Terraform e a AWS para a construção de um projeto completo e em produção na nuvem.

Referências

[1] https://docs.aws.amazon.com/lambda/latest/dg/welcome.html

[2] https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html

[3] https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/firehose.html

[4] https://aws.amazon.com/cloudformation/

[5] https://docs.aws.amazon.com/whitepapers/latest/aws-overview/introduction.html

[6] https://docs.aws.amazon.com/glue/latest/dg/add-job.html

[7] https://developer.hashicorp.com/terraform/docs

--

--