Fala dataholics, sabemos que o Delta lake é a engine do momento e sabemos também que sou fascinado por essa engine e falaremos mais sobre ela por aqui.
Esse post de hoje ficou muito bacana e com certeza vai esclarecer muitas dúvidas do pessoal que usa Delta lake no seu dia a dia.
O que veremos por aqui:
Delta lake Time Travel
Viajando para o passado (sim é possível)
Restaurando uma tabela com Time Travel
CDF (não é sobre aquele seu amigo nerd rs)
Change Data Capture (CDC vs CDF)
Change Data Feed, na prática e sem enrolação
Restaurando dados com CDF? Será que dá?
Fabric e OneLake
Performance, Custo e Considerações finais
Referencias
Delta lake Time Travel
Se você vem acompanhando o DataInAction, você já é quase um expert em Delta Lake, se ainda não é, até o final do ano será.
Mas se você esta chegando agora, vamos fazer um recap rápido antes de aprofundar.
A Delta Engine por padrão não altera os arquivos de dados (PARQUET), o seu trabalho é adicionar novos arquivos e escrever no Transaction Log uma nova versão. Então quando você realiza um UPDATE em uma tabela Delta, a engine irá ler os arquivos de dados onde estão os registros a serem alterados, criar novos arquivos de dados com as alterações e registrar no Log uma nova versão, informando que os arquivos antigos não fazem mais parte da tabela.
Note que, a engine não exclui os arquivos de dados antigos, eles são mantidos até que uma operação de VACUUM seja executada na sua tabela, logo com esses arquivos antigos disponíveis podemos visualizar dados antigos, o famoso TIME TRAVEL.
O Time travel ganhou esse nome justamente por poder visualizar dados que já foram apagados ou alterados, pois, seus arquivos de dados continuam disponíveis e registrados no transacion log, contudo, não fazem mais parte da versão atual da tabela, as aplicações (Spark, Power BI, Dremio, etc) sempre utilizam a última versão disponível da tabela delta.
Bora pra prática onde tudo faz sentido.
Como sempre aquele nosso Lab reproduzível, todos os scripts são sempre disponibilizados ao final do post e você pode reproduzir aí com a mesma base de dados que eu.
Criando nossa tabela Delta, chamada PatientInfoDelta, ela contém dados fake de pacientes do COVID.
Agora vamos realizar 1 Update nessa tabela, alterando a idade do paciente 1000000001 de 50 para 33.
Primeiro passo, use e abuse do comando "describe history db_demo.PatientInfoDelta", com ele você consegue ver todas as alterações que a tabela sofreu, basicamente ele faz a leitura do Transaction log e nos entrega num formato mais legível.
Abaixo podemos ver que a versão 0 foi a criação da tabela, logo após a versão 1 com Update, todas as aplicações sempre irão ler a versão 1.
A famosa viagem no tempo, precisamos especificar qual a versão queremos visualizar, note que informando a versão 0 a idade do paciente continua com 50.
Podemos viajar no tempo usando ou a versão da tabela, ou usando um timestamp, note que no comando abaixo uso uma data, também estou fazendo um UNION ALL para ver as duas versões (Atual e antiga).
Até aqui legal né?! Podemos olhar qualquer alteração feita na tabela, desde que não seja executado um VACUUM passando retenção de 0 horas, se isso acontecer todas suas versões antigas serão excluídas de fato e você não poderá mais viajar no tempo com aqueles dados, a recomendação para o VACUUM é no mínimo de 7 dias, ou seja, deixar pelo menos 7 dias de TIME TRAVEL.
E para que o TIME TRAVEL é útil?
Os principais casos são:
Auditoria
Experimentos de ML
Recuperar alterações indevidas (Muito usado rs)
Em um belo dia ensolarado, numa segunda-feira, alguém não tomou seu café ainda e acidentalmente rodou um DELETE sem WHERE, é raro, mas acontece sempre rs!
Como agora você conhece o Time Travel, não haverá panico, só ter calma, encontrar a versão anterior ao DELETE no histórico, usando o describe history.
E aplicar o comando RESTORE, pronto, dia salvo!
Pronto, agora sabemos como funciona o Time Travel, basicamente são arquivos de dados marcados como excluídos (pois, versões novas foram adicionadas), mas não foram excluídos do Storage ainda, a engine Delta nos permite navegar por esses arquivos usando o VERSION AS OF ou TIMESTAMP AS OF.
CDF - Change Data Feed
Agora entraremos num tema muito interessante e poderiamos falar muito sobre isso, daria para escrever vários posts sobre CDF\CDC, mas minha ideia aqui é te dar o pontapé inicial, então resumirei e mostrarei na prática.
CDF (que não é aquele seu colega de classe que era inteligente rsrs) ou Change Data Feed é praticamente o mesmo conceito de CDC (Change Data Capture) encontrado na maioria dos SGBDs como SQL Server, Oracle, PostgreSQL, MongoDB e etc.
Resumindo muitíssimo o conceito de CDC, basicamente ele nasceu para resolver uma dor de extrair dados de SGBDs e cópia-los para outros sistemas, como Kafka, Data Warehouses ou diretamente para um Data Lake, como era feito isso antes do CDC? Cargas em Batch copiando grandes ranges de dados (exemplo D-30), para não perder nenhuma alteração, para alguns cenários tendo que ser sempre carga FULL por existirem tabelas sem campos de data ou um campo confiável para isso. Criar essa lógica de carga incremental para cada tabela era sempre um desafio.
Então nasce o CDC, com o proposito de rastrear todas as alterações na tabela, como INSERTs UPDATEs e DELETES, deixando essas informações disponíveis para ferramentas de ETL\ELT consumirem e levarem para os seus destinos, porém, agora ao invés de realizar uma carga FULL ou com um range muito grande de dados, exemplo copiar D-30, agora copiamos apenas o que mudou naquela tabela, ou seja, se nada mudou, nada sera copiado, ou se tiveram alguns INSERTs e UPDATEs, apenas eles serão copiados.
Isso trouxe um benefício gigante de performance e redução de custos para os ambientes que aplicaram bem o CDC.
Um dos grandes benefícios é a replicação de DELETEs, esse é um problema muito comum quando se fala de ETL\ELT, é simples copiar D-30, mas e quando tem Deletes nessa tabela, como você replica isso para o seu Lake? Vamos ver isso, na prática.
Esse foi um resumo sobre CDC (Change Data Capture), o Delta lake implementou esse mesmo conceito para as tabelas Delta, porém, chamado de CDF (Change Data Feed).
Vamos habilitar o CDF na nossa tabela Delta, usando o ALTER TABLE.
Para o nosso exemplo, mostrarei na prática a utilidade do CDF, então vou simular uma tabela Silver (que seria uma tabela mais tratada, filtrada e normalizada), nessa tabela estou pegando apenas pacientes que foram infectados por outros pacientes, então ela vai se chamar SilverPatientInfectedBy.
O objetivo aqui é replicar as alterações que ocorrem na tabela PatientInfoDelta para a tabela SilverPatientInfectedBy.
Existem muitas formas de fazer isso, não vou entrar no quesito de SCD (slowly changing dimension), mas daria pra fazermos sempre uma carga FULL para replicar as alterações, seria o caminho mais fácil certo? Mas qual seria o melhor caminho?
Após habilitado o CDF vou gerar algumas alterações na nossa tabela PatientInfoDelta, e vamos ver como replicar essas informações para nossa tabela Silver.
De olho nas versões, note que temos a versão 4 que foi onde habilitamos o CDF e depois mais 4 versões que foram as alterações acima.
Para consultar as alterações rastreadas pelo CDF, temos a função table_changes(), passamos a tabela que queremos consultar e a partir de qual versão, nesse caso estou passando a versão 4 que foi quando habilitei, se informo a versão 3 tomaremos um erro, pois não tinha CDF nela ainda.
Note que temos 3 colunas de controle, sendo elas:
_change_type: insert, delete, update_preimage e update_postimage
_commit_version: versão da tabela delta
_commit_timestamp: Data e hora de quando ocorreu
O campo _change_type é o segredo do CDC\CDF, todas as engines de CDC tem esse campo, claro que com nomes diferentes, mas ele é extremamente importante para sabermos qual operação ocorreu naquele registro, no Databricks temos 4 marcações para isso:
insert: Como o nome diz, é uma operação de insert, em outras engines aparece como "I"
delete: Informa que o registro foi excluído da tabela, em outras engines pode aparecer como "D"
update_preimage: Informa que o registro sofreu Update e essa é a versão do registro antes do Update
update_postimage: Informa que o registro sofreu Update e essa é a versão do registro depois do Update
Quando trabalhamos com CDC\CDF os Updates geralmente geram 2 registros, para poder visualizarmos o antes e depois, em algumas engines pode vir até como um Delete seguido de Insert.
Agora que temos o rastreamento do que aconteceu na nossa tabela PatientInfoDelta, precisamos aplicar essas alterações na tabela Silver, e claro não faremos carga FULL né.
Nesse nosso caso, vou criar uma View temporária para tratar as versões, a ideia principal dessa view é retornar sempre a versão mais recente do registro, para depois aplicarmos o MERGE.
Exemplo o registro 1000000003 sofreu 2 updates certo? Com essa lógica abaixo pegaremos apenas o último Update, pois ele é o mais recente e já tem as alterações anteriores.
Outro ponto, note que estou tirando as versões update_preimage (usaremos ela para outra finalidade), pois só me interessa a versão depois do Update.
Veja o resultado, temos 1 Update para aplicar, 1 Insert e 1 delete.
Essa é a nossa Silver antes do MERGE, note que não temos o registro 1000003211, pois ele será inserido ainda, o registro 1000000005 ainda existe, mas precisa ser excluído e o registro 1000000003 precisa aplicar 2 updates (que no caso estão consolidados em 1).
Aqui é onde a mágica acontece, aplicando o MERGE na tabela SilverPatientInfectedBy, utilizando a view temporária e usando o campo _change_type para identificar qual ação será aplicada.
Note que 3 linhas foram afetadas.
E consultando a nossa tabela silver depois do MERGE, tudo aplicado como deveria.
Reginaldo, daria pra fazer o MERGE sem CDC?
Até daria, mas nesse caso precisaria sempre atualizar a tabela inteira, isso tem um custo, o pior de tudo, como aplicar o DELETE? O comando MERGE recentemente ganhou uma nova opção (WHEN NOT MATCHED BY SOURCE), contudo ela não vai ser tão performatica quanto o CDF e precisaríamos comparar a tabela inteira sempre, então a performance não será boa e aumentará seu custo de Storage e Computação, não é a melhor opção, use CDF sempre que possível.
Reginaldo daria pra recuperar dados com CDC?
Vamos simular um caso de UPDATE sem WHERE, todo mundo foi alterado para idade 10.
Vamos consultar nosso histórico novamente, descobrimos que a versão 9 foi onde aconteceu esse UPDATE sem WHERE.
Consultando somente a versão 9 no CDF, note que aqui estou buscando somente a versão do update_preimage, que é como estava antes do Update, e podemos ver o campo Age com os valores corretos.
Fazendo o Rollback manualmente com o comando MERGE.
É funciona! Mas, concorda que com o TIME TRAVEL era muito mais fácil e mais rápido?
Fabric e OneLake
Você deve estar pensando que o Reginaldo está entrando na ondinha do Microsoft Fabric né?!
É indiscutível que o Microsoft Fabric é uma grande promessa e competirá de frente com a Databricks, mas, também indiscutível o quanto prematuro está o Microsoft Fabric, não usaremos em produção tão cedo assim, no mínimo ele precisa sair de Preview para começarmos essa discussão.
Contudo, somos apaixonados por tecnologia e precisamos ficar atentos a tudo ao nosso redor, não se pode ignorar algo simplemente por que está em preview, deixar pra estudar o Fabric somente quando ele for um produto maduro é um erro, a meu ver, precisamos nos preparar e por isso falarei bastante dele por aqui.
Mas diz aí, o que tem a ver o Fabric e OneLake com o tema Time Travel e Change Data Feed?
Tudo que eu disse aqui se aplica também para o o Microsoft Fabric e OneLake, pois, são features da engine Delta, é importante reforçar isso, pois, como falo muito de Databricks, pode parecer que são features exclusivas da Databricks.
O Time Travel é uma feature nativa do Delta lake, logo ela existe em todas as versões.
O Change Data Feed é uma feature que nasceu na versão do Delta Lake 2.0, logo a versão do Apache Spark que você estiver utilizando precisa suportar essa versão da engine do Delta, essa versão já tem quase 1 ano, então as versões atuais do Apache Spark já suportam ela.
Se você for criar um Cluster de Apache Spark dentro do Microsoft Fabric essa informação já fica visível bem na criação do cluster.
Note que o Runtime 1.1 ele já usa Spark 3.3 e Delta 2.2, suportando Change Data Feed.
Performance, Custo e Considerações finais
Resumindo aqui, ambas as features apresentadas conseguem visualizar o passado da tabela, porém, com propósitos diferentes.
O Time Travel é nativo da engine Delta e não precisa habilitar nada, é simplesmente a maneira como a engine trabalha, você pode utilizá-lo para auditoria, experimentos de ML e recuperação de desastre, não seria útil utilizar o Time Travel para ETL\ETL ou replicar dados para outra camada, como fizemos no nosso exemplo da Silver.
Já o Change Data Feed nasceu justamente para o propósito de melhorar a peformance do ETL\ELT e replicar dados entre camadas é uma ótima aplicação para o CDF, replicando somente o necessário, assim melhorando a performance e custo.
Imagine no exemplo que vimos hoje, porém, em um ambiente de produção onde a volumetria é muito mais agressiva, ficar realizando carga FULL de uma tabela de 1 TB de dados é extremamente custoso, seu storage vai ficar caro devido as transações e seu cluster passará mais tempo ligado.
O CDF pode ser utilizado também com pipelines Streaming, uma junção de sucesso é utilizar CDF com Delta Live Tables, deixarei referências para você se aprofundar.
O CDF é uma feature que precisa ser habilitada na sua tabela e importante sua tabela será atualizada, quer saber mais sobre isso, leia esse post:
Logo apesar de poderem ser utilizadas para algumas finalidades em comum, elas têm propósitos diferentes, utilize cada uma para o seu devido proposito.
Espero que tenha esclarecido suas dúvidas sobre o tema.
Fique bem e até a próxima.
Link dos scripts no Github:
Referências:
https://docs.databricks.com/delta/delta-change-data-feed.html (Databricks CDF)
https://www.databricks.com/blog/2021/06/09/how-to-simplify-cdc-with-delta-lakes-change-data-feed.html (CDC with Data Lake)
Comments