Como funcionam as tabelas de streaming
Uma tabela de streaming é uma tabela Delta regular com suporte extra para streaming ou processamento incremental de dados.
As tabelas de streaming são uma boa opção para a ingestão de dados pelos seguintes motivos:
- Cada linha de entrada é manipulada apenas uma vez, o que modela a grande maioria das cargas de trabalho de ingestão (ou seja, anexando ou atualizando linhas em uma tabela).
- Eles podem lidar com grandes volumes de dados somente acréscimo.
As tabelas de streaming também são uma boa opção para transformações de streaming de baixa latência pelos seguintes motivos:
- Razão sobre linhas e janelas de tempo
- Lidar com grandes volumes de dados
- Baixa latência
O diagrama a seguir ilustra como as tabelas de streaming funcionam.
As tabelas de streaming são definidas e atualizadas por um único pipeline Delta Live Tables. Ao criar um pipeline Delta Live Tables, você pode definir explicitamente tabelas de streaming no código-fonte do pipeline. Essas tabelas são definidas por esse pipeline e não podem ser alteradas ou atualizadas por nenhum outro pipeline. Quando você cria uma tabela de streaming no Databricks SQL, o Databricks cria um pipeline Delta Live Tables que é usado para atualizar essa tabela.
Tabelas de streaming para ingestão
As tabelas de streaming são projetadas para fontes de dados somente de acréscimo e entradas de processo apenas uma vez.
A atualização completa faz com que as tabelas de streaming reprocessem dados que já foram processados. A ação de atualização completa faz com que uma tabela de streaming reprocesse todas as entradas, incluindo aquelas que já foram processadas antes.
O exemplo a seguir mostra como usar uma tabela de streaming para ingerir novos arquivos do armazenamento em nuvem. Quando você usa uma ou mais spark.readStream
invocações em uma definição de conjunto de dados, isso faz com que o Delta Live Tables trate o conjunto de dados como uma tabela de streaming em vez de uma exibição materializada.
import dlt
@dlt.table
def raw_customers():
return (
spark.readStream.format("cloudFiles")
.option("cloudFiles.format", "json")
.option("cloudFiles.inferColumnTypes", "true")
.load("/Volumes/path/to/files")
)
O diagrama a seguir ilustra como as tabelas de streaming somente acréscimo funcionam.
Tabelas de streaming e streaming de baixa latência
As tabelas de streaming são projetadas para streaming de baixa latência em estado limitado. As tabelas de streaming usam o RocksDB para gerenciamento de pontos de verificação, o que as torna adequadas para streaming de baixa latência. No entanto, eles esperam córregos que são naturalmente limitados ou limitados com uma marca d'água.
Um fluxo naturalmente limitado é produzido por uma fonte de dados de streaming que tem um início e um fim bem definidos. Um exemplo de um fluxo naturalmente limitado é a leitura de dados de um diretório de arquivos onde nenhum novo arquivo está sendo adicionado depois que um lote inicial de arquivos é colocado. O fluxo é considerado limitado porque o número de arquivos é finito e, em seguida, o fluxo termina depois que todos os arquivos foram processados.
Você também pode usar uma marca d'água para vincular um fluxo. Uma marca d'água no Spark Structured Streaming é um mecanismo que ajuda a lidar com dados atrasados, especificando quanto tempo o sistema deve esperar por eventos atrasados antes de considerar a janela de tempo como concluída. Um fluxo não limitado que não tem uma marca d'água pode fazer com que um pipeline Delta Live Tables falhe devido à pressão da memória.
Junção de stream-snapshot
As junções de instantâneo de fluxo são uniões entre um fluxo e uma dimensão que é capturada em instantâneo quando os fluxos são iniciados. Essas junções não serão recalculadas se a dimensão mudar após o início do fluxo, porque a tabela de dimensões é tratada como um instantâneo no tempo e as alterações na tabela de dimensões após o início do fluxo não são refletidas, a menos que você recarregue ou atualize a tabela de dimensões. Este é um comportamento razoável se você puder aceitar pequenas discrepâncias em uma associação. Por exemplo, uma junção aproximada é aceitável quando o número de transações é muitas ordens de grandeza maior do que o número de clientes.
No exemplo de código a seguir, juntamos uma tabela de dimensão, clientes, com duas linhas com um conjunto de dados cada vez maior, transações. Materializamos uma junção entre esses dois conjuntos de dados em uma tabela chamada sales_report
. Observe que, se um processo externo atualizar a tabela de clientes adicionando uma nova linha (customer_id=3, name=Zoya
), essa nova linha NÃO estará presente na junção porque a tabela de dimensão estática foi capturada em instantâneo quando os fluxos foram iniciados.
import dlt
@dlt.view
# assume this table contains an append-only stream of rows about transactions
# (customer_id=1, value=100)
# (customer_id=2, value=150)
# (customer_id=3, value=299)
# ... <and so on> ...
def v_transactions():
return spark.readStream.table("transactions")
# assume this table contains only these two rows about customers
# (customer_id=1, name=Bilal)
# (customer_id=2, name=Olga)
@dlt.view
def v_customers():
return spark.read.table("customers")
@dlt.table
def sales_report():
facts = spark.readStream.table("v_transactions")
dims = spark.read.table("v_customers")
return (
facts.join(dims, on="customer_id", how="inner"
)
Limitações da tabela de streaming
As tabelas de streaming têm as seguintes limitações:
- Evolução limitada: você pode alterar a consulta sem recalcular todo o conjunto de dados. Como uma tabela de streaming vê uma linha apenas uma vez, você pode ter consultas diferentes operando em linhas diferentes. Isso significa que você deve estar ciente de todas as versões anteriores da consulta que estão sendo executadas em seu conjunto de dados. Uma atualização completa é necessária para fazer com que a tabela de streaming veja os dados que foram vistos novamente.
- Gerenciamento de estado: as tabelas de streaming são de baixa latência, portanto, você precisa garantir que os fluxos sobre os quais operam sejam naturalmente limitados ou limitados com marca d'água.
- As junções não recalculam: ao contrário das visualizações materializadas, cujos resultados estão sempre corretos porque recalculam automaticamente, as junções em tabelas de streaming não recalculam quando as dimensões mudam. Esta característica pode ser boa para cenários "rápidos, mas errados".