Plataforma de Dados — Solução para Ingestão (Parte 3)

Rubens Minoru Andako Bueno
6 min readJan 30, 2021

--

Não podemos falar de uma Plataforma de Dados sem pensar também em uma camada de ingestão. É dela que vem a maior parte da descentralização do modelo tradicional de equipes de BI e também é com ela que daremos um passo rumo ao Real-Time e tornaremos possível a construção de Aplicações de Dados mais reativas.

Antes de arquitetar a camada de ingestão, tracei os principais objetivos que gostaria de resolver:

  • Automatização completa da ingestão, minimizando a necessidade de centralização por equipes de Engenharia de Dados de qualquer parte do processo
  • Disponibilização mais próxima possível do Real-time para consulta analítica do dado e seu histórico
  • Suporte a construção de Produtos de Dados reativos e próximos do Real-Time

Plataforma de Streaming

Decidimos começar a construção da Camada de Ingestão pelo local onde o dado irá transitar até ser persistido na nossa Memória Permanente (S3). Precisávamos transitar o dado com a menor latência possível para nos aproximar do Real-Time e tornar possível também a consulta por outros sistemas e equipes.

Na plataforma de streaming, as premissas são que o dado irá trafegar com baixíssima latência, com garantia de não perder a informação da ordem de chegada do dado e com possibilidade dar volatilidade à esse dado para evitar custos desnecessários.

E quando falamos de Big Data, a escolha é quase óbvia: Apache Kafka. Vamos elencar algumas das suas características que tornam ela a primeira escolha nesse assunto:

  • Ferramenta distribuída
  • Garantia de ordem no consumo do dado
  • Armazenamento do dados tolerante à falhas
  • Processamento reativo do dado
  • Abstrações úteis dentro do universo de dados (KStream/KTable)
  • Conformidade ao ecossistema de BigData corrente

E para estar alinhado às melhores práticas na utilização da ferramenta, segregamos os dados que irão compor cada tabela da nossa Camada de Consumo em tópicos no Kafka, nos preocupando em garantir que os dados de um mesmo tópico tenham uma estrutura compatível entre si.

Governança da Estrutura

Com a ciência de que o dado trafegando na Plataforma de Streaming irá compor uma tabela da camada de consumo, então precisamos adequar ao máximo esse dado no formato tabular. E quando falamos em formato tabular, estamos falando em:

  • Estruturas em Linha
  • Tipagem
  • Constraints
  • Garantias de compatibilidade na evolução da estrutura

A opção mais fácil seria pensar em trafegar o dado em um formato livre de estrutura, tal qual JSON, sem constraints, tipagem quase inexistente e sem suporte nativo a evolução de estrutura. Porém é sabido que quando um dado já está em repouso, o custo para consertá-lo é muito maior, e por isso faz sentido pensar em uma estrutura com um contrato mais forte e com as garantias acima mencionadas.

Dentre as opções que estão disponíveis, as principais eu poderia dizer que são: Avro e Protobuf. A internet está recheada de benchmarks entre estes dois formatos, muitos deles apontando pouca diferença significativa em tempo de serialização/deserialização e compressão do dado, restando apenas a diferença na definição e gestão da estrutura.

No Protobuf, a definição da estrutura ocorre através de um arquivo de formato próprio, denominado de .proto, e que geralmente é compilado junto ao código que irá utilizar essa estrutura para serializar e desserializar o dado. O Avro, por outro lado, possui uma definição de estrutura mais simples e que pode ser transcrita em.json, facilitando sua leitura por humanos e retirando a necessidade de se aprofundar em uma linguagem de domínio nova.

Além disso, o Avro conta no seu ecossistema com uma ferramenta chamada Confluent Schema Registry, que permite que o armazenamento e gestão das estruturas dos dados em um único lugar. Essas estruturas também são disponibilizadas para as aplicações através de uma API, tornando na maioria dos casos desnecessário recompilar o código ao alterar a estrutura.

Lembra que os principais objetivos da camada de ingestão são: autonomia e automatização? Nesse caso então optamos por serializar todos os dados trafegando no Apache Kafka em Avro por essa autonomia de poder alterar diretamente a estrutura deste através de um formato conhecido (.json).

Proxy

Agora que já definimos o lugar e a forma que o dado vai trafegar, resta ainda saber por onde ele vai chegar. É possível encontrar inúmeros clientes de Apache Kafka e para o Confluent Schema Registry nas mais diversas linguagens, capazes de em poucas linhas de código atingir seu objetivo.

Na prática, contudo, encontrei muita resistência entre as equipes para integrarem seus sistemas com o Apache Kafka e o com Avro, e por isso acabamos decidindo por facilitar a vida de todos colocando um Proxy HTTP REST. A Confluent mesmo já disponibiliza uma ferramenta open-source que cumpre esse objetivo, transformando uma requisições HTTP com o dado em JSON em eventos Avro e populando um tópico do Apache Kafka. Desta forma, bastaria as equipes implementarem um simples client HTTP para começar a popular os tópicos com dados em Avro no Apache Kafka.

Persistência

Nesse momento, temos uma forma fácil de coletar os dados, uma plataforma de streaming onde todos os dados estão trafegando em Real-Time, e temos a garantia de conformidade do dado com as estruturas definidas através do Avro e o Confluent Schema Registry. Nos resta agora levar esse dado da Plataforma de Streaming para a Memória Permanente da nossa camada de consulta para que este dado esteja então disponível para consulta através da Arquitetura definida na parte 2 desse artigo.

Algumas ferramentas de mercado já fazem esse trabalho, como o Kafka Connect da Confluent, o Gobblin da Apache ou o Secor do Pinterest. Porém na minha experiência com elas, nenhuma atendeu a todos os requisitos exigidos, esbarrando em questões de performance ou, em alguns casos, na geração de arquivos com tamanho não customizáveis que afetavam muito a Engine de Consumo. Foi então que decidimos construir a própria ferramenta: o Dumping Machine.

O objetivo principal da ferramenta é trafegar o dado do armazenamento transitório (Apache Kafka) para o armazenamento estacionário (S3/HDFS). Nesta transição, nós também precisamos que:

  • O dado que está em Avro seja transformado em Parquet para atender o desempenho ótimo em consultas analíticas
  • Capacidade de traduzir a estrutura do Avro para o Hive Metastore, automatizando a criação de novas tabelas e a atualização da estrutura de tabelas com base na alteração da estrutura em Avro
  • Adicionar cada nova partição para que o novo dado seja reconhecido pelas Engines de Computação

O Dumping Machine tem servido a esse propósito por um bom tempo, e em todos os casos com desempenho superior ao das outras ferramentas, sendo portanto a escolha mais óbvia.

Agora com o dado traduzido em Parquet na nossa Memória Permanente (S3) e com a estrutura e os metadados atualizados no Gerenciador de Catálogo (Hive Metastore), esse dado já está disponível para consulta junto com todo o resto.

Dessa maneira, qualquer equipe de engenharia agora pode enviar seus dados através de uma simples requisição no nosso REST Proxy, em JSON, de modo que esse dado irá ser persistido em uma tabela na nossa Memória Persistente e estará disponível para consultas analíticas através da Engine de Consumo. E mais, esse dado também irá transitar na nossa Plataforma de Streaming ao lado dos dados de todas as outras equipes, impulsionando ainda mais possibilidades de construir aplicações que irão consumir todos esses dados para tomada de decisões em tempo real.

--

--