Saiba como usar o conector de armazenamento de fluxo Fluss.
Informações básicas
O Fluss utiliza uma arquitetura de integração lake-stream que se integra perfeitamente a formatos de data lake, como Apache Paimon, para oferecer processamento de dados com baixa latência e reduzir significativamente os custos de construção e manutenção de um data warehouse em tempo real. O Fluss ajuda as empresas a eliminar silos de dados, acelerar análises profundas e compartilhar dados de forma eficiente dentro do data lake, fornecendo um mecanismo unificado para sinergia entre fluxos de dados e lakehouse.
|
Categoria |
Descrição |
|
Tipos suportados |
Tabelas de origem, tabelas de dimensão e tabelas de resultado, além de sinks de ingestão de dados. |
|
Modo de execução |
Modo streaming e modo batch. |
|
Formato de dados |
Ainda não suportado. |
|
Tipo de API |
SQL e yaml de ingestão de dados. |
|
Suporte a atualizações e exclusões na tabela de resultado |
Sim. |
Criar um catálogo personalizado
O Fluss evolui mais rapidamente que o Realtime Compute for Apache Flink. O pacote mais recente do Catalog personalizado está disponível aqui para que você possa testar recursos do Fluss Catalog ainda não lançados nas versões VVR. Para mais informações, consulte Register a Fluss Catalog.
SQL
Use o conector Fluss como tabela de origem, tabela de dimensão ou tabela de resultado em jobs SQL. Para mais informações, consulte Engine Integration - Flink.
Pré-requisitos
Possua permissões de leitura e escrita na tabela Fluss de destino. Para mais informações, consulte Grant access to a Fluss cluster.
O workspace do Flink e o cluster Fluss devem estar na mesma VPC.
Crie um Fluss Catalog no console do Flink. Para detalhes, consulte Create a Fluss Catalog.
Recursos principais
O Conector Fluss oferece os seguintes recursos principais:
|
Recurso |
Descrição |
|
Suporta consumo completo, incremental e unificado (completo e incremental). |
|
|
Permite exploração rápida de dados no modo batch do Flink SQL, útil para desenvolvimento, depuração, validação de dados e troubleshooting. |
|
|
As tabelas de chave primária do Fluss oferecem suporte nativo à assinatura de log de Change Data Capture (CDC), permitindo que jobs Flink downstream consumam um fluxo completo de eventos de alteração (INSERT, UPDATE_BEFORE, UPDATE_AFTER e DELETE) em tempo real. |
|
|
O suporte a consultas pontuais eficientes de chave-valor (KV) e buscas por índice secundário torna o Fluss ideal para cenários de join de tabela de dimensão com baixa latência. |
|
|
Atualiza apenas os dados nas colunas modificadas, e não a linha inteira. |
|
|
Esta solução inovadora de join preserva a semântica de join de fluxo duplo ao enviar operações de atualização de dados para a tabela Fluss. Esse processo reduz significativamente o consumo de recursos do Flink e melhora a estabilidade e a eficiência de execução do job. |
|
|
Tabelas de chave primária do Fluss permitem configurar diferentes motores de mesclagem para controlar como registros com a mesma chave primária são combinados. |
|
|
Oferece integração profunda entre o armazenamento de fluxo em tempo real (Fluss) e um data lake baseado em Paimon, com metadados gerenciados pelo Data Lake Formation (DLF). Este modelo de "um dado, duas visões" permite que uma única tabela lógica ofereça acesso a dados em tempo real com baixa latência e análise histórica de alto throughput. |
|
|
Suporta a criação de tabelas particionadas, leitura e escrita nessas tabelas, além de gerenciar automaticamente a criação e limpeza de partições. |
|
|
Permite adicionar colunas dinamicamente sem interromper jobs de leitura e escrita em andamento. |
Limitações
Tabelas de log suportam apenas operações INSERT, não aceitando UPDATE ou DELETE.
Tabelas de chave primária suportam operações INSERT, UPDATE e DELETE.
Lookup joins são suportados apenas em tabelas de dimensão que também são tabelas de chave primária. A condição de join deve incluir todos os campos da chave primária.
Para um Delta join, ambas as tabelas devem ser tabelas de chave primária do Fluss, e a chave de join deve incluir a bucket key.
Considerações
Existem dois tipos de tabelas no Fluss: a tabela de log, que não possui chave primária e é semelhante a um tópico Kafka, e a tabela de chave primária, que possui chave primária e suporta semântica upsert. Escolha o tipo de tabela mais adequado ao seu caso de uso.
Em ambiente de produção, configure adequadamente o parâmetro
bucket.numpara garantir desempenho ideal de leitura e escrita paralelas e distribuição equilibrada dos dados.Para tabelas particionadas, defina sua estratégia de particionamento com base no volume de dados e nos padrões de consulta. Escolha uma granularidade de tempo adequada (por exemplo, diária ou mensal) e utilize o parâmetro
table.auto-partition.num-retentionpara controlar quantas partições históricas são retidas, evitando o inchaço de metadados. Se uma tabela de chave primária contiver dados com características naturais de particionamento (como por tempo ou dimensão de negócio), utilize uma tabela particionada em vez de armazenar todos os dados em uma única tabela não particionada. Tabelas particionadas simplificam o gerenciamento do ciclo de vida dos dados e habilitam o pruning de partições para consultas streaming e batch, o que reduz significativamente varreduras desnecessárias de dados e melhora o desempenho das consultas.Antes de usar o Delta Join, configure os parâmetros de runtime necessários no seu job Flink para ativar essa otimização.
Funcionalidades
Consumo completo e incremental
Visão geral
As tabelas de chave primária do Fluss suportam consumo completo e incremental. O sistema lê primeiro um snapshot histórico completo da tabela. Após a conclusão da leitura do snapshot, ele alterna automática e perfeitamente para o consumo de fluxo incremental. Esse processo garante a integridade e consistência dos dados.
Modos de consumo
Controle o ponto inicial de consumo usando o parâmetro scan.startup.mode.
|
Modo |
Descrição |
|
|
Padrão. Lê um snapshot completo primeiro e depois consome dados incrementais. Adequado para cenários que exigem dados históricos completos. |
|
|
Consome dados a partir do offset de log mais antigo disponível, sem ler um snapshot completo. |
|
|
Consome dados a partir do offset mais recente. Apenas novos dados gerados após o início do job são consumidos. |
|
|
Consome dados a partir de um timestamp específico. Este modo exige que você também defina o parâmetro |
Exemplos de SQL
-- Full and incremental consumption (default mode)
SELECT * FROM `fluss_catalog`.`fluss_db`.orders;
-- Consume from a specific timestamp by using a hint
SELECT * FROM `fluss_catalog`.`fluss_db`.orders
/*+ OPTIONS('scan.startup.mode' = 'timestamp', 'scan.startup.timestamp' = '2025-01-01 00:00:00') */;
-- Consume from the latest offset
SELECT * FROM `fluss_catalog`.`fluss_db`.orders
/*+ OPTIONS('scan.startup.mode' = 'latest') */;
Assinatura de log CDC e tabelas virtuais
Assinatura de log
As tabelas de chave primária do Fluss suportam nativamente a assinatura de log CDC (Change Data Capture). Isso permite que jobs Flink downstream consumam um fluxo completo de changelog (eventos INSERT, UPDATE_BEFORE, UPDATE_AFTER e DELETE) em tempo real, sem necessidade de configuração separada de binlog.
Isso significa que:
Todas as alterações em uma tabela de chave primária geram logs CDC automaticamente.
Aplicações downstream podem assinar diretamente a tabela de chave primária para receber o fluxo completo de changelog, destinado à sincronização de dados em tempo real ou ETL streaming.
Exemplo de SQL
-- Read the primary key table directly to get the CDC changelog stream
SELECT * FROM `fluss_catalog`.`fluss_db`.orders;
-- The output includes complete INSERT, UPDATE, and DELETE events.
Tabelas virtuais
Além de assinar o fluxo CDC diretamente, o Fluss fornece um mecanismo de tabela virtual. Você pode acessar changelogs com metadados adicionando um sufixo específico ao nome da tabela base, eliminando a necessidade de armazenamento extra de dados. O sistema gera essas tabelas virtuais automaticamente, dispensando criação manual.
Tabela de changelog ($changelog)
Este recurso aplica-se a tabelas de chave primária e tabelas append-only, fornecendo o fluxo bruto de changelog com metadados.
Estrutura da tabela (O sistema adiciona automaticamente as seguintes colunas de metadados ao esquema original da tabela):
|
Coluna de metadados |
Tipo |
Descrição |
|
|
STRING |
O tipo de alteração. Para uma tabela de chave primária, os valores possíveis são |
|
|
BIGINT |
O offset da alteração no log. |
|
|
TIMESTAMP_LTZ |
O timestamp de commit da alteração. |
Exemplos de SQL:
-- Read the $changelog virtual table for the orders table
SELECT * FROM `fluss_catalog`.`fluss_db`.orders$changelog;
-- Consume from the latest offset by using a hint
SELECT * FROM `fluss_catalog`.`fluss_db`.orders$changelog
/*+ OPTIONS('scan.startup.mode' = 'latest') */;
-- Filter for delete events
SELECT * FROM `fluss_catalog`.`fluss_db`.orders$changelog
WHERE _change_type = 'delete';
Tabela Binlog ($binlog)
Disponível apenas para tabelas de chave primária, este recurso fornece dados formatados em Binlog que incluem imagens antes/depois, facilitando a recuperação precisa do estado dos dados antes e após cada alteração.
Estrutura da tabela (Além das colunas de metadados, os dados completos da linha antes e depois são apresentados em um tipo ROW aninhado):
|
Coluna |
Tipo |
Descrição |
|
|
STRING |
O tipo de alteração. Os valores possíveis são |
|
|
BIGINT |
O offset do log. |
|
|
TIMESTAMP_LTZ |
O timestamp de commit. |
|
|
ROW |
Os dados da linha antes da alteração. O valor é NULL para operações |
|
|
ROW |
Os dados da linha após a alteração. O valor é NULL para operações |
Mapeamento de eventos de alteração:
|
Tipo de alteração |
|
|
|
|
NULL |
Novo valor |
|
|
Valor antigo |
Novo valor |
|
|
Valor antigo |
NULL |
Exemplos de SQL:
-- Read the $binlog virtual table for the users table
SELECT * FROM `fluss_catalog`.`fluss_db`.users$binlog;
-- Get the before and after values of a field from an update event
SELECT
`before`.user_name AS old_name,
`after`.user_name AS new_name,
_commit_timestamp AS change_time
FROM `fluss_catalog`.`fluss_db`.users$binlog
WHERE _change_type = 'update';
Limitações
Atualmente, as tabelas $changelog e $binlog não suportam pushdown de projeção, pruning de partição ou pushdown de predicado.
A tabela $binlog está disponível apenas para tabelas de chave primária. Não há suporte para tabelas append-only.
Os modos de inicialização suportados para tabelas virtuais são
earliest(padrão),latestetimestamp. O modofullnão é suportado.
Atualização parcial
Visão geral
O Fluss suporta atualizações parciais, permitindo que múltiplos fluxos de dados escrevam independentemente em suas respectivas colunas na mesma tabela ampla de chave primária. O motor do Fluss mescla automaticamente os campos no nível de registro com base na chave primária. Essa abordagem evita a necessidade de manter estados complexos de join de múltiplos fluxos no Flink e previne problemas relacionados a tamanhos elevados de estado.
Caso de uso
Um caso de uso típico é a construção de tabelas amplas de perfil de usuário em tempo real. Diferentes fontes de dados, como sistemas de recomendação, logs de impressão, logs de cliques e dados de carrinho de compras, podem atualizar seus respectivos campos na tabela de perfil do usuário. Esse processo cria uma visão 360 graus completa do usuário.
Limitações
A tabela de destino deve ser uma tabela de chave primária.
A operação de escrita de cada fluxo de dados deve incluir todos os campos da chave primária.
A topologia de computação não deve conter nós de join de múltiplos fluxos. O Fluss lida com a operação de mesclagem diretamente na camada de armazenamento.
Exemplos de SQL
-- 1. Create a wide table
CREATE TABLE IF NOT EXISTS `fluss_catalog`.fluss_db.user_rec_wide (
user_id STRING,
item_id STRING,
rec_score DOUBLE,
imp_cnt INT,
click_cnt INT,
PRIMARY KEY (user_id, item_id) NOT ENFORCED
) WITH ('bucket.num' = '3');
-- 2. Use multiple streams to write to their respective fields
-- Stream 1: Writes recommendation scores
INSERT INTO `fluss_catalog`.fluss_db.user_rec_wide (user_id, item_id, rec_score)
SELECT user_id, item_id, rec_score
FROM `fluss_catalog`.fluss_db.recommendations;
-- Stream 2: Writes impression counts
INSERT INTO `fluss_catalog`.fluss_db.user_rec_wide (user_id, item_id, imp_cnt)
SELECT user_id, item_id, imp_cnt
FROM `fluss_catalog`.fluss_db.impressions;
-- Stream 3: Writes click counts
INSERT INTO `fluss_catalog`.fluss_db.user_rec_wide (user_id, item_id, click_cnt)
SELECT user_id, item_id, click_cnt
FROM `fluss_catalog`.fluss_db.clicks;
As três instruções INSERT acima podem ser executadas como jobs Flink separados. A camada de armazenamento do Fluss mescla automaticamente os campos para a mesma chave primária em linhas completas.
Delta Join
Visão geral
O Delta Join é um paradigma de join fluxo-fluxo de próxima geração fornecido pelo Fluss. Ele transfere as operações de atualização de dados para a camada de armazenamento do Fluss, aproveitando tabelas de chave primária e índices secundários para buscas eficientes. Este design elimina a necessidade de manter estado de join no Flink.
Principais vantagens:
Sem estado de join: Elimina o armazenamento redundante de estado e evita problemas de garbage collection (GC) causados por estados grandes.
Baixo consumo de recursos: Reduz o consumo de memória e CPU do Flink em mais de 86% nos testes.
Maior estabilidade e eficiência: Evita gargalos de desempenho causados pelo inchaço do estado.
Comparação com joins tradicionais
|
Recurso |
Join tradicional do Flink (com Kafka) |
Fluss Delta Join |
|
Armazenamento de Estado |
Exige cache de todos os dados upstream no Flink. |
Sem estado de join; depende dos índices do Fluss. |
|
Consumo de Recursos |
Alto, devido ao GC frequente causado por estado grande. |
Baixo |
|
Estabilidade |
Suscetível a problemas de inchaço de estado. |
Mais estável |
|
Mecanismo |
Atualizações de ambos os fluxos impulsionam o join. |
O Fluss transfere atualizações para sua camada de armazenamento. |
|
Casos de Uso |
Joins fluxo-fluxo de uso geral. |
Joins eficientes entre tabelas de chave primária do Fluss. |
Limitações
Tanto a tabela da esquerda quanto a da direita devem ser tabelas de chave primária do Fluss (tabelas particionadas são suportadas).
A bucket key deve ser um prefixo da chave primária.
A chave de join deve incluir a bucket key. Para uma tabela particionada, deve incluir também a chave de partição.
Exemplos de SQL
1. Criar tabelas
CREATE TABLE orders (
user_id BIGINT,
order_date DATE,
order_id BIGINT,
amount DECIMAL(10, 2),
PRIMARY KEY (user_id, order_id, order_date) NOT ENFORCED
) WITH ('bucket.key' = 'user_id, order_id');
CREATE TABLE order_enhance (
user_id BIGINT,
order_id BIGINT,
risk_level TINYINT,
is_fraud BOOLEAN,
update_time TIMESTAMP(3),
PRIMARY KEY (user_id, order_id) NOT ENFORCED
) WITH ('bucket.key' = 'user_id, order_id');
2. Executar um Delta Join
SELECT * FROM orders o
INNER JOIN order_enhance e
ON o.user_id = e.user_id AND o.order_id = e.order_id;
3. Otimizar o desempenho de busca com hints
SELECT * FROM orders o /*+ OPTIONS('client.lookup.queue-size'='2560') */
INNER JOIN order_enhance e /*+ OPTIONS('client.lookup.queue-size'='2560') */
ON o.user_id = e.user_id AND o.order_id = e.order_id;
Configuração de parâmetros do job
Para usar um Delta Join, adicione as seguintes configurações aos parâmetros de runtime do seu job Flink:
table.exec.delta-join.cache-enabled: 'true'
table.exec.async-lookup.buffer-capacity: '3000'
table.optimizer.delta-join.strategy: FORCE
table.exec.delta-join.left.cache-size: '100'
table.exec.delta-join.right.cache-size: '1000'
|
Parâmetro |
Descrição |
|
|
Defina como |
|
|
A capacidade do buffer para requisições assíncronas. Recomendamos definir este valor na casa dos milhares. |
|
|
Ativa o cache local para reduzir requisições ao Fluss. |
|
|
O número de chaves a serem armazenadas em cache para a tabela da esquerda. Ajuste este valor com base na memória e nos padrões de dados quentes. |
|
|
O número de chaves a serem armazenadas em cache para a tabela da direita. Ajuste este valor com base na memória e nos padrões de dados quentes. |
Após ativar o Delta Join, o nó Delta Join aparece na visão geral do job Flink, indicando que a otimização está ativa.
Lookup join (join de tabela de dimensão)
Visão geral
Utilize uma tabela de chave primária do Fluss como uma tabela de dimensão no Flink SQL. Um lookup join permite enriquecer dados de streaming com dados dimensionais em tempo real. O Fluss suporta buscas pontuais KV eficientes e pesquisas por índice secundário, sendo adequado para cenários de join de tabela de dimensão com baixa latência.
Limitações
Apenas uma tabela de chave primária pode ser usada como tabela de dimensão.
A condição de join deve incluir todos os campos da chave primária da tabela de dimensão.
Modos síncrono e assíncrono
|
Modo |
Configuração |
Descrição |
|
Assíncrono (padrão) |
|
Oferece alto throughput. Recomendado para a maioria dos casos de uso. |
|
Síncrono |
|
Consulta registros sequencialmente. Adequado para depuração ou cenários de baixa concorrência. |
Exemplos de SQL
-- Configure lookup cache by using a hint to perform a dimension table join
SELECT
o.order_id,
o.amount,
u.user_name,
p.product_name
FROM `fluss_catalog`.`fluss_db`.orders AS o
LEFT JOIN `fluss_catalog`.`fluss_db`.user_dim
/*+ OPTIONS('lookup.cache' = 'PARTIAL', 'lookup.partial-cache.expire-after-write' = '60s', 'lookup.partial-cache.max-rows' = '10000') */
FOR SYSTEM_TIME AS OF o.proctime AS u
ON o.user_id = u.user_id
LEFT JOIN `fluss_catalog`.`fluss_db`.product_dim
FOR SYSTEM_TIME AS OF o.proctime AS p
ON o.product_id = p.product_id;
-- Use synchronous lookup mode (suitable for debugging)
SELECT o.order_id, o.amount, d.user_name
FROM `fluss_catalog`.`fluss_db`.orders AS o
LEFT JOIN `fluss_catalog`.`fluss_db`.user_dim
/*+ OPTIONS('lookup.async' = 'false') */
FOR SYSTEM_TIME AS OF o.proctime AS d
ON o.user_id = d.user_id;
Motor de mesclagem
Visão geral
As tabelas de chave primária do Fluss permitem configurar um motor de mesclagem para controlar como o sistema combina registros com a mesma chave primária. Use o parâmetro table.merge-engine para selecionar uma das seguintes estratégias:
|
Motor de mesclagem |
Descrição |
|
|
Mantém o último registro gravado. Dados posteriores sobrescrevem os anteriores. Adequado para a maioria dos cenários de upsert. |
|
|
Mantém o primeiro registro gravado, ignorando quaisquer dados subsequentes com a mesma chave primária. Ideal para cenários de deduplicação, como deduplicação de logs. |
|
|
Mantém o registro com o maior número de versão de uma coluna de versão especificada. Exige o parâmetro |
Exemplos de SQL
-- Use first_row for deduplication
CREATE TABLE IF NOT EXISTS `fluss_catalog`.fluss_db.event_dedup (
event_id STRING,
event_type STRING,
event_time TIMESTAMP(3),
payload STRING,
PRIMARY KEY (event_id) NOT ENFORCED
) WITH (
'table.merge-engine' = 'first_row'
);
-- Use versioned to update based on a version column
CREATE TABLE IF NOT EXISTS `fluss_catalog`.fluss_db.user_profile (
user_id BIGINT,
user_name STRING,
age INT,
update_version BIGINT,
PRIMARY KEY (user_id) NOT ENFORCED
) WITH (
'table.merge-engine' = 'versioned',
'table.merge-engine.versioned.ver-column' = 'update_version'
);
Tabela particionada
Visão geral
O Fluss suporta tabelas particionadas. Utilize PARTITIONED BY para dividir dados em diferentes partições físicas com base em uma chave de partição. Isso é ideal para gerenciar ciclos de vida de dados e melhorar o desempenho de consultas baseadas em tempo ou dimensões de negócio. Tabelas particionadas suportam particionamento de campo único e particionamento de múltiplos campos, oferecendo três estratégias ortogonais de gerenciamento de partição: gerenciamento manual, gerenciamento automático e criação dinâmica.
Regras básicas
O tipo de dados de uma chave de partição deve ser STRING.
Para uma tabela de chave primária, a chave de partição deve ser um subconjunto da chave primária.
Configure regras de particionamento automático apenas durante a criação da tabela; não é possível modificá-las posteriormente.
Estratégias de gerenciamento de partição
|
Estratégia |
Descrição |
|
Gerenciamento manual |
Crie ou exclua partições manualmente usando |
|
Gerenciamento automático |
O sistema cria novas partições e limpa partições históricas expiradas automaticamente com base em regras temporais. Projetada para ingestão contínua de dados baseada em tempo. |
|
Criação dinâmica |
Ao gravar dados, o cliente cria automaticamente a partição de destino se ela não existir. Mais indicada para cenários com valores de partição imprevisíveis. |
Essas três estratégias são ortogonais e podem ser usadas em combinação. Por exemplo, ative o gerenciamento automático para criação e limpeza baseadas em tempo e a criação dinâmica como fallback para lidar com partições que não foram pré-criadas.
Exemplos de SQL
1. Criar uma tabela particionada por campo único com gerenciamento automático de partição
CREATE TABLE `fluss_catalog`.fluss_db.site_access (
site_id BIGINT,
user_name STRING,
pv BIGINT,
event_day STRING,
PRIMARY KEY (site_id, event_day) NOT ENFORCED
) PARTITIONED BY (event_day) WITH (
'table.auto-partition.enabled' = 'true',
'table.auto-partition.time-unit' = 'DAY',
'table.auto-partition.num-precreate' = '5',
'table.auto-partition.num-retention' = '30',
'table.auto-partition.time-zone' = 'Asia/Shanghai'
);
2. Criar uma tabela particionada por múltiplos campos
CREATE TABLE `fluss_catalog`.fluss_db.region_access (
access_id BIGINT,
user_name STRING,
event_date STRING,
region STRING,
PRIMARY KEY (access_id, event_date, region) NOT ENFORCED
) PARTITIONED BY (event_date, region) WITH (
'table.auto-partition.enabled' = 'true',
'table.auto-partition.key' = 'event_date',
'table.auto-partition.time-unit' = 'DAY',
'table.auto-partition.num-retention' = '7'
);
Nota : Para particionamento de múltiplos campos, especifique a chave baseada em tempo para particionamento automático usandotable.auto-partition.key. O particionamento de múltiplos campos suporta apenas expiração e limpeza automáticas, não a pré-criação automática. O parâmetronum-precreateé forçado a 0.
3. Gerenciar partições manualmente
-- View all partitions
SHOW PARTITIONS `fluss_catalog`.fluss_db.site_access;
-- Manually add a partition
ALTER TABLE `fluss_catalog`.fluss_db.site_access
ADD PARTITION (event_day = '20250315');
-- Manually drop a partition
ALTER TABLE `fluss_catalog`.fluss_db.site_access
DROP PARTITION (event_day = '20250101');
4. Criar partições dinamicamente
Ao gravar dados, se a partição de destino não existir, o cliente a cria automaticamente. Este recurso está ativado por padrão.
-- Write data. If the partition '20250701' does not exist, it is automatically created.
INSERT INTO `fluss_catalog`.fluss_db.site_access
VALUES (1, 'hello', 100, '20250701');
O parâmetro do cliente client.writer.dynamic-create-partition.enabled (padrão: true) controla a criação dinâmica. Ele está sujeito aos limites de nível de cluster de max.partition.num (padrão: 1000) e max.bucket.num (padrão: 128000).
Pruning de partição
Ao consultar uma tabela particionada no modo streaming ou batch, o Fluss suporta pruning de partição. Ao filtrar pela chave de partição em uma cláusula WHERE, a consulta lê apenas as partições correspondentes, reduzindo a sobrecarga desnecessária de I/O.
-- Read only the data from the partition for a specific date
SELECT * FROM `fluss_catalog`.`fluss_db`.site_access
WHERE event_day = '20250315';
-- Filter a multi-field partitioned table by region
SELECT * FROM `fluss_catalog`.`fluss_db`.region_access
WHERE region = 'US';
Parâmetros de particionamento automático
|
Parâmetro |
Tipo |
Padrão |
Descrição |
|
|
Boolean |
false |
Especifica se o gerenciamento automático de partição deve ser ativado. |
|
|
String |
Nenhum |
Para particionamento de múltiplos campos, especifica a chave baseada em tempo para o particionamento automático. Não necessário para particionamento de campo único. |
|
|
Enum |
DAY |
A granularidade de tempo para particionamento automático. Valores válidos: |
|
|
Integer |
2 |
O número de partições futuras a serem pré-criadas. Não suportado para particionamento de múltiplos campos, onde o valor é forçado a 0. |
|
|
Integer |
7 |
O número de partições históricas a serem retidas. Partições expiradas além desse limite são excluídas automaticamente. |
|
|
String |
Fuso horário do sistema |
O fuso horário usado para particionamento automático. |
Melhores práticas
Escolha a granularidade de partição correta: Selecione uma granularidade de tempo com base no volume de dados e nos padrões de consulta. Para grandes volumes de dados e faixas de tempo de consulta estreitas, recomendamos particionar por
DAYouHOUR. Para volumes menores, particione porMONTHouQUARTER.Defina uma política de retenção razoável: Use
num-retentionpara controlar o número de partições históricas. Isso ajuda a evitar o inchaço de metadados e reduz a carga de gerenciamento do cluster causada por um número excessivo de partições.Combine gerenciamento automático e criação dinâmica: Utilize o gerenciamento automático para criação e limpeza rotineiras de partições baseadas em tempo e a criação dinâmica como fallback para lidar com dados anormais ou atrasados.
Esteja ciente dos limites do cluster: O parâmetro
max.partition.num(padrão: 1000) limita o número de partições por tabela. O número total de buckets no cluster é limitado pormax.bucket.num(padrão: 128.000). O número total de buckets em uma tabela (número de partições ×bucket.num) não deve exceder esse limite.
Pushdown de consulta streaming
O Fluss usa o formato de armazenamento colunar Apache Arrow para transmissão de logs. Isso suporta o pushdown de operações de filtro e projeção para a camada de armazenamento, reduzindo o volume de transferência de dados e podendo melhorar o desempenho da consulta em até 10 vezes.
Este recurso é especialmente eficaz nos seguintes cenários:
Leitura de apenas um subconjunto de colunas de uma tabela ampla (pushdown de projeção).
Filtragem de uma grande quantidade de dados com base em condições específicas (pushdown de predicado).
O formato de armazenamento de log é controlado pelo parâmetro table.log.format, cujo padrão é ARROW.
Arquitetura unificada stream-lake
Visão geral
O Fluss suporta uma arquitetura unificada stream-lake que pode sincronizar automaticamente dados em tempo real do Fluss para um data lake, como o Apache Paimon. Isso alcança o armazenamento em camadas automático para dados quentes e frios, equilibrando a baixa latência das consultas em tempo real com os baixos custos de armazenamento de dados históricos.
Principais recursos:
Grava automaticamente dados de streaming do Fluss no armazenamento lake Paimon.
Organiza automaticamente dados quentes e frios em camadas. Dados quentes são retidos no armazenamento de fluxo Fluss, enquanto dados frios são movidos para o Paimon.
Fornece uma interface de consulta Flink SQL unificada para acessar dados tanto no armazenamento de fluxo quanto no lake simultaneamente.
Parâmetros de configuração
|
Parâmetro |
Tipo |
Padrão |
Descrição |
|
|
Boolean |
false |
Ativa o armazenamento em camadas no lake. |
|
|
Enum |
Padrão do cluster |
O formato do data lake. Atualmente, apenas |
|
|
Integer |
2 |
O número de segmentos de log a serem retidos localmente após a ativação do armazenamento em camadas. |
Exploração de dados
Visão geral
O Fluss suporta exploração rápida de dados em tabelas no modo batch do Flink SQL, incluindo consultas LIMIT, buscas pontuais por chave primária e agregações COUNT(*). Visualize rapidamente os dados em uma tabela sem iniciar um job de streaming contínuo. Isso é útil para desenvolvimento, depuração, validação de dados e troubleshooting.
Consultas LIMIT
Execute consultas LIMIT em tabelas de chave primária e tabelas append-only para recuperar rapidamente uma pequena amostra de dados.
-- View the first 10 records from a primary key table
SELECT * FROM `fluss_catalog`.`fluss_db`.orders LIMIT 10;
-- View the first 5 records from an append-only table
SELECT * FROM `fluss_catalog`.`fluss_db`.events LIMIT 5;
-- Combine with projection to view only specific columns
SELECT order_id, amount, order_time
FROM `fluss_catalog`.`fluss_db`.orders LIMIT 20;
Buscas pontuais por chave primária
Para tabelas de chave primária, realize buscas pontuais precisas especificando a chave primária em uma cláusula WHERE. Isso aproveita o motor de armazenamento KV do Fluss para alcançar tempos de resposta no nível de milissegundos.
-- Perform a point lookup for a single record by its primary key
SELECT * FROM `fluss_catalog`.`fluss_db`.orders
WHERE order_id = 1001;
-- Perform a point lookup with a composite primary key
SELECT * FROM `fluss_catalog`.`fluss_db`.user_orders
WHERE user_id = 12345 AND order_id = 6789;
Agregações COUNT(*)
Execute uma consulta COUNT(*) em uma tabela de chave primária para obter rapidamente o número total de registros.
-- Count the total number of rows in a primary key table
SELECT COUNT(*) FROM `fluss_catalog`.`fluss_db`.orders;
Parâmetros WITH
Parâmetros de armazenamento
Os seguintes parâmetros são persistidos nos metadados da tabela.
|
Parâmetro |
Tipo |
Valor padrão |
Obrigatório |
Descrição |
|
|
Integer |
Nenhum |
Não |
O número de buckets para a tabela Fluss. Este parâmetro afeta o paralelismo de leitura e escrita de dados. O valor padrão é herdado da configuração |
|
|
String |
Nenhum |
Não |
As colunas usadas para distribuição de dados baseada em hash. Essas colunas devem ser um subconjunto da chave primária. Use vírgula para separar múltiplas colunas. |
|
|
Duration |
7d |
Não |
O período de retenção para dados de log. |
|
|
Integer |
Padrão do cluster |
Não |
O fator de replicação para a tabela de log. Este valor não pode ser maior que o número de tablet servers. |
|
|
Enum |
ARROW |
Não |
O formato de armazenamento para o log. As opções incluem |
|
|
Enum |
ZSTD |
Não |
O tipo de compressão para o formato ARROW. Opções válidas: |
|
|
Integer |
3 |
Não |
O nível de compressão ZSTD (1-22). |
|
|
Enum |
COMPACTED |
Não |
O formato de armazenamento KV. Opções válidas: |
|
|
Enum |
last_row |
Não |
A estratégia de mesclagem para a tabela de chave primária. Opções válidas: |
|
|
String |
Nenhum |
Condicionalmente obrigatório |
Obrigatório se |
|
|
Boolean |
false |
Não |
Ativa ou desativa o armazenamento em camadas no data lake. |
|
|
Enum |
Padrão do cluster |
Não |
O formato do data lake. Atualmente, apenas |
|
|
Integer |
2 |
Não |
O número de segmentos de log a serem retidos localmente após a ativação do armazenamento em camadas. |
Parâmetros de auto-particionamento
|
Parâmetro |
Tipo |
Valor padrão |
Obrigatório |
Descrição |
|
|
Boolean |
false |
Não |
Ativa ou desativa a criação automática de partição. |
|
|
Enum |
DAY |
Não |
A granularidade de tempo para auto-particionamento. Opções válidas: |
|
|
Integer |
2 |
Não |
O número de partições futuras a serem pré-criadas durante as verificações. |
|
|
Integer |
7 |
Não |
O número de partições históricas a serem retidas. Partições mais antigas são excluídas automaticamente. |
|
|
String |
Fuso horário do sistema |
Não |
O fuso horário usado para auto-particionamento. |
Parâmetros de leitura
Configure os seguintes parâmetros por meio da cláusula WITH ou hints SQL.
|
Parâmetro |
Tipo |
Valor padrão |
Obrigatório |
Descrição |
|
|
Enum |
full |
Não |
O modo de inicialização do consumo. Opções válidas: |
|
|
Long/String |
Nenhum |
Condicionalmente obrigatório |
O timestamp de inicialização, que pode ser um valor em milissegundos ou uma string no formato |
|
|
Duration |
1 minute |
Não |
O intervalo para descoberta automática de novas partições. Defina como um valor negativo para desativar a descoberta automática. |
|
|
Boolean |
true |
Não |
Especifica se deve realizar uma verificação CRC32 nas mensagens para garantir a integridade dos dados. |
|
|
Integer |
500 |
Não |
O número máximo de registros que uma única chamada |
|
|
MemorySize |
16mb |
Não |
O número máximo de bytes a serem buscados do servidor por requisição. |
|
|
MemorySize |
1mb |
Não |
O número máximo de bytes a serem buscados por bucket em uma única requisição. |
|
|
MemorySize |
1b |
Não |
O tamanho mínimo de dados que o servidor deve retornar para uma requisição de busca. |
|
|
Duration |
500ms |
Não |
O tempo máximo que o servidor aguarda quando o número mínimo de bytes não é atingido. |
|
|
String |
Diretório temporário do sistema |
Não |
O diretório local para armazenar arquivos temporários, como snapshots e segmentos de log. |
|
|
Integer |
4 |
Não |
O número de segmentos de log remoto a serem pré-buscados. |
|
|
Integer |
3 |
Não |
O número de threads usadas para baixar arquivos remotos. |
Parâmetros de escrita
Configure os seguintes parâmetros por meio da cláusula WITH ou hints SQL.
|
Parâmetro |
Tipo |
Valor padrão |
Obrigatório |
Descrição |
|
|
Boolean |
false |
Não |
Especifica se deve ignorar mensagens |
|
|
Boolean |
true |
Não |
Especifica se deve embaralhar dados por ID de bucket antes da escrita, o que pode melhorar o desempenho de gravação. |
|
|
MemorySize |
64mb |
Não |
O tamanho total de memória do buffer interno para dados de linha. |
|
|
MemorySize |
2mb |
Não |
O tamanho alvo do lote para registros dentro do mesmo bucket. |
|
|
Duration |
Long.MAX |
Não |
O tempo máximo que o writer bloqueia enquanto aguarda um segmento disponível. |
|
|
Duration |
100ms |
Não |
O tempo máximo para armazenar registros em buffer antes de enviá-los em lote. |
|
|
Enum |
STICKY |
Não |
A estratégia de atribuição de bucket para tabelas sem chave primária. Opções válidas: |
|
|
String |
all |
Não |
O nível de reconhecimento para escritas. |
|
|
MemorySize |
10mb |
Não |
O tamanho máximo de uma única requisição em bytes. |
|
|
Integer |
MAX_VALUE |
Não |
O número de vezes para tentar novamente um envio que falhou com um erro retriable. |
|
|
Boolean |
true |
Não |
Ativa escritas idempotentes, que fornecem semântica exactly-once e garantias de ordenação de mensagens. |
|
|
Integer |
5 |
Não |
O número máximo de requisições em trânsito por bucket. Aplica-se apenas quando escritas idempotentes estão ativadas. |
Parâmetros de tabela de dimensão
|
Parâmetro |
Tipo |
Valor padrão |
Obrigatório |
Descrição |
|
|
Boolean |
true |
Não |
Ativa lookup assíncrono, o que pode melhorar o throughput para joins de tabela de dimensão. |
|
|
Enum |
NONE |
Não |
A política de cache. Opções válidas: |
|
|
Integer |
3 |
Não |
O número máximo de tentativas se um lookup falhar. |
|
|
Duration |
Nenhum |
Não |
O período de expiração do cache após o último acesso. |
|
|
Duration |
Nenhum |
Não |
O período de expiração do cache após a última escrita. |
|
|
Boolean |
true |
Não |
Especifica se deve armazenar em cache chaves que não existem na tabela de dimensão (ou seja, cachear valores nulos). |
|
|
Long |
Nenhum |
Não |
O número máximo de linhas no cache. |
|
|
Integer |
25600 |
Não |
O tamanho da fila para operações de lookup pendentes. |
|
|
Integer |
128 |
Não |
O tamanho máximo do lote para combinar múltiplas operações de lookup. |
|
|
Integer |
128 |
Não |
O número máximo de requisições de lookup em trânsito. |
|
|
Duration |
100ms |
Não |
O tempo máximo de espera para que um lote de lookup seja preenchido antes de ser enviado. |
Ingestão de dados
O conector Fluss atua como um sink de dados em um job yaml de ingestão de dados.
Sintaxe
source:
type: xxx
sink:
type: fluss
name: Fluss Sink
bootstrap.servers: localhost:9123
properties.client.security.protocol: sasl
properties.client.security.sasl.mechanism: PLAIN
properties.client.security.sasl.username: developer
properties.client.security.sasl.password: developer-pass
pipeline:
schema.change.behavior: IGNORE
Alteração de esquema
O Fluss Server suporta a adição de novas colunas, mas não aceita outras operações de coluna (como excluir colunas, renomear colunas ou alterar tipos de coluna). Portanto, recomendamos usar a configuração padrão do Flink CDC schema.change.behavior = LENIENT:
Quando uma coluna é renomeada, o conector envia dois eventos. Ele não exclui a coluna original; em vez disso, altera o tipo de dados da coluna para anulável e adiciona uma nova coluna com o novo nome e tipo de dados anulável.
Quando uma coluna é removida, o conector envia um evento de alteração de tipo de coluna, mudando o tipo de dados da coluna para anulável.
Quando uma coluna é adicionada, o conector envia um evento de adição de coluna, mas altera o tipo de dados da coluna para anulável.
Este recurso requer VVR 11.6 ou versão posterior.
Parâmetros
|
Parâmetro |
Descrição |
Obrigatório |
Tipo |
Padrão |
Observações |
|
type |
Especifica o tipo do sink. |
Sim |
String |
Nenhum |
Valor fixo: fluss. |
|
name |
Especifica o nome do sink. |
Não |
String |
Nenhum |
Nenhuma. |
|
bootstrap.servers |
Especifica o endereço do Fluss Server. |
Sim |
String |
Nenhum |
Formato: |
|
bucket.key |
Especifica a bucket key. |
Não |
String |
Nenhum |
Especifique a política de distribuição de dados para cada tabela Fluss. Tabelas são separadas por Formato: Os dados são distribuídos para buckets com base no valor de hash da bucket key. A bucket key deve ser um subconjunto da chave primária e não pode incluir a chave de partição de uma tabela de chave primária. Se uma tabela tiver chave primária, mas nenhuma bucket key for especificada, a bucket key será, por padrão, a chave primária (excluindo a chave de partição). Se uma tabela não tiver chave primária e nenhuma bucket key for especificada, os dados serão distribuídos aleatoriamente para os buckets. Os valores de |
|
bucket.num |
Especifica o número de buckets para tabelas Fluss. |
Não |
String |
Nenhum |
O número de buckets para cada tabela Fluss. Os números são separados por Formato: Se uma tabela não tiver um número de buckets configurado, o item de configuração do lado do servidor Os valores de |
|
properties.table.* |
Propriedades da tabela Fluss. |
Não |
String |
Nenhum |
Passa parâmetros suportados pelas tabelas Fluss para o pipeline. Para mais informações, consulte Opções de tabela Fluss. |
|
properties.client.* |
Parâmetros do cliente Fluss. |
Não |
String |
Nenhum |
Passa parâmetros suportados pelo cliente Fluss para o pipeline. Para mais informações, consulte Opções do cliente Fluss. |
Mapeamento de tipos
A tabela a seguir mostra o mapeamento de tipos de dados para ingestão de dados.
|
Tipo de campo CDC |
Tipo de campo Fluss |
|
TINYINT |
TINYINT |
|
SMALLINT |
SMALLINT |
|
INT |
INT |
|
BIGINT |
BIGINT |
|
FLOAT |
FLOAT |
|
DOUBLE |
DOUBLE |
|
DECIMAL(p, s) |
DECIMAL(p, s) |
|
BOOLEAN |
BOOLEAN |
|
DATE |
DATE |
|
TIME |
TIME |
|
TIMESTAMP |
TIMESTAMP |
|
TIMESTAMP_LTZ |
TIMESTAMP_LTZ |
|
CHAR(n) |
CHAR(n) |
|
VARCHAR(n) |
STRING |
|
ARRAY |
ARRAY |
|
MAP |
MAP |
|
ROW |
ROW |
|
BINARY(n) |
Não suportado |
|
VARBINARY(n) |