Todos os produtos
Search
Central de documentação

Realtime Compute for Apache Flink:Stream storage Fluss

Última atualização: Aug 20, 2026

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

unified full and incremental consumption

Suporta consumo completo, incremental e unificado (completo e incremental).

data exploration

Permite exploração rápida de dados no modo batch do Flink SQL, útil para desenvolvimento, depuração, validação de dados e troubleshooting.

CDC log subscription and virtual table

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.

lookup join (dimension table join)

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.

partial update

Atualiza apenas os dados nas colunas modificadas, e não a linha inteira.

delta join

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.

merge engine

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.

lake-stream integration

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.

partitioned table

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.

add columns

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.num para 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-retention para 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

full

Padrão. Lê um snapshot completo primeiro e depois consome dados incrementais. Adequado para cenários que exigem dados históricos completos.

earliest

Consome dados a partir do offset de log mais antigo disponível, sem ler um snapshot completo.

latest

Consome dados a partir do offset mais recente. Apenas novos dados gerados após o início do job são consumidos.

timestamp

Consome dados a partir de um timestamp específico. Este modo exige que você também defina o parâmetro scan.startup.timestamp.

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

_change_type

STRING

O tipo de alteração. Para uma tabela de chave primária, os valores possíveis são insert, update_before, update_after e delete. Para uma tabela append-only, o único valor possível é insert.

_log_offset

BIGINT

O offset da alteração no log.

_commit_timestamp

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

_change_type

STRING

O tipo de alteração. Os valores possíveis são insert, update e delete.

_log_offset

BIGINT

O offset do log.

_commit_timestamp

TIMESTAMP_LTZ

O timestamp de commit.

before

ROW

Os dados da linha antes da alteração. O valor é NULL para operações insert.

after

ROW

Os dados da linha após a alteração. O valor é NULL para operações delete.

Mapeamento de eventos de alteração:

Tipo de alteração

before

after

insert

NULL

Novo valor

update

Valor antigo

Novo valor

delete

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), latest e timestamp. O modo full nã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

table.optimizer.delta-join.strategy

Defina como FORCE para impor o Delta Join. O job falhará se as condições não forem atendidas.

table.exec.async-lookup.buffer-capacity

A capacidade do buffer para requisições assíncronas. Recomendamos definir este valor na casa dos milhares.

table.exec.delta-join.cache-enabled

Ativa o cache local para reduzir requisições ao Fluss.

table.exec.delta-join.left.cache-size

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.

table.exec.delta-join.right.cache-size

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)

'lookup.async' = 'true'

Oferece alto throughput. Recomendado para a maioria dos casos de uso.

Síncrono

'lookup.async' = 'false'

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

last_row (padrão)

Mantém o último registro gravado. Dados posteriores sobrescrevem os anteriores. Adequado para a maioria dos cenários de upsert.

first_row

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.

versioned

Mantém o registro com o maior número de versão de uma coluna de versão especificada. Exige o parâmetro table.merge-engine.versioned.ver-column para especificar a coluna de versão. Recomendado para cenários que exigem controle da ordem de atualização de dados com base em versões.

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 ALTER TABLE. Indicada para cenários com número limitado e controlável de partições.

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 usando table.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âmetro num-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

table.auto-partition.enabled

Boolean

false

Especifica se o gerenciamento automático de partição deve ser ativado.

table.auto-partition.key

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.

table.auto-partition.time-unit

Enum

DAY

A granularidade de tempo para particionamento automático. Valores válidos: HOUR, DAY, MONTH, QUARTER e YEAR.

table.auto-partition.num-precreate

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.

table.auto-partition.num-retention

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.

table.auto-partition.time-zone

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 DAY ou HOUR. Para volumes menores, particione por MONTH ou QUARTER.

  • Defina uma política de retenção razoável: Use num-retention para 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 por max.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

table.datalake.enabled

Boolean

false

Ativa o armazenamento em camadas no lake.

table.datalake.format

Enum

Padrão do cluster

O formato do data lake. Atualmente, apenas paimon é suportado.

table.log.tiered.local-segments

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

bucket.num

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 default.bucket.number do cluster.

bucket.key

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.

table.log.ttl

Duration

7d

Não

O período de retenção para dados de log.

table.replication.factor

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.

table.log.format

Enum

ARROW

Não

O formato de armazenamento para o log. As opções incluem ARROW (formato colunar que suporta pushdown de consulta) e INDEXED.

table.log.arrow.compression.type

Enum

ZSTD

Não

O tipo de compressão para o formato ARROW. Opções válidas: NONE, LZ4_FRAME e ZSTD.

table.log.arrow.compression.zstd.level

Integer

3

Não

O nível de compressão ZSTD (1-22).

table.kv.format

Enum

COMPACTED

Não

O formato de armazenamento KV. Opções válidas: COMPACTED ou INDEXED.

table.merge-engine

Enum

last_row

Não

A estratégia de mesclagem para a tabela de chave primária. Opções válidas: first_row, versioned e last_row.

table.merge-engine.versioned.ver-column

String

Nenhum

Condicionalmente obrigatório

Obrigatório se table.merge-engine estiver definido como versioned. Especifica o nome da coluna de versão.

table.datalake.enabled

Boolean

false

Não

Ativa ou desativa o armazenamento em camadas no data lake.

table.datalake.format

Enum

Padrão do cluster

Não

O formato do data lake. Atualmente, apenas paimon é suportado.

table.log.tiered.local-segments

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

table.auto-partition.enabled

Boolean

false

Não

Ativa ou desativa a criação automática de partição.

table.auto-partition.time-unit

Enum

DAY

Não

A granularidade de tempo para auto-particionamento. Opções válidas: YEAR, QUARTER, MONTH, DAY e HOUR.

table.auto-partition.num-precreate

Integer

2

Não

O número de partições futuras a serem pré-criadas durante as verificações.

table.auto-partition.num-retention

Integer

7

Não

O número de partições históricas a serem retidas. Partições mais antigas são excluídas automaticamente.

table.auto-partition.time-zone

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

scan.startup.mode

Enum

full

Não

O modo de inicialização do consumo. Opções válidas: full, earliest, latest e timestamp.

scan.startup.timestamp

Long/String

Nenhum

Condicionalmente obrigatório

O timestamp de inicialização, que pode ser um valor em milissegundos ou uma string no formato yyyy-MM-dd HH:mm:ss. Aplica-se apenas quando scan.startup.mode está definido como timestamp.

scan.partition.discovery.interval

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.

client.scanner.log.check-crc

Boolean

true

Não

Especifica se deve realizar uma verificação CRC32 nas mensagens para garantir a integridade dos dados.

client.scanner.log.max-poll-records

Integer

500

Não

O número máximo de registros que uma única chamada poll() pode retornar.

client.scanner.log.fetch.max-bytes

MemorySize

16mb

Não

O número máximo de bytes a serem buscados do servidor por requisição.

client.scanner.log.fetch.max-bytes-for-bucket

MemorySize

1mb

Não

O número máximo de bytes a serem buscados por bucket em uma única requisição.

client.scanner.log.fetch.min-bytes

MemorySize

1b

Não

O tamanho mínimo de dados que o servidor deve retornar para uma requisição de busca.

client.scanner.log.fetch.wait-max-time

Duration

500ms

Não

O tempo máximo que o servidor aguarda quando o número mínimo de bytes não é atingido.

client.scanner.io.tmpdir

String

Diretório temporário do sistema

Não

O diretório local para armazenar arquivos temporários, como snapshots e segmentos de log.

client.scanner.remote-log.prefetch-num

Integer

4

Não

O número de segmentos de log remoto a serem pré-buscados.

client.remote-file.download-thread-num

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

sink.ignore-delete

Boolean

false

Não

Especifica se deve ignorar mensagens DELETE e UPDATE_BEFORE da origem.

sink.bucket-shuffle

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.

client.writer.buffer.memory-size

MemorySize

64mb

Não

O tamanho total de memória do buffer interno para dados de linha.

client.writer.batch-size

MemorySize

2mb

Não

O tamanho alvo do lote para registros dentro do mesmo bucket.

client.writer.buffer.wait-timeout

Duration

Long.MAX

Não

O tempo máximo que o writer bloqueia enquanto aguarda um segmento disponível.

client.writer.batch-timeout

Duration

100ms

Não

O tempo máximo para armazenar registros em buffer antes de enviá-los em lote.

client.writer.bucket.no-key-assigner

Enum

STICKY

Não

A estratégia de atribuição de bucket para tabelas sem chave primária. Opções válidas: STICKY ou ROUND_ROBIN.

client.writer.acks

String

all

Não

O nível de reconhecimento para escritas. all (ou -1): Aguarda todas as réplicas confirmarem. 1: Aguarda apenas o líder confirmar. 0: Não aguarda nenhum reconhecimento. A configuração all é recomendada para máxima durabilidade dos dados.

client.writer.request-max-size

MemorySize

10mb

Não

O tamanho máximo de uma única requisição em bytes.

client.writer.retries

Integer

MAX_VALUE

Não

O número de vezes para tentar novamente um envio que falhou com um erro retriable.

client.writer.enable-idempotence

Boolean

true

Não

Ativa escritas idempotentes, que fornecem semântica exactly-once e garantias de ordenação de mensagens.

client.writer.max-inflight-requests-per-bucket

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

lookup.async

Boolean

true

Não

Ativa lookup assíncrono, o que pode melhorar o throughput para joins de tabela de dimensão.

lookup.cache

Enum

NONE

Não

A política de cache. Opções válidas: NONE (sem cache) ou PARTIAL (cache parcial).

lookup.max-retries

Integer

3

Não

O número máximo de tentativas se um lookup falhar.

lookup.partial-cache.expire-after-access

Duration

Nenhum

Não

O período de expiração do cache após o último acesso.

lookup.partial-cache.expire-after-write

Duration

Nenhum

Não

O período de expiração do cache após a última escrita.

lookup.partial-cache.cache-missing-key

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).

lookup.partial-cache.max-rows

Long

Nenhum

Não

O número máximo de linhas no cache.

client.lookup.queue-size

Integer

25600

Não

O tamanho da fila para operações de lookup pendentes.

client.lookup.max-batch-size

Integer

128

Não

O tamanho máximo do lote para combinar múltiplas operações de lookup.

client.lookup.max-inflight-requests

Integer

128

Não

O número máximo de requisições de lookup em trânsito.

client.lookup.batch-timeout

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.

Nota

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: host:port,host:port,host:port. Use vírgulas (,) para separar múltiplos endereços.

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 ';', e bucket keys são separadas por ','.

Formato: database1.table1:key1,key2;database1.table2:key3.

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.key e bucket.num não podem ser alterados após a criação da tabela.

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: database1.table1:4;database1.table2:8.

Se uma tabela não tiver um número de buckets configurado, o item de configuração do lado do servidor default.bucket.number será usado por padrão.

Os valores de bucket.key e bucket.num não podem ser alterados após a criação da tabela.

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)