O blog da AWS
Data Lake transacional na AWS usando o Debezium, AWS Glue e Apache Iceberg
Por Isabela Gherson Monteiro, Arquiteta de Soluções, AWS Brasil Setor Público;
e Thiago da Hora, Arquiteto de Soluções Sênior, AWS LATAM Setor Público
Cada vez mais, vemos as empresas motivadas a adotarem estratégias data-driven, com o objetivo de otimizar seus resultados, ao tornarem seu processo de tomada de decisões mais informado e assertivo a partir da análise de dados organizacionais e públicos.
Para manter uma cultura orientada a dados (data-driven), é necessário construir mecanismos para coleta, armazenamento, preparação e análise de dados que usualmente contam com repositórios de dados centralizados como Data Lakes e Data Warehouses e a construção desse tipo de infraestrutura tem se tornado cada vez mais comum na nuvem AWS.
É comum, nesses cenários, trazer dados de diferentes fontes para o Data Lake. Muitas vezes é feita uma migração completa de bancos de dados de origem para a nuvem, no entanto, são muitos os casos onde a fonte de dados não pode ser migrada ou não é gerenciada pelo cliente e existe uma atualização contínua daquela base. Nesses casos, faz-se necessário a implementação da estratégia de CDC (ou Change Data Capture).
O CDC é o processo de replicação contínua de dados a partir da captura de atualizações nas fontes de dados. Com essa estratégia, é possível não só migrar os dados para um Data Lake, como também atualizá-lo conforme são realizados updates, inserts ou deletes no banco de dados de origem, mantendo sua base de conhecimento sempre atualizada. Essa estratégia garante a consistência dos seus dados (principal característica de um Data Lake transacional) e pode ter uma série de desafios para sua implementação.
Implementação de CDC na AWS
Existem diferentes formas de se executar estratégias de CDC na AWS. A mais comum é trabalhar com o AWS Database Migration Service (DMS), que permite a configuração de CDC de forma simplificada: basta criar um endpoint de fonte (com configurações de conexão com o banco de dados), um endpoint de destino (pode ser outro banco de dados autogerenciado, um banco no RDS, um bucket no S3, entre outros), uma instância de replicação (máquina virtual responsável por executar a replicação contínua) e a configuração de uma tarefa de migração, apontando quais as tabelas a serem migradas/atualizadas e outras configurações adicionais. Saiba mais sobre a configuração de CDC usando o DMS aqui.
O DMS pode não ser a melhor opção para certos casos de uso. São exemplos:
- Se a sua fonte de dados ou versão não é suportada como origem do AWS DMS;
- Se você busca uma ferramenta open source;
- Se você possui um grande número de fontes de dados para serem atualizadas localizadas em redes diferentes, e busca otimização de custo e segurança. (Esse cenário pode ser comum em aplicações que possuem bases de dados single-tenant para múltiplos clientes).
Para este último caso, onde temos múltiplas fontes localizadas em redes diferentes, acessar essas origens de forma segura via DMS implica na criação de múltiplas VPNs, além da escalabilidade da instância de replicação em si, o que pode representar um grande aumento da complexidade e de custo da solução. Neste Blogpost, iremos explorar uma alternativa OpenSource ao DMS: o Debezium Server, e mostrar como sua integração com o serviço Amazon Kinesis e o framework Apache Iceberg podem viabilizar a criação de um Data Lake transacional na AWS.
Debezium como uma alternativa para o CDC
O Debezium é uma plataforma distribuída de código aberto para a configuração de change data capture amplamente conhecida, e pode funcionar como uma alternativa ao DMS para capturar atualizações em seu banco de dados de origem.
Existem diferentes formas de se implementar o Debezium para garantir a atualização do seu Data Lake na AWS. A forma mais comum é a partir de sua integração nativa com o Apache Kafka, que faz uso do framework Kafka Connect, para implementar e operacionalizar conectores fonte e de sincronização para a propagação das atualizações em um cluster de Kafka. A AWS possui conectores gerenciados a partir do MSK Connect, que simplifica a configuração do CDC para esta abordagem. Um tutorial para a implementação do Debezium usando o MSK Connect pode ser encontrado aqui.
Existe no entanto, a necessidade de se provisionar um cluster de Kafka para esta primeira solução, além de que, para o cenário em que comentamos, onde temos múltiplas fontes de dados em redes diferentes, estabelecer a conectividade privada e múltiplos conectores ainda pode sair com um custo alto.
Neste Blogpost, iremos abordar uma segunda opção para a implementação do Debezium: O Debezium Server. Esta solução baseia-se na implementação de uma aplicação pré-construída, pronta para se utilizar que transmite eventos de atualização de um banco de dados de origem a uma variedade de serviços de mensagem, incluindo o Amazon Kinesis: serviço da AWS que facilita a coleta, o processamento e a análise de dados de streaming em tempo real de forma totalmente gerenciada.
Figura 1 – Arquitetura Debezium Server
Com esta alternativa, conseguimos implementar a aplicação do Debezium Server em qualquer servidor local, sem precisar configurar uma VPN, ou expor o banco de dados a internet, de forma simples. Utilizar o Amazon Kinesis para receber a transmissão de atualizações de dados, também simplifica muito o processo, uma vez que é um serviço serverless, totalmente gerenciado, e com uma simples integração ao AWS Glue, que têm suporte a frameworks como o Apache Iceberg, para processar os arquivos de cdc de entrada, e salvar o dado atualizado automaticamente em tabelas do Data Lake.
Este blog contém o passo a passo para a configuração do Debezium Server, a conexão a um banco de dados de origem e a integração ao Amazon Kinesis Data Streams para envio das informações de CDC, bem como a configuração de um streaming Job do AWS Glue usando o Apache Iceberg para a atualização contínua de um Data Lake armazenado no Amazon S3.
Arquitetura da Solução
Durante este passo a passo, será implementada a seguinte arquitetura:
Figura 2 – Arquitetura de alto nível da demonstração
- Será provisionada uma VPC, que irá simular um ambiente on-premises. O Componente 1 representa uma instância de Banco de Dados MySQL, do qual nós vamos copiar e atualizar as tabelas para o nosso Data Lake, hospedado no Amazon S3. Iremos utilizar uma instância EC2 como cliente MySQL, para executar as operações no Banco de Dados de forma privada.
- Iremos provisionar o Debezium Server em uma instância EC2 (representando um servidor local). Observação: O Debezium server pode ser hospedado tanto on-premises como na AWS, porém para o cenário onde tenho múltiplas fontes de dados, e não quero provisionar uma VPN, o ideal é hospedá-lo localmente.
- É necessário configurar Streams de Dados no serviço do Kinesis Data Streams para receber as atualizações. Por padrão, é necessário provisionar uma stream para o servidor e uma stream por tabela, porém existe também a possibilidade de se utilizar uma stream para múltiplas tabelas (com maior complexidade de configuração explicada posteriormente).
- Iremos utilizar um Streaming Job do AWS Glue e o Apache Iceberg para ler os logs de CDC gerados pelo Debezium Server enviadas à stream do Kinesis e executar as atualizações no Data Lake.
- O AWS Glue Data Catalog mantém a catalogação do Schema do Data Lake para que possam ser feitas operações em nosso Data Lake.
- Após o processamento, os dados são enfim atualizados no Data Lake.
Implementando CDC com o Debezium Server e Kinesis
Pré-requisitos:
Provisionaremos uma stack do AWS CloudFormation, para a configuração mais rápida dos recursos utilizados na solução. Para que tudo funcione conforme o esperado é necessário:
- Ter acesso a uma Conta AWScom as permissões necessárias configuradas nos serviços utilizados;
- Utilizar a região us-east-2 (Ohio).
- Criar credenciais de acesso via CLI (credenciais serão utilizadas para fornecer acesso ao Debezium Server ao Kinesis);
o DISCLAIMER: Nativamente o Debezium server só têm suporte a credenciais de longo termo, por utilizar a classe ProfileCredentialsProvider. Se for utilizar essa solução em produção recomenda-se a customização do projeto do Debezium Server para se trabalhar com IAM Roles através da classe InstanceProfileCredentialsProvider
Provisionando os recursos
- Acesse o repositório púlicoda solução e faça o download do template do AWS CloudFormation em sua máquina.
git clone https://github.com/aws-samples/transactional-data-lake-debezium-cdc.git
- Acesse o console do AWS CloudFormation em sua conta. Clique em “Create Stack”, selecione “Upload a template file” e importe o template DebeziumServer-Kinesis-CDC.json:
Figura 3 – Criando uma Stack no CloudFormation
- Adicione um nome para a stack e os parâmetros necessários para seu provisionamento:
Figura 4 – Parâmetros CloudFormation
- DBmasterusername: O nome do usuário master do banco de dados MySQL.
- DBmasteruserpassword: A senha do usuário master do banco de dados MySQL. Precisa conter no mínimo 8 caracteres.
- Observação: Para simplificar a demonstração iremos usar este usuário para fornecer acesso ao debezium server. A melhor prática é criar um usuário a mais no banco de dados apenas para prover o acesso necessário ao Debezium Server.
- YourIPAddress: O seu endereço de IP, para acessar as instâncias EC2 (Formato 0.0.0.0/32).
- Após adicionar os parâmetros, revise as demais configurações, aceite o aviso sobre provisionamento de recursos IAM, e clique em “Submit”. Aguarde a stack mostrar o status “CREATE_COMPLETE”.
Acessando o Banco de Dados
- Visite a aba “Resources” (Recursos) no console do CloudFormation, para visualizar todos os recursos provisionados.
- Clique no Physical ID do recurso MySQLRDSIntance, para ser direcionado ao console do RDS.
- Na seção “Connectivity & security” copie o endpoint da sua instância de Banco de dados e cole em uma nota de fácil acesso posterior. Vamos precisar do endpoint para acessar o banco, criar e manipular tabelas:
Figura 5 – Endpoint RDS
- Volte a aba “Resources” do CloudFormation e agora clique no Physical ID do recurso EC2MySQLClient para ser direcionado ao console do Amazon EC2.
- Selecione a instância “MySQLClient” e clique em “Connect”. Selecione Session Manager e clique em “connect” para acessar a instância com o mysql client instalado.
- Ao acessar a EC2, execute o comando a seguir para acessar o banco de dados. Substituindo <rds-enpoint> pelo endpoint do RDS copiado anteriormente, e <masterusername> pelo nome do usuário master configurado no momento de provisionamento da stack:
mysql -h <rds-endpoint> -P 3306 -u <masterusername> -p
- No prompt de senha, coloque a senha do usuário master configurada no momento de provisionamento da stack.
Criando uma tabela
- Após acessar o banco, escute os comandos a seguir para criar uma tabela de demonstração no Banco de Dados:
USE DemoDBZ;
CREATE TABLE MYTABLE (
DATA_ID INTEGER PRIMARY KEY,
DATA VARCHAR(50)
);
INSERT INTO MYTABLE VALUES (1,'data1'),(2,'data2');
- Para visualizar a tabela recém-criada, execute:
SELECT * FROM MYTABLE;
A saída deve ser a seguinte:
Figura 6 – Tabela Recém criada no MySQL
Configurando o Debezium Server
Para que o Debezium Server inicie o monitoramento, e envio das atualizações no Banco de Dados ao Amazon Kinesis Data Stream, é necessário antes, configurar as credenciais de acesso via CLI e editar o arquivo de configuração do Debezium Server application.properties.
- Repita os passos 4 ao 6 da sessão “Acessando o Banco de Dados”para acessar o Debezium Server. Porém desta vez clique no Physical ID do recurso “EC2Debezium”.
- Ao acessar a instância EC2, execute:
sudo aws configure
- Preencha os parâmetros com as credenciais de acesso do usuário previamente configurado na seção de requisitos, a região de provisionamento da stack, e o formato de saída desejado.
- Acesse o arquivo application.properties:
cd ../../..
cd debezium-server/
sudo nano conf/application.properties
- Edite o arquivo application.properties de acordo com o template disponibilizado no repositório público do GitHub:
debezium.sink.type=kinesis
debezium.sink.kinesis.region=<aws region>
debezium.sink.kinesis.credentials.profile=default
debezium.source.tombstones.on.delete=false
debezium.source.snapshot.mode=when_needed
debezium.source.connector.class=io.debezium.connector.mysql.MySqlConnector
debezium.source.offset.storage.file.filename=data/offsets.dat
debezium.source.offset.flush.interval.ms=0
debezium.source.database.hostname=<rds instance endpoint>
debezium.source.database.port=3306
debezium.source.database.user=<masterusername>
debezium.source.database.password=<masterusernamepassword>
debezium.source.database.dbname=DemoDBZ
debezium.source.database.server.name=debezium-demo
debezium.source.database.history=io.debezium.relational.history.FileDatabaseHistory
debezium.source.database.history.file.filename=history.dat
Substituindo:
- <aws region> – Região AWS na qual a stack foi provisionada
- <rds instance endpoint> – Endpoint de acesso do RDS copiado anteriormente
- <masterusername>- Usuário master configurado na stack de CloudFormation
- <masterusernamepassword> senha do usuário master configurado na stack de CloudFormation
- Para simplificar a demonstração iremos usar o usuário master para fornecer acesso ao debezium server. A melhor prática é criar um usuário a mais no banco de dados apenas para prover o acesso necessário ao Debezium Server.
- Reforçamos também que sempre que possível, a melhor prática é fazer o uso do AWS Secrets Manager para armazenamento e rotação de credenciais.
Importante: Valide que nenhum espaço é deixado após os parâmetros de configuração e que após cada parâmetro tenha uma quebra de linha antes do próximo. A má configuração desse arquivo pode acarretar em erros ao executar o Debezium Server.
Para mais informações sobre a configuração do Debezium Server, visite a documentação.
- Para salvar o arquivo pressione ctrl+x, e para confirmar pressione y e depois Enter.
- Agora o debezium server já está configurado, e podemos iniciar sua execução rodando:
sudo sh run.sh
Aguarde até mostrar o recado “Keepalive thread is running”. Neste ponto o seu servidor de CDC do Debezium já esta ativo, capturando as informações iniciais do Banco de Dados e qualquer alteração.
Adicionando e Alterando dados
Para testar o funcionamento do Debezium, vamos adicionar uma nova linha, editar e deletar outras.
- Repita os passos 4 ao 8 da seção “Acessando o Banco de Dados” para acessar o seu banco.
- Execute os comandos a seguir:
USE DemoDBZ;
INSERT INTO MYTABLE VALUES (3,'data3');
UPDATE MYTABLE SET DATA='updated_data' where DATA_ID=1;
DELETE FROM MYTABLE WHERE DATA_ID=2;
SELECT * FROM MYTABLE;
A saída deve retornar:
Figura 7 – Tabela Atualizada
Validando a saída do Debezium
Após executar as atualizações, podemos acompanhar o envio de dados ao Amazon Kinesis a partir do console de monitoramento do Kinesis Data Stream.
- No console do CloudFormation, na Aba “Resources” clique no Physical ID do recurso KDSStreamDBTBL. Na nova página, clique em “Monitoring”. Você será direcionado ao console de monitoramento da Stream que recebe os dados de cdc da tabela “MYTABLE”. Aguarde até visualizar dados sendo ingeridos a sua stream (pode levar alguns minutos):
Figura 8 – Dados recebidos Kinesis Data Stream
Agora que sabemos que o Debezium está ativo e funcionando, vamos entender como usá-lo na prática com o Glue Streaming e o Iceberg atualizando os dados em um Data Lake transacional.
CDC com o Glue Streaming e Apache Iceberg
- Clone o outro repositório púlicoda solução ou faça o download do AWS Glue Studio Notebook em seu computador (demo-glue-streaming-cdc.ipynb).
- Acesse o console do AWS Glue Studio em sua conta. Clique em “ETL jobs” no menu à esquerda, e selecione “Notebook”:
Figura 9 – Criando um Jupyter Notebook no Glue Studio
- No prompt do Notebook selecione “Upload notebook”. Mantenha a Engine Spark(Python). Clique no botão “Choose file” e selecione o arquivo demo-glue-streaming-cdc.ipynb. Para “IAM Role” escolha Role provisionada pelo template de CloudFormation “AWSGlueServiceNotebookRoleDemo”. Para concluir a criação, clique em “Create notebook”:
Figura 10 – Criando um Jupyter Notebook no Glue Studio (Prompt)
- Ao abrir o notebook adicione um nome para o Job, clicando na caixa “Untitled job” no menu superior e alterando o nome:
Figura 11 – Parâmetros de configuração do AWS Glue Studio Notebook
- O notebook contém 21 passos, da configuração de parâmetros do AWS Glue e importação de bibliotecas à execução do CDC e finalização da sessão. Cada uma das etapas contém comentários explicativos sobre o código e se é preciso realizar alguma modificação.
Figura 12 – AWS Glue Studio Notebook
Atenção aos itens; 2/ Substitua <bucket_name> e <stream_name> pelos recursos provisionados pela stack de CloudFormation (Encontre esses valores na sessão outputs do CloudFormation, buscando pelos recursos DebeziumOutputBucket e KDSStreamDBTBL. Os valores devem coincidir com os padrões: debezium-ouput-bucket-<AccountID> e debezium-demo.DemoDBZ.MYTABLE respectivamente). 9/ é opcional para filtrar por um intervalo de data na streaming de dados.
Para uma maior compreensão do código, execute uma etapa por vez.
Trabalhando com uma única Stream no Kinesis para múltiplas tabelas
Até então, vimos como configurar o Debezium Server em conjunto com o Amazon Kinesis para fazer streaming de dados de CDC para a AWS. A configuração atual, obedece um padrão, no qual é necessário configurar uma stream do Kinesis Data Stream por tabela dentro do Banco de Dados com a seguinte nomenclatura:
- Stream para o servidor : debezium.source.database.server.name (parâmetro configurado no arquivo application.properties)
o Em nosso exemplo equivale a stream: debezium-demo
- Stream para as tabelas: debezium.source.database.nomedobancodedados.nomedatabela
o Em nosso exemplo a stream: debezium-demo.DemoDBZ.MYTABLE
Essa configuração é a forma mais simples de se utilizar o Debezium Server, e atende uma série de aplicações. Porém, em casos onde preciso fazer o CDC de múltiplas tabelas e bancos de dados, esse processo pode aumentar o gerenciamento necessário e atingir limites dos serviços.
É possível fazer a configuração de modo que o Debezium passe a enviar os dados de múltiplas tabelas para uma única stream. Para isso, é necessário fazer uma implementação personalizada da classe io.debezium.server.StreamNameMapper, para mapear o nome do destino planejado (tópico) para uma stream do Kinesis específica pré-existente. Dessa forma, é possível mapear todas as tabelas de um Banco de Dados para uma única stream e analisar os metadados do payload para entender em qual tabela o dado foi alterado e realizar as operações de atualização do Data Lake.
Não está no escopo deste Blogpost, a implementação da classe customizada io.debezium.server.StreamNameMapper, mas existe uma série de referências que podem ser encontradas on-line, como este artigo.
IMPORTANTE: A referência acima é um exemplo de implementação de um projeto independente, sem vínculo ou relação com a AWS. Não é recomendado que seja feita uma implantação do código diretamente em produção.
Limpando os Recursos
Para limpar os recursos, é necessário antes deletar os dados do bucket no Amazon S3.
- Acesse o console do Amazon S3 e selecione o bucket provisionado pela stack de CloudFormation (debezium-output-bucket-AccountID)
- Clique em “Empty” e confirme a deleção para deletar todos os arquivos do bucket.
- Vá ao console do IAM, Selecione “Roles” e busque a role “dbz-ec2-role”. No console de edição da Role, selecione todas as policies e clique em “remove”.
- Volte ao console do CloudFormation, selecione a stack provisionada.
- Clique em “Delete” e depois em “Delete” novamente para confirmar. Espere a stack chegar ao status “DELETE_COMPLETE”.
Conclusão
É extremamente comum, ao manter Data Lakes na nuvem, ter a necessidade de se executar um monitoramento sobre as atualizações em bancos de dados de origem, e replicar essas mudanças através de estratégias de Change Data Capture. Existem diferentes formas de se implementar CDC, incluindo a utilização do serviço totalmente gerenciado AWS Database Migration Service ou trabalhar com ferramentas open-source como o Debezium.
Neste Blogpost, exemplificamos a implementação do Debezium Server, uma variante do Debezium, que permite enviar dados de CDC diretamente a streams do Amazon Kinesis, e atualizar o Data Lake de forma segura e com eficiência de custo.
Para saber mais sobre o Debezium Server, visite a documentação.
Sobre os Autores:
Isabela Gherson Monteiro é Arquiteta de Soluções na AWS com foco no setor Educacional e ajuda clientes do setor publico a construirem suas soluções seguindo boas práticas na nuvem AWS. Apresenta forte entusiasmo pelas áreas de Analytics e Inteligência Artificial.
Thiago da Hora, Arquiteto de Soluções da AWS, com foco em parceiros de software (ISV) do setor público e especialista em Data & AI. Trabalhou anteriormente em consultorias de TI como especialista em nuvem, banco de dados, migração, modernização de aplicações e desenvolvimento de software. Tem um interesse especial em Analytics, Databases, Machine Learning e Serverless.