{"id":20381605,"url":"https://github.com/douglasmoraisdev/python_etl","last_synced_at":"2025-06-10T23:07:04.154Z","repository":{"id":211454165,"uuid":"249563108","full_name":"douglasmoraisdev/python_etl","owner":"douglasmoraisdev","description":"A proposta apresentada consiste em uma conjunto de 3 micro serviços desenvolvidos em Python. Cada um responsável por uma etapa distinta do ETL (Extração, Transformação e Carregamento)","archived":false,"fork":false,"pushed_at":"2020-03-23T23:03:54.000Z","size":115,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-04T22:36:08.173Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/douglasmoraisdev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2020-03-23T23:01:42.000Z","updated_at":"2020-03-23T23:03:57.000Z","dependencies_parsed_at":"2023-12-08T16:50:53.889Z","dependency_job_id":null,"html_url":"https://github.com/douglasmoraisdev/python_etl","commit_stats":null,"previous_names":["douglasmoraisdev/python_etl"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/douglasmoraisdev%2Fpython_etl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/douglasmoraisdev%2Fpython_etl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/douglasmoraisdev%2Fpython_etl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/douglasmoraisdev%2Fpython_etl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/douglasmoraisdev","download_url":"https://codeload.github.com/douglasmoraisdev/python_etl/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/douglasmoraisdev%2Fpython_etl/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259166965,"owners_count":22815591,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-15T02:14:28.367Z","updated_at":"2025-06-10T23:07:04.134Z","avatar_url":"https://github.com/douglasmoraisdev.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ETL Python\n\n## Solução proposta\n\nA proposta apresentada consiste em uma conjunto de 3 micro serviços desenvolvidos em Python. Cada um responsável por uma etapa distinta do ETL (Extração, Transformação e Carregamento)\n\nOs micro serviços e o restante da arquitetura proposta tem como principal objetivo possibilitar o *balanceamento* e a *escalabilidade* do sistema para atender em especial o requisito:\n\n\u003e Os dados enriquecidos são utilizados em nosso produto exponencial e de alta demanda, e pode ser necessário processar milhões de novas coordenadas por dia.\n\n*Escalabilidade*: É possível instanciar *n* em paralelo sem que haja conflito ou inconsistência nos dados processados. Isso se deve graças a arquitetura, utilizando sistemas como filas de mensagens(RabbitMQ) e cache(Redis) para evitar reprocessamentos e perda de dados.\n\n*Balanceamento*: Por se tratar de serviços interdependentes, é possível *subir* diferente quantidades e *threads* para cada serviço conforme a demanda. \nPor exemplo, se o processo de Extração estiver demandando mais processamento, é possível instanciar mais serviços *Extractor*. Por outro lado, se o processo de Load estiver demandando mais processamento, é possível instanciar mais serviços *Loader*, etc.\n\n## Arquitetura\n\nA arquitetura conta com:\n* 3 micro serviços em Python (Extractor, Transformer e Loader)\n* Redis: Sistema de Cache em RAM, utilizado no Extractor para evitar download e extrações de arquivos repetidamente\n* RabbitMQ: Sistema de Gerenciamento de Filas de Mensagens, utilizado por todos os micro serviços. Faz a ponte de comunicação entre os serviços, \"avisando\" a etapa seguinte que deve processar dados da etapa anterior em tempo real.\n* Google GeocodingAPI: Fornece os dados para enriquecimento dos dados (endereços completos)\n* MongoDB: Utilizado como banco de dados *Lookup*. Possibilita que o serviço *Loader* efetue *bulk inserts* e *bulk updates*, melhorando a performance na inserção de dados no DW.\n* FTP: Utilizado para simular um *Datasource*\n* Mysql: Utilizado como Data Warehouse\n\n\n![Imagem disponivem em /doc/arquitetura_etl4all.png](doc/arquitetura_etl4all.png)\n\n### Fluxo de dados\n\n#### Extractor\n* Efetua varreduras no servidor FTP, através de *loops* com tempo de intervalo definidos em configuração.\n    * Ao encontrar arquivos para download:\n        * Instancia uma nova thread(subprocesso) para efetuar o donwload e extração de cada arquivo, um arquivo por thread.\n        * Extrai **Latitude** e **Longitude** dos arquivos.\n        * Salva os dados extraidos em disco no formato comma-separated values (csv).\n        * Posta os arquivos processados no Rabbit para ser posteriormente processado pelo *Transformer*.\n        * Adiciona os arquivos ao cache Redis para evitar download e processamentos desnecessários. \n\n#### Transformer\n* Instancia *n* threads(subprocesso), definidos em configuração, cada uma das threads abre um *Listener*, escutando as filas do RabbitMQ a procura de arquivos processados pelo *Extractor*.\n    * Thread, ao encontrar os arquivos no Rabbit:\n        * Carrega o arquivo do disco.\n        * Faz chamadas a GeocodingAPI do GoogleMaps para obter endereços completos, passando como parametro latitudes e longitudes obtidas dos arquivos processados pelo *Extractor*.\n        * Salva os dados enriquecidos em disco no formato csv.\n        * Posta os arquivos processados no Rabbit para ser posteriormente processado pelo *Loader*.\n    * Permanece \"escutando\" as filas do Rabbit em busca de mensagens de arquivos a processar.\n\n#### Loader\n* Instancia *n* threads(subprocesso), definidos em configuração, cada uma das threads abre um *Listener*, escutando as filas do RabbitMQ a procura de arquivos processados pelo *Transformer*.\n    * Thread, ao encontrar os arquivos no Rabbit:\n        * Carrega o arquivo do disco.\n        * Verifica se o registro já existe no banco de dados *Lookup* (MongoDB)\n            * Caso exista, adiciona o registro a lista de UPDATE\n            * Senão, adiciona o registro na lista de INSERT, e atualiza o Lookup.\n        * Executa a lista de INSERT e UPDATE no Data Warehouse (Mysql).\n    * Permanece \"escutando\" as filas do Rabbit em busca de mensagens de arquivos a processar.\n\n## Runbook\n\n### Script do Banco de Dados\n\nO script de criação do banco de dados se encontra em **/docs/**\nMais informações sobre o como acessar o Mysql CLI na sessão **Visualizando  os Dados*\n\n\n### Subindo a aplicação\n\nSeguir as seguintes etapas para subir o sistema de ETL:\n\n**Na raiz do diretório /avaliacao**:\n\n* 1º - Subir a stack segundária (bancos de dados, caches, etc)\n\n    `$ docker-compose up rabbitmq mysql ftp_files_ds mongo mongo-express redis`\n\n* 2º - Subir a stack dos micro serviços\n\n    `$ docker-compose up extractor transformer loader`\n\nNo terminal utilizado para subir a stack dos micro serviços é possivel acompanhar os logs de execução de cada microserviço.\n\n* ***Opcional*** - Escalonar os micro serviços\n\n    `$ docker-compose scale extractor=4 transformer=5 loader=3`\n\n\n### Adicionando arquivos para processamento\n\nÉ utilizado um container de FTP para simular um Datasource.\n\nPara adicionar arquivos para processamento, basta acessar o servidor FTP, utilizando a ferramenta de sua escolha (ex.: FileZilla) e fazer upload dos arquivos data_points.txt para o diretório raiz do usuário.\n\n\u003e Dados de acesso também disponíveis no docker-compose.yml\n\n``Servidor FTP: localhost (0.0.0.0)``\n\n``Usuario: username``\n\n``Senha: mypass``\n\n### Visualizando os dados\n\nÉ utilizado um container de Mysql para simular o Data Warehouse.\nÉ necessário entrar no container via *bash*, e executar SELECTS no Mysql Client:\n\nMais informações em: https://docs.docker.com/engine/reference/commandline/exec/\n\n\n\u003e Dados de acesso também disponíveis no docker-compose.yml\n\n* Lista os ids dos containers:\n\n    `$ docker ps`\n\n* Acessa o container via *bash*\n\n    `$ docker exec -it \u003chash_id_do_container_mysql\u003e bash`\n\n* Dentro do container, executar o Mysql CLI:\n\n    `$ mysql -u root -p`\n    \n    ``Senha root: example``\n\n    ``Schema (nome do banco de dados): etl4all``\n\n    ``Tabela: address``\n\n\n* Query de exemplo:\n    \n    `SELECT * FROM address`\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdouglasmoraisdev%2Fpython_etl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdouglasmoraisdev%2Fpython_etl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdouglasmoraisdev%2Fpython_etl/lists"}