Todos os produtos
Search
Central de documentação

Realtime Compute for Apache Flink:Kafka

Última atualização: Jul 03, 2026

Utilize o conector Kafka como source, sink ou destino Flink CDC no Realtime Compute for Apache Flink.

Visão geral

O Apache Kafka é uma plataforma de streaming de eventos distribuída e open-source, amplamente utilizada para processamento de dados de alto desempenho, análises em tempo real e integração de dados. O conector Kafka para Realtime Compute for Apache Flink utiliza o cliente Apache Kafka open-source para oferecer alto throughput de dados, suporte à leitura e escrita de múltiplos formatos de dados e semântica exactly-once.

Categoria

Descrição

Tipos suportados

Source e sink SQL

Source e sink Flink CDC

Source e sink DataStream

Modo de execução

Streaming

Formatos de dados

Formatos de dados suportados

  • CSV

  • JSON

  • Apache Avro

  • Confluent Avro

  • Debezium JSON

  • Canal JSON

  • Maxwell JSON

  • Raw

  • Protobuf

Nota
  • O formato de dados Protobuf integrado é suportado apenas no Ververica Runtime (VVR) 8.0.9 e versões posteriores.

  • Cada formato de dados suportado possui parâmetros correspondentes que podem ser especificados na cláusula WITH. Para mais informações, consulte Formats.

Métricas

Métricas

  • Tabela Source

    • numRecordsIn

    • numRecordsInPerSecond

    • numBytesIn

    • numBytesInPerSecond

    • currentEmitEventTimeLag

    • currentFetchEventTimeLag

    • sourceIdleTime

    • pendingRecords

  • Tabela Sink

    • numRecordsOut

    • numRecordsOutPerSecond

    • numBytesOut

    • numBytesOutPerSecond

    • currentSendTime

Nota

Para mais informações sobre as métricas, consulte Metrics.

Tipos de API

SQL, DataStream, Flink CDC

Atualização/exclusão no sink

O conector suporta apenas a adição de dados a uma tabela sink. Não há suporte para atualizações ou exclusões.

Nota

Para mais informações sobre como atualizar ou excluir dados em uma Sink Table, consulte Upsert Kafka.

Pré-requisitos

Antes de começar, verifique se você atende aos pré-requisitos para o tipo do seu cluster Kafka:

  • Conectar-se a um cluster ApsaraMQ for Kafka

    • O cluster Kafka deve estar na versão 0.11 ou posterior.

    • Você criou um cluster ApsaraMQ for Kafka. Para mais informações, consulte Step 3: Create resources.

    • O workspace do Flink e o cluster Kafka estão na mesma Virtual Private Cloud (VPC), e você adicionou o bloco CIDR do workspace do Flink à lista de permissões do ApsaraMQ for Kafka. Para mais informações, consulte Configure whitelists.

    Importante

    Limitações na escrita de dados no ApsaraMQ for Kafka:

    • O ApsaraMQ for Kafka não suporta o formato de compactação Zstandard (zstd) para escritas.

    • O ApsaraMQ for Kafka não suporta escritas idempotentes ou transacionais, o que impede o uso da semântica exactly-once fornecida pelas tabelas sink do Kafka. A partir do Ververica Runtime (VVR) 8.0.0, o conector Kafka utiliza o cliente Kafka 3.x, onde a propriedade properties.enable.idempotence tem como padrão true. Portanto, para evitar falhas de escrita ao usar o Ververica Runtime (VVR) 8.0.0 ou posterior com o ApsaraMQ for Kafka, você deve adicionar a configuração properties.enable.idempotence=false à definição da sua tabela sink. Para uma comparação dos mecanismos de armazenamento e limitações de recursos do ApsaraMQ for Kafka, consulte Comparison between storage engines.

  • Conectar-se a um cluster Apache Kafka autogerenciado

    • O cluster Apache Kafka autogerenciado deve estar na versão 0.11 ou posterior.

    • O workspace do Flink possui conectividade de rede com o cluster Apache Kafka autogerenciado. Para detalhes sobre como se conectar a um cluster pela internet pública, consulte FAQ about network connectivity.

    • Apenas as opções de configuração de cliente para Apache Kafka versão 2.8 são suportadas. Para mais informações, consulte a documentação do Apache Kafka sobre Consumer Configs e Producer Configs.

Observações

Não recomendamos escritas transacionais devido a limitações conhecidas de design no Apache Flink e no Apache Kafka. Ao definir sink.delivery-guarantee = 'exactly-once', o conector Kafka habilita escritas transacionais, apresentando os seguintes problemas conhecidos:

  • Cada checkpoint gera um novo Transaction ID. Se o intervalo entre checkpoints for muito curto, o excesso de Transaction IDs pode esgotar a memória do coordenador do cluster Kafka, comprometendo a estabilidade do cluster.

  • Cada transação cria uma nova instância de Producer. Se muitas transações forem confirmadas simultaneamente, o TaskManager pode ficar sem memória, desestabilizando o job do Apache Flink.

  • Se vários jobs do Apache Flink usarem o mesmo sink.transactional-id-prefix, os Transaction IDs gerados podem entrar em conflito. Quando uma operação de escrita falha em um job, isso pode impedir o avanço do Log Start Offset (LSO) de uma partição do Apache Kafka, afetando todos os consumidores dessa partição.

Caso precise da semântica exactly-once, utilize o conector Upsert Kafka para escrever em uma tabela com chave primária, garantindo a idempotência. Se for indispensável o uso de escritas transacionais, consulte Notas de uso da semântica exactly-once.

Solucionar problemas de conectividade de rede

O erro Timed out waiting for a node assignment durante a falha na inicialização de um job do Realtime Compute for Apache Flink geralmente indica um problema de conectividade de rede entre o Realtime Compute for Apache Flink e o cluster Kafka.

Um cliente Kafka conecta-se aos brokers da seguinte forma:

  1. O cliente usa os endereços especificados em bootstrap.servers para estabelecer uma conexão inicial com o cluster Kafka.

  2. O cluster Kafka retorna metadados de cada broker, incluindo seus endpoints.

  3. Em seguida, o cliente utiliza esses endpoints para conectar-se aos brokers e ler ou gravar dados.

Mesmo que os endereços em bootstrap.servers estejam acessíveis, o cliente não conseguirá ler ou gravar dados se o Kafka retornar endpoints de broker incorretos. Esse problema é comum em arquiteturas de rede que utilizam proxy, encaminhamento de porta ou linha dedicada.

Etapas de solução de problemas

ApsaraMQ for Kafka

  1. Confirme o tipo de Endpoint

    • Default Endpoint (rede interna)

    • SASL Endpoint (rede interna com autenticação)

    • Public Endpoint (requer solicitação separada)

    Use o recurso Network Probe no console de desenvolvimento do Realtime Compute for Apache Flink para descartar problemas de conectividade com o endereço bootstrap.servers.

  2. Verifique grupos de segurança e listas de permissões

    Adicione o bloco CIDR do workspace do Realtime Compute for Apache Flink à lista de permissões da sua instância Kafka. Para mais informações, consulte View VPC CIDR Block e Configure a whitelist.

  3. Verifique a configuração SASL (se habilitada)

    Se você utilizar um endpoint SASL_SSL, garanta que os mecanismos JAAS, SSL e SASL estejam configurados corretamente no seu job do Realtime Compute for Apache Flink. A falta de autenticação pode causar falha na conexão durante a fase de handshake, o que também pode se manifestar como um timeout. Para mais informações, consulte Security and authentication.

Self-managed Kafka

  1. Use o recurso Network Probe

    Esse recurso ajuda a descartar problemas de conectividade com o endereço bootstrap.servers e a verificar se o endpoint interno ou público correto está sendo utilizado.

  2. Verifique grupos de segurança e listas de permissões

    • O grupo de segurança da instância Elastic Compute Service (ECS) deve permitir tráfego de entrada na porta do endpoint Kafka, que geralmente é 9092 ou 9093.

    • Garanta que qualquer firewall na instância ECS permita tráfego proveniente da VPC do seu workspace do Realtime Compute for Apache Flink. Para mais informações, consulte View VPC CIDR Block.

  3. Verifique a configuração

    1. Use a ferramenta zkCli.sh ou zookeeper-shell.sh para fazer login no cluster ZooKeeper utilizado pelo Kafka.

    2. Execute um comando para obter os metadados do broker. Por exemplo, execute get /brokers/ids/0. No campo endpoints da resposta, localize o endereço que o Kafka anuncia aos clientes.

      example

    3. Utilize o recurso Network Probe no console de desenvolvimento do Realtime Compute for Apache Flink para testar se esse endereço está acessível.

      Nota
      • Se o endereço não estiver acessível, entre em contato com os administradores do Kafka para verificar e corrigir as configurações listeners e advertised.listeners, garantindo que o endereço anunciado seja acessível pelo Realtime Compute for Apache Flink.

      • Para mais informações sobre conexões de clientes Kafka, consulte Troubleshoot Connectivity.

  4. Verifique a configuração SASL (se habilitada)

    Se você utilizar um endpoint SASL_SSL, garanta que os mecanismos JAAS, SSL e SASL estejam configurados corretamente no seu job do Realtime Compute for Apache Flink. A falta de autenticação pode causar falha na conexão durante a fase de handshake, o que também pode se manifestar como um timeout. Para mais informações, consulte Security and authentication.

SQL

Utilize o conector Kafka como tabela source ou sink em jobs SQL.

Sintaxe

CREATE TABLE KafkaTable (
  `user_id` BIGINT,
  `item_id` BIGINT,
  `behavior` STRING,
  `ts` TIMESTAMP_LTZ(3) METADATA FROM 'timestamp' VIRTUAL
) WITH (
  'connector' = 'kafka',
  'topic' = 'user_behavior',
  'properties.bootstrap.servers' = 'localhost:9092',
  'properties.group.id' = 'testGroup',
  'scan.startup.mode' = 'earliest-offset',
  'format' = 'csv'
)

Colunas de metadados

Defina colunas de metadados em uma tabela source ou sink para acessar os metadados das mensagens do Kafka. Por exemplo, ao assinar vários tópicos, uma coluna de metadados pode identificar de qual tópico cada registro se origina.

CREATE TABLE kafka_source (
  -- Read the message topic as the `record_topic` column
  `record_topic` STRING NOT NULL METADATA FROM 'topic' VIRTUAL,
  -- Read the timestamp from the ConsumerRecord as the `ts` column
  `ts` TIMESTAMP_LTZ(3) METADATA FROM 'timestamp' VIRTUAL,
  -- Read the message offset as the `record_offset` column
  `record_offset` BIGINT NOT NULL METADATA FROM 'offset' VIRTUAL,
  ...
) WITH (
  'connector' = 'kafka',
  ...
);

CREATE TABLE kafka_sink (
  -- Write the timestamp from the `ts` column as the ProducerRecord's timestamp to Kafka
  `ts` TIMESTAMP_LTZ(3) METADATA FROM 'timestamp' VIRTUAL,
  ...
) WITH (
  'connector' = 'kafka',
  ...
);

A tabela a seguir lista as colunas de metadados suportadas pelas tabelas source e sink do Kafka.

Chave

Tipo

Descrição

Escopo

topic

STRING NOT NULL METADATA VIRTUAL

Tópico da mensagem.

Tabela source

partition

INT NOT NULL METADATA VIRTUAL

ID da partição da mensagem.

Tabela source

headers

MAP<STRING, BYTES> NOT NULL METADATA VIRTUAL

Cabeçalhos da mensagem.

Tabela source e sink

leader-epoch

INT NOT NULL METADATA VIRTUAL

Leader-epoch da mensagem.

Tabela source

offset

BIGINT NOT NULL METADATA VIRTUAL

Offset da mensagem.

Tabela source

timestamp

TIMESTAMP(3) WITH LOCAL TIME ZONE NOT NULL METADATA VIRTUAL

Timestamp da mensagem.

Tabela source e sink

timestamp-type

STRING NOT NULL METADATA VIRTUAL

Tipo de timestamp da mensagem. Os valores válidos são:

  • NoTimestampType: Nenhum timestamp definido na mensagem.

  • CreateTime: Hora de criação da mensagem.

  • LogAppendTime: Hora em que a mensagem foi anexada ao log do broker Kafka.

Tabela source

__raw_key__

STRING NOT NULL METADATA VIRTUAL

Chave bruta da mensagem.

Tabela source e sink

Nota

Este parâmetro é suportado apenas no Ververica Runtime (VVR) 11.4 e versões posteriores.

__raw_value__

STRING NOT NULL METADATA VIRTUAL

Valor bruto da mensagem.

Tabela source e sink

Nota

Este parâmetro é suportado apenas no Ververica Runtime (VVR) 11.4 e versões posteriores.

Opções do conector

  • Geral

    Option

    Description

    Type

    Required

    Default

    Remarks

    connector

    Tipo do conector.

    String

    Sim

    O valor deve ser kafka.

    properties.bootstrap.servers

    Lista de endereços dos brokers Kafka.

    String

    Sim

    Formato: host:port,host:port,.... Separe os endereços com vírgulas (,).

    properties.*

    Propriedades adicionais para o cliente Kafka.

    String

    Não

    As chaves de propriedade devem ser opções válidas definidas na documentação oficial do Apache Kafka para Producer Configs e Consumer Configs.

    O Realtime Compute for Apache Flink remove o prefixo properties. e passa os pares chave-valor restantes para o cliente Kafka subjacente. Por exemplo, defina 'properties.allow.auto.create.topics' = 'false' para desativar a criação automática de tópicos.

    O conector Kafka sobrescreve estas opções, portanto não é possível configurá-las desta forma:

    • key.deserializer

    • value.deserializer

    format

    Formato para serializar e desserializar o valor de uma mensagem Kafka.

    String

    Não

    Formatos suportados:

    • csv

    • json

    • avro

    • debezium-json

    • canal-json

    • maxwell-json

    • avro-confluent

    • raw

    Nota

    Para mais informações, consulte Opções de formato.

    key.format

    Formato para serializar e desserializar a chave de uma mensagem Kafka.

    String

    Não

    Formatos suportados:

    • csv

    • json

    • avro

    • debezium-json

    • canal-json

    • maxwell-json

    • avro-confluent

    • raw

    Nota

    Ao usar esta configuração, key.options é obrigatório.

    key.fields

    Campos do esquema da tabela a serem usados como chave da mensagem Kafka.

    String

    Não

    Separe vários nomes de campos com ponto e vírgula (;). Por exemplo, 'field1;field2'.

    key.fields-prefix

    Prefixo personalizado para todos os campos de chave, evitando conflitos de nomes com os campos de valor.

    String

    Não

    Este prefixo distingue os campos de chave dos campos de valor. Ele é removido antes da serialização da chave ou após a desserialização.

    Nota

    Se você usar esta opção, value.fields-include deve ser definido como EXCEPT_KEY.

    value.format

    Formato para serializar e desserializar o valor de uma mensagem Kafka.

    String

    Não

    Esta configuração equivale a format. Defina apenas format ou value.format. Se ambos forem configurados, value.format substitui format.

    value.fields-include

    Define se os campos de chave estão incluídos no formato de valor.

    String

    Não

    ALL

    Valores válidos:

    • ALL: O valor da mensagem Kafka inclui todas as colunas da tabela.

    • EXCEPT_KEY: O valor da mensagem Kafka inclui todas as colunas da tabela, exceto aquelas definidas em key.fields.

  • Tabela source

    Option

    Description

    Type

    Required

    Default

    Remarks

    topic

    Tópico ou tópicos de leitura.

    String

    Não

    Para assinar vários tópicos, separe os nomes com ponto e vírgula (;), por exemplo, 'topic-1;topic-2'.

    Nota

    Especifique esta opção ou topic-pattern, mas não ambas.

    topic-pattern

    Expressão regular que corresponde aos tópicos a serem assinados. O consumidor assina todos os tópicos cujos nomes correspondem a este padrão.

    String

    Não

    Exemplos:

    • user_event_.*: Corresponde a todos os tópicos com o prefixo user_event_.

    • prod\.logs\..*: Corresponde a tópicos com o prefixo prod.logs. (o caractere . deve ter escape).

    Nota

    Especifique esta opção ou topic, mas não ambas.

    properties.group.id

    ID do grupo de consumidores da source Kafka.

    String

    Não

    KafkaSource-{Source-Table-Name}

    Ao usar um ID de grupo de consumidores pela primeira vez, defina também properties.auto.offset.reset como earliest ou latest para definir o offset inicial de partida.

    scan.startup.mode

    Offset de inicialização do consumidor Kafka.

    String

    Não

    group-offsets

    Valores válidos:

    • earliest-offset: Inicia a leitura a partir do offset mais antigo disponível.

    • latest-offset: Inicia a leitura a partir do offset mais recente.

    • group-offsets: Inicia a leitura a partir dos offsets confirmados do properties.group.id especificado.

    • timestamp: Inicia a leitura a partir do scan.startup.timestamp-millis especificado.

    • specific-offsets: Inicia a leitura a partir dos offsets especificados em scan.startup.specific-offsets.

    Nota

    Esta opção aplica-se apenas quando um job inicia sem estado. Se um job for retomado de um checkpoint, ele lê os offsets armazenados no estado do checkpoint.

    scan.startup.specific-offsets

    Offset inicial por partição quando scan.startup.mode é specific-offsets.

    String

    Não

    Por exemplo, partition:0,offset:42;partition:1,offset:300

    scan.startup.timestamp-millis

    Timestamp inicial em milissegundos quando scan.startup.mode está definido como timestamp.

    Long

    Não

    A unidade é milissegundos.

    scan.topic-partition-discovery.interval

    Intervalo de descoberta de partições.

    Duration

    Não

    5 minutos

    O conector descobre periodicamente novas partições e lê dados delas. Ao usar topic-pattern, o conector também descobre novos tópicos que correspondem ao padrão. Defina o intervalo como um valor não positivo para desativar esse recurso.

    Nota

    No Ververica Runtime (VVR) 6.0.x, a descoberta dinâmica de partições vem desativada por padrão. A partir do VVR 8.0, esse recurso é ativado por padrão com um intervalo de descoberta de 5 minutos.

    scan.header-filter

    Filtra mensagens com base nos cabeçalhos das mensagens Kafka.

    String

    Não

    Uma chave de cabeçalho e seu valor são separados por dois pontos (:). Várias condições de cabeçalho são conectadas usando operadores lógicos (& e |). O operador lógico NOT (!) também é suportado. Por exemplo, depart:toy|depart:book&!env:test retém dados Kafka se o cabeçalho contiver depart=toy ou depart=book e não contiver env=test.

    Nota
    • Esta opção é suportada apenas no Ververica Runtime (VVR) 8.0.6 e posterior.

    • Parênteses em expressões não são suportados.

    • As operações lógicas são avaliadas da esquerda para a direita.

    • Os valores dos cabeçalhos são convertidos em strings UTF-8 para comparação.

    scan.check.duplicated.group.id

    Verifica se outro consumidor ativo já está usando o properties.group.id.

    Boolean

    Não

    false

    Valores válidos:

    • true: Antes de iniciar o job, o sistema verifica se há um grupo de consumidores duplicado. Se encontrar um, o job falha para evitar conflitos.

    • false: Inicia o job sem verificar conflitos.

    Nota

    Esta opção é suportada apenas no Ververica Runtime (VVR) 6.0.4 e posterior.

  • Tabela sink

    Option

    Description

    Type

    Required

    Default

    Remarks

    topic

    Tópico de destino.

    String

    Sim

    sink.partitioner

    Mapeia registros de instâncias sink paralelas para partições Kafka.

    String

    Não

    default

    Valores válidos:

    • default: Usa o particionador padrão do Kafka.

    • fixed: Cada instância sink paralela grava em uma partição Kafka fixa.

    • round-robin: Os registros são distribuídos para as partições em esquema round-robin.

    • Particionador personalizado: Para usar um particionador personalizado, forneça o nome de classe totalmente qualificado de uma subclasse FlinkKafkaPartitioner, por exemplo, org.mycompany.MyPartitioner.

    sink.delivery-guarantee

    Garantia de entrega do sink.

    String

    Não

    at-least-once

    Valores válidos:

    • none: Não oferece garantias. Registros podem ser perdidos ou duplicados.

    • at-least-once: Garante que nenhum registro seja perdido, mas eles podem ser duplicados.

    • exactly-once: Usa transações Kafka para fornecer semântica exactly-once, garantindo que os registros não sejam perdidos nem duplicados.

    Nota

    Ao usar a semântica exactly-once, especifique também sink.transactional-id-prefix.

    sink.transactional-id-prefix

    Prefixo do ID de transação. Obrigatório quando sink.delivery-guarantee é exactly-once.

    String

    Sim, se sink.delivery-guarantee for exactly-once

    Obrigatório apenas quando sink.delivery-guarantee está definido como exactly-once.

    sink.parallelism

    Paralelismo do operador sink.

    Integer

    Não

    Por padrão, o framework determina o paralelismo com base nos operadores upstream.

Segurança e autenticação

Se o cluster Kafka exigir uma conexão segura ou autenticação, adicione o prefixo properties. às configurações relevantes de segurança e autenticação e defina-as no parâmetro WITH. O exemplo a seguir configura uma tabela Kafka para usar PLAIN como mecanismo SASL com uma configuração JAAS.

CREATE TABLE KafkaTable (
  `user_id` BIGINT,
  `item_id` BIGINT,
  `behavior` STRING,
  `ts` TIMESTAMP_LTZ(3) METADATA FROM 'timestamp'
) WITH (
  'connector' = 'kafka',
  ...
  'properties.security.protocol' = 'SASL_PLAINTEXT',
  'properties.sasl.mechanism' = 'PLAIN',
  'properties.sasl.jaas.config' = 'org.apache.flink.kafka.shaded.org.apache.kafka.common.security.plain.PlainLoginModule required username="username" password="password";'
)

O exemplo a seguir mostra como usar SASL_SSL como protocolo de segurança e SCRAM-SHA-256 como mecanismo SASL.

CREATE TABLE KafkaTable (
  `user_id` BIGINT,
  `item_id` BIGINT,
  `behavior` STRING,
  `ts` TIMESTAMP_LTZ(3) METADATA FROM 'timestamp'
) WITH (
  'connector' = 'kafka',
  ...
  'properties.security.protocol' = 'SASL_SSL',
  /* SSL configuration */
  /* Path to the truststore for the server's CA certificate. */
  /* Files uploaded using Artifacts are stored in the /flink/usrlib/ directory. */
  'properties.ssl.truststore.location' = '/flink/usrlib/kafka.client.truststore.jks',
  'properties.ssl.truststore.password' = 'test1234',
  /* If client authentication is required, you must also configure the path to the keystore (private key). */
  'properties.ssl.keystore.location' = '/flink/usrlib/kafka.client.keystore.jks',
  'properties.ssl.keystore.password' = 'test1234',
  /* The algorithm used to verify the server hostname. An empty string disables hostname verification. */
  'properties.ssl.endpoint.identification.algorithm' = '',
  /* SASL configuration */
  /* Set the SASL mechanism to SCRAM-SHA-256. */
  'properties.sasl.mechanism' = 'SCRAM-SHA-256',
  /* Configure JAAS. */
  'properties.sasl.jaas.config' = 'org.apache.flink.kafka.shaded.org.apache.kafka.common.security.scram.ScramLoginModule required username="username" password="password";'
)

Use o recurso Artifacts do console Realtime Compute for Apache Flink para fazer upload do certificado CA e da chave privada mencionados no exemplo. Os arquivos enviados são armazenados no diretório /flink/usrlib. Para usar um arquivo de certificado CA chamado my-truststore.jks, defina a propriedade 'properties.ssl.truststore.location' na cláusula WITH de uma das duas maneiras seguintes:

  • Defina 'properties.ssl.truststore.location' = '/flink/usrlib/my-truststore.jks'. Este método evita o download dinâmico de arquivos do Object Storage Service (OSS) durante a execução, mas não suporta o Debug Mode.

  • Se a versão do mecanismo Realtime Compute for VVR 11.5 ou posterior, configure properties.ssl.truststore.location e properties.ssl.keystore.location com um caminho absoluto do OSS. O formato do caminho do arquivo é oss://flink-fullymanaged-<Workspace ID>/artifacts/namespaces/<Namespace name>/<file name>. Este método baixa dinamicamente os arquivos do OSS durante a execução do Flink e suporta o Debug Mode.

Nota
  • Verifique sua configuração: Os exemplos neste tópico mostram configurações comuns. Antes de configurar o conector Kafka, entre em contato com sua equipe de O&M do Kafka para obter as configurações corretas de segurança e autenticação.

  • Escape: Diferente do Apache Flink nativo, o editor SQL do Realtime Compute for Apache Flink escapa aspas duplas (") por padrão. Portanto, não é necessário adicionar barras invertidas (\) para escapar as aspas duplas usadas no nome de usuário e senha na opção properties.sasl.jaas.config.

Offset inicial da tabela source

Modo de inicialização

Configure a opção scan.startup.mode para especificar o offset a partir do qual uma tabela source Kafka começa a ler dados. Os valores válidos incluem:

  • earliest-offset: Inicia a leitura a partir do offset mais antigo.

  • latest-offset: Inicia a leitura a partir do offset mais recente.

  • group-offsets: Inicia a leitura a partir dos offsets confirmados para o grupo de consumidores especificado em properties.group.id.

  • timestamp: Inicia a leitura a partir da primeira mensagem com timestamp maior ou igual ao valor especificado em scan.startup.timestamp-millis.

  • specific-offsets: Inicia a leitura a partir dos offsets de partição específicos definidos em scan.startup.specific-offsets.

Nota
  • Se você não especificar um modo de inicialização, o padrão será 'group-offsets'.

  • A opção scan.startup.mode aplica-se apenas a jobs sem estado. Quando um job com estado é iniciado, ele sempre consome a partir dos offsets armazenados em seu estado.

Exemplo:

CREATE TEMPORARY TABLE kafka_source (
  ...
) WITH (
  'connector' = 'kafka',
  ...
  -- Consume from the earliest offset.
  'scan.startup.mode' = 'earliest-offset',
  -- Consume from the latest offset.
  'scan.startup.mode' = 'latest-offset',
  -- Consume from the committed offsets of the consumer group "my-group".
  'properties.group.id' = 'my-group',
  'scan.startup.mode' = 'group-offsets',
  'properties.auto.offset.reset' = 'earliest', -- If "my-group" is used for the first time, consumption starts from the earliest offset.
  'properties.auto.offset.reset' = 'latest', -- If "my-group" is used for the first time, consumption starts from the latest offset.
  -- Consume from the specified timestamp in milliseconds: 1655395200000.
  'scan.startup.mode' = 'timestamp',
  'scan.startup.timestamp-millis' = '1655395200000',
  -- Consume from specific offsets.
  'scan.startup.mode' = 'specific-offsets',
  'scan.startup.specific-offsets' = 'partition:0,offset:42;partition:1,offset:300'
);

Prioridade do offset inicial

O offset inicial da tabela source é determinado pelas regras a seguir, em ordem de prioridade:

Prioridade (da maior para a menor)

O offset armazenado em um checkpoint ou savepoint.

A hora de início selecionada no console Realtime Compute for Apache Flink durante a inicialização do job.

O offset inicial especificado por scan.startup.mode na cláusula WITH.

Se scan.startup.mode não for especificado, group-offsets será usado para iniciar o consumo a partir dos offsets do grupo de consumidores correspondente.

Se o offset determinado por qualquer uma dessas etapas for inválido, por exemplo, porque expirou ou ocorreu um problema no cluster Kafka, o sistema redefine o offset de acordo com a política especificada em properties.auto.offset.reset. Se esta opção não estiver configurada, o sistema lança uma exceção que requer intervenção do usuário.

Um cenário comum envolve iniciar o consumo com um novo ID de grupo de consumidores. A tabela source primeiro consulta o cluster Kafka para obter os offsets confirmados desse grupo. Como o ID do grupo é novo, nenhum offset válido é encontrado. Consequentemente, o sistema redefine o offset de acordo com a política especificada em properties.auto.offset.reset. Portanto, ao consumir com um novo ID de grupo, configure a opção properties.auto.offset.reset.

Confirmação de offsets da source

A tabela source Kafka confirma seu offset de consumo no cluster Kafka apenas após um checkpoint bem-sucedido; portanto, um longo intervalo de checkpoint causa atraso no offset confirmado. A tabela source armazena seu progresso real de leitura no estado do checkpoint, que o sistema usa para recuperação de falhas. Os offsets confirmados servem apenas como monitor de progresso e não são usados para recuperação, logo, falhas de confirmação não afetam a precisão dos dados.

Particionador de sink personalizado

Caso a estratégia de particionamento nativa do Kafka não atenda aos seus requisitos, implemente um particionador personalizado estendendo a classe FlinkKafkaPartitioner. Após concluir o desenvolvimento, compile seu código em um pacote JAR e faça o upload utilizando o recurso Artifacts no console do Realtime Compute. Depois que o pacote JAR for carregado e referenciado, defina o parâmetro sink.partitioner na cláusula WITH com o nome de classe totalmente qualificado do seu particionador, por exemplo, org.mycompany.MyPartitioner.

Kafka, Upsert Kafka e catálogo Kafka JSON

O Kafka é uma plataforma de streaming de eventos do tipo append-only que não suporta atualizações ou exclusões de dados. No SQL de streaming, uma tabela de sink padrão do Kafka não consegue processar dados de Change Data Capture (CDC) da origem nem a lógica de retração de operadores como agregação e junção. Se você precisar gravar dados que contenham alterações ou retrações, utilize uma tabela de sink Upsert Kafka.

Para simplificar a sincronização em lote de dados de Change Data Capture (CDC) de uma ou mais tabelas de banco de dados de origem para o Kafka, use um catálogo Kafka JSON. Quando os dados armazenados no Kafka estão em formato JSON, o catálogo Kafka JSON permite pular a etapa de definição de schema e parâmetros WITH. Para mais detalhes, consulte Gerenciar catálogos Kafka JSON.

Exemplos

Exemplo 1: Leitura e gravação no Kafka

Este exemplo lê dados de um tópico de origem do Kafka e os grava em um tópico de sink. Os dados estão no formato CSV.

CREATE TEMPORARY TABLE kafka_source (
  id INT,
  name STRING,
  age INT
) WITH (
  'connector' = 'kafka',
  'topic' = 'source',
  'properties.bootstrap.servers' = '<yourKafkaBrokers>',
  'properties.group.id' = '<yourKafkaConsumerGroupId>',
  'format' = 'csv'
);

CREATE TEMPORARY TABLE kafka_sink (
  id INT,
  name STRING,
  age INT
) WITH (
  'connector' = 'kafka',
  'topic' = 'sink',
  'properties.bootstrap.servers' = '<yourKafkaBrokers>',
  'properties.group.id' = '<yourKafkaConsumerGroupId>',
  'format' = 'csv'
);

INSERT INTO kafka_sink SELECT id, name, age FROM kafka_source;

Exemplo 2: Sincronizar schema e dados da tabela

Use o conector do Kafka para sincronizar mensagens de um tópico do Kafka para o Hologres em tempo real. Para evitar mensagens duplicadas no Hologres durante um failover, utilize o offset e o ID da partição das mensagens do Kafka como chave primária composta.

CREATE TEMPORARY TABLE kafkaTable (
  `offset` INT NOT NULL METADATA,
  `part` BIGINT NOT NULL METADATA FROM 'partition',
  PRIMARY KEY (`part`, `offset`) NOT ENFORCED
) WITH (
  'connector' = 'kafka',
  'properties.bootstrap.servers' = '<yourKafkaBrokers>',
  'topic' = 'kafka_evolution_demo',
  'scan.startup.mode' = 'earliest-offset',
  'format' = 'json',
  'json.infer-schema.flatten-nested-columns.enable' = 'true'
    -- Optional. Flattens all nested columns.
);

CREATE TABLE IF NOT EXISTS hologres.kafka.`sync_kafka`
WITH (
  'connector' = 'hologres'
) AS TABLE vvp.`default`.kafkaTable;

Exemplo 3: Sincronizar chaves e valores do Kafka

Se a chave da mensagem do Kafka contiver informações relevantes, sincronize tanto a chave quanto o valor.

CREATE TEMPORARY TABLE kafkaTable (
  `key_id` INT NOT NULL,
  `val_name` VARCHAR(200)
) WITH (
  'connector' = 'kafka',
  'properties.bootstrap.servers' = '<yourKafkaBrokers>',
  'topic' = 'kafka_evolution_demo',
  'scan.startup.mode' = 'earliest-offset',
  'key.format' = 'json',
  'value.format' = 'json',
  'key.fields' = 'key_id',
  'key.fields-prefix' = 'key_',
  'value.fields-prefix' = 'val_',
  'value.fields-include' = 'EXCEPT_KEY'
);

CREATE TABLE IF NOT EXISTS hologres.kafka.`sync_kafka`(
WITH (
  'connector' = 'hologres'
) AS TABLE vvp.`default`.kafkaTable;
Nota

As chaves de mensagens do Kafka não suportam Schema Evolution ou análise automática de tipos. Declare o schema manualmente.

Exemplo 4: Sincronizar dados e realizar computação

Ao sincronizar dados do Kafka para o Hologres, talvez sejam necessárias transformações leves.

CREATE TEMPORARY TABLE kafkaTable (
  `distinct_id` INT NOT NULL,
  `properties` STRING,
  `timestamp` TIMESTAMP_LTZ METADATA,
  `date` AS CAST(`timestamp` AS DATE)
) WITH (
  'connector' = 'kafka',
  'properties.bootstrap.servers' = '<yourKafkaBrokers>',
  'topic' = 'kafka_evolution_demo',
  'scan.startup.mode' = 'earliest-offset',
  'key.format' = 'json',
  'value.format' = 'json',
  'key.fields' = 'key_id',
  'key.fields-prefix' = 'key_'
);

CREATE TABLE IF NOT EXISTS hologres.kafka.`sync_kafka` WITH (
   'connector' = 'hologres'
) AS TABLE vvp.`default`.kafkaTable
ADD COLUMN
  `order_id` AS COALESCE(JSON_VALUE(`properties`, '$.order_id'), 'default');
--Use COALESCE to handle null values.

Exemplo 5: Analisar JSON aninhado

A seguir, veja um exemplo de mensagem JSON:

{
  "id": 101,
  "name": "VVP",
  "properties": {
    "owner": "Alibaba Cloud",
    "engine": "Flink"
  }
}

Para evitar o uso de funções como JSON_VALUE(payload, '$.properties.owner') na análise de campos, defina a estrutura diretamente no DDL de origem:

CREATE TEMPORARY TABLE kafka_source (
  id          VARCHAR,
  `name`      VARCHAR,
  properties  ROW<`owner` STRING, engine STRING>
) WITH (
  'connector' = 'kafka',
  'topic' = 'xxx',
  'properties.bootstrap.servers' = 'xxx',
  'scan.startup.mode' = 'earliest-offset',
  'format' = 'json'
);

Com essa abordagem, o Flink analisa o JSON em campos estruturados durante a fase de leitura. Consultas SQL subsequentes podem referenciar diretamente properties.owner sem chamadas adicionais de função, o que melhora o desempenho geral.

DataStream API

Importante

Para ler ou gravar dados com a DataStream API, use o DataStream Connector correspondente para se conectar ao Realtime Compute for Apache Flink. Para obter mais informações sobre como configurar um DataStream Connector, consulte Integrar conectores DataStream.

  • Criar uma origem Kafka

    A Kafka Source fornece uma classe builder para criar uma instância de Kafka Source. O código de exemplo a seguir cria uma Kafka Source que consome dados a partir do Offset mais antigo do Topic input-topic. O Consumer Group é my-group e o Value da Message do Kafka é desserializado como uma string.

    Java

    KafkaSource<String> source = KafkaSource.<String>builder()
        .setBootstrapServers(brokers)
        .setTopics("input-topic")
        .setGroupId("my-group")
        .setStartingOffsets(OffsetsInitializer.earliest())
        .setValueOnlyDeserializer(new SimpleStringSchema())
        .build();
    
    env.fromSource(source, WatermarkStrategy.noWatermarks(), "Kafka Source");

    Para criar uma Kafka Source, especifique as seguintes propriedades.

    Parâmetro

    Descrição

    BootstrapServers

    Lista de endereços de brokers do Kafka. Defina esta propriedade chamando o método setBootstrapServers(String).

    GroupId

    ID do Consumer Group. Defina esta propriedade chamando o método setGroupId(String).

    Topics ou Partitions

    Tópicos ou partições para assinar. A Kafka Source oferece suporte aos três métodos a seguir para assinar tópicos ou partições:

    • Assina todas as partições dos tópicos em uma lista.

      KafkaSource.builder().setTopics("topic-a","topic-b")
    • Padrão de tópico: Assina todas as partições de tópicos cujos nomes correspondem à expressão regular especificada.

      KafkaSource.builder().setTopicPattern("topic.*")
    • Lista de partições, onde é possível assinar uma partição específica.

      final HashSet<TopicPartition> partitionSet = new HashSet<>(Arrays.asList(
              new TopicPartition("topic-a", 0),    // Partition 0 of topic "topic-a"
              new TopicPartition("topic-b", 5)));  // Partition 5 of topic "topic-b"
      KafkaSource.builder().setPartitions(partitionSet)

    Deserializer

    Desserializador usado para analisar mensagens do Kafka.

    Especifique o desserializador usando o método setDeserializer(KafkaRecordDeserializationSchema). O KafkaRecordDeserializationSchema define como analisar um ConsumerRecord do Kafka. Se você precisar apenas analisar o Value de uma Message do Kafka, use um dos seguintes métodos:

    • Utilize o método setValueOnlyDeserializer(DeserializationSchema) da classe builder. O DeserializationSchema define como analisar os dados binários do Value da Message do Kafka.

    • Use uma classe que implemente a interface Deserializer do Kafka. Por exemplo, use StringDeserializer para analisar o Value da Message do Kafka como uma string.

      import org.apache.kafka.common.serialization.StringDeserializer;
      
      KafkaSource.<String>builder()
              .setDeserializer(KafkaRecordDeserializationSchema.valueOnly(StringDeserializer.class));
    Nota

    Para analisar um ConsumerRecord completo, implemente a interface KafkaRecordDeserializationSchema.

    POM

    O Kafka DataStream Connector está disponível no repositório central do Maven.

    <dependency>
        <groupId>com.alibaba.ververica</groupId>
        <artifactId>ververica-connector-kafka</artifactId>
        <version>${vvr-version}</version>
    </dependency>

    Ao usar o DataStream Connector do Kafka, considere as seguintes propriedades:

    • Offset inicial

      Uma Kafka Source especifica seu offset inicial usando um inicializador de offset (OffsetsInitializer). Os inicializadores integrados incluem:

      Inicializador de offset

      Código

      Inicia o consumo a partir do Offset mais antigo.

      KafkaSource.builder().setStartingOffsets(OffsetsInitializer.earliest())

      Inicia o consumo a partir do Offset mais recente.

      KafkaSource.builder().setStartingOffsets(OffsetsInitializer.latest())

      Começa a consumir dados cujo timestamp seja maior ou igual ao tempo especificado. A unidade é milissegundos.

      KafkaSource.builder().setStartingOffsets(OffsetsInitializer.timestamp(1592323200000L))

      Inicia o consumo a partir do Offset confirmado do Consumer Group. Se não existir nenhum Offset confirmado, usa a estratégia de redefinição especificada (por exemplo, o Offset mais antigo).

      KafkaSource.builder().setStartingOffsets(OffsetsInitializer.committedOffsets(OffsetResetStrategy.EARLIEST))

      O consumo começa a partir do offset confirmado pelo consumer group, sem nenhuma política de redefinição de offset especificada.

      KafkaSource.builder().setStartingOffsets(OffsetsInitializer.committedOffsets())

      Nota
      • Se os inicializadores integrados não atenderem aos seus requisitos, implemente um inicializador de offset personalizado.

      • Caso nenhum inicializador de offset seja especificado, o padrão será OffsetsInitializer.earliest().

    • Modo de streaming e modo em lote

      A Kafka Source suporta tanto o modo de streaming quanto o Batch Mode. Por padrão, ela opera em modo de streaming, onde o Job é executado indefinidamente até falhar ou ser cancelado. Para configurar a Kafka Source para execução em Batch Mode, use setBounded(OffsetsInitializer) para especificar um Offset de parada. A Kafka Source encerra quando todas as partições atingem seus offsets de parada especificados.

      Nota

      Uma Kafka Source em modo de streaming normalmente não possui um Offset de parada. No entanto, para fins de teste, use setUnbounded(OffsetsInitializer) para especificar um Offset de parada mesmo no modo de streaming. Observe os nomes diferentes dos métodos para especificar o Offset de parada: setUnbounded para modo de streaming e setBounded para Batch Mode.

    • Descoberta dinâmica de partições

      Para lidar com o dimensionamento de Topic ou a criação de novos tópicos sem reiniciar o Job do Flink, ative a descoberta dinâmica de partições ao assinar tópicos por padrão. Esse recurso fica desativado por padrão e deve ser ativado explicitamente:

      KafkaSource.builder()
          .setProperty("partition.discovery.interval.ms", "10000") // Discover new partitions every 10 seconds.
      Importante

      O recurso de descoberta dinâmica de partições depende do mecanismo de atualização de metadados do cluster Kafka. Se o cluster Kafka não atualizar as informações de partição em tempo hábil, novas partições poderão não ser descobertas. Certifique-se de que a configuração partition.discovery.interval.ms do cluster Kafka corresponda ao seu cenário real.

    • Tempo de evento e watermark

      Por padrão, a Kafka Source usa o timestamp da Message do Kafka como Event Time. Defina uma estratégia personalizada de Watermark para extrair o Event Time do corpo da Message e emitir uma Watermark downstream.

      env.fromSource(kafkaSource, new CustomWatermarkStrategy(), "Kafka Source With Custom Watermark Strategy")

      Para saber mais sobre estratégias personalizadas de Watermark, consulte Generating Watermarks.

      Nota

      Se uma subtarefa de origem estiver ociosa (por exemplo, quando uma Partition do Kafka não tem novos dados ou o Parallelism da origem é superior ao número de partições do Kafka), a Watermark dessa subtarefa não avançará. Isso pode bloquear computações de janela downstream.

      Para resolver esse problema, considere as seguintes soluções:

      • Configure um tempo limite de ociosidade da origem: Ative a Property table.exec.source.idle-timeout para marcar uma origem ociosa como temporariamente inativa. Isso permite que a Watermark downstream avance.

      • Defina um Parallelism adequado: Garanta que o Parallelism da origem não seja maior que o número de partições do Kafka.

    • Confirmação de offset

      Quando o checkpointing está ativado, a Kafka Source confirma o Offset atual do consumidor no Kafka assim que um Checkpoint é concluído. Isso garante que o estado do Checkpoint do Flink seja consistente com o Offset confirmado no broker do Kafka. Se o checkpointing estiver desativado, a Kafka Source dependerá do mecanismo interno de confirmação periódica automática de Offset do consumidor Kafka. Esse recurso é controlado pelas propriedades do consumidor Kafka enable.auto.commit e auto.commit.interval.ms.

      Nota

      A Kafka Source não depende de offsets confirmados para tolerância a falhas e recuperação. A confirmação de offsets serve apenas para monitorar o progresso do consumidor Kafka e do Consumer Group.

    • Outras propriedades

      Além das propriedades mencionadas, use setProperties(Properties) e setProperty(String, String) para definir qualquer Property para a Kafka Source e seu consumidor Kafka subjacente. A Kafka Source fornece as seguintes propriedades específicas.

      Parâmetro

      Descrição

      client.id.prefix

      Prefixo do Client ID para o consumidor Kafka.

      partition.discovery.interval.ms

      Intervalo de descoberta de partições em milissegundos. Um valor de -1 desativa a descoberta dinâmica de partições.

      Nota

      No Batch Mode, esta propriedade é definida automaticamente como -1.

      register.consumer.metrics

      Registra métricas do consumidor Kafka no Flink.

      Outras configurações do consumidor Kafka

      Para obter uma lista completa das configurações do consumidor Kafka, consulte a documentação oficial do Apache Kafka.

      Importante

      Para garantir a operação correta, o DataStream Connector do Kafka substitui as seguintes propriedades configuradas manualmente:

      • key.deserializer é sempre substituído por org.apache.kafka.common.serialization.ByteArrayDeserializer.

      • value.deserializer é sempre substituído por org.apache.kafka.common.serialization.ByteArrayDeserializer.

      • auto.offset.reset.strategy é substituído pela estratégia fornecida pelo OffsetsInitializer.

      O exemplo a seguir mostra como configurar um consumidor Kafka para usar o mecanismo PLAIN SASL e fornecer uma configuração JAAS.

      KafkaSource.builder()
          .setProperty("sasl.mechanism", "PLAIN")
          .setProperty("sasl.jaas.config", "org.apache.kafka.common.security.plain.PlainLoginModule required username=\"username\" password=\"password\";")
    • Monitoramento

      A Kafka Source expõe métricas por meio do sistema de métricas do Flink para monitoramento e diagnóstico.

      • Escopo das métricas

        Todas as métricas do leitor de origem Kafka são registradas no grupo de métricas KafkaSourceReader, que é um subgrupo do grupo de métricas do operador. Métricas relacionadas a uma partição de tópico específica são registradas no subgrupo KafkaSourceReader.topic.<topic_name>.partition.<partition_id>.

        Por exemplo, a métrica de Consumer Offset atual (currentOffset) para a Partição 1 do tópico "my-topic" está disponível em .operator.KafkaSourceReader.topic.my-topic.partition.1.currentOffset. O número de confirmações bem-sucedidas (commitsSucceeded) está disponível em .operator.KafkaSourceReader.commitsSucceeded.

      • Lista de métricas

        Métrica

        Descrição

        Escopo

        currentOffset

        O Offset atual do consumidor de uma partição.

        TopicPartition

        committedOffset

        O último Offset confirmado para uma partição.

        TopicPartition

        commitsSucceeded

        Número total de confirmações de offset bem-sucedidas.

        KafkaSourceReader

        commitsFailed

        Número de confirmações com falha

        KafkaSourceReader

      • Métricas do consumidor Kafka

        As métricas do consumidor Kafka subjacente são registradas no grupo de métricas KafkaSourceReader.KafkaConsumer. Por exemplo, a métrica records-consumed-total é registrada em .operator.KafkaSourceReader.KafkaConsumer.records-consumed-total.

        Use a Property register.consumer.metrics para especificar se deseja registrar as métricas do consumidor Kafka. Esta opção está ativada por padrão (true). Para obter mais informações sobre as métricas do consumidor Kafka, consulte a documentação do Apache Kafka.

  • Criar um sink Kafka

    O Kafka Sink do Flink grava um fluxo de dados em um ou mais tópicos do Kafka.

    DataStream<String> stream = ...
    
    Properties kafkaProperties = new Properties();
    kafkaProperties.setProperty("bootstrap.servers", "localhost:9092");
    
    KafkaSink<String> sink = KafkaSink.<String>builder()
            .setKafkaProducerConfig(kafkaProperties)
            .setRecordSerializer(
                    KafkaRecordSerializationSchema.builder()
                            .setTopic("my-topic")
                            .setValueSerializationSchema(new SimpleStringSchema())
                            .build())
            .setDeliveryGuarantee(DeliveryGuarantee.AT_LEAST_ONCE)
            .build();
    
    stream.sinkTo(sink);

    Para criar um Kafka Sink, configure as seguintes propriedades.

    Parâmetro

    Descrição

    Propriedades do cliente Kafka

    A Property bootstrap.servers é obrigatória. Ela especifica uma lista separada por vírgulas de brokers do Kafka.

    Serializador de registros

    Forneça um KafkaRecordSerializationSchema para converter dados de entrada em um ProducerRecord do Kafka. O Flink fornece um construtor de schema que oferece componentes comuns, como serialização para chaves e valores de mensagens, seleção de tópicos e particionamento de mensagens. Também é possível implementar as interfaces correspondentes para um controle mais granular. O método ProducerRecord<byte[], byte[]> serialize(T element, KafkaSinkContext context, Long timestamp) é chamado para cada registro recebido, a fim de gerar um ProducerRecord a ser gravado no Kafka.

    O ProducerRecord oferece controle refinado sobre como cada registro é gravado no Kafka, permitindo que você:

    • Defina o Topic de destino.

    • Defina a Key da Message.

    • Especifique a Partition de destino.

    Garantia de entrega

    O parâmetro bootstrap.servers é obrigatório e especifica uma lista separada por vírgulas de brokers do Kafka.

    Garantia de entrega

    Quando os checkpoints do Flink estão ativados, o Kafka Sink do Flink pode fornecer semântica exactly-once. Além de ativar os checkpoints, use o parâmetro DeliveryGuarantee para especificar diferentes garantias de entrega. O parâmetro DeliveryGuarantee oferece as seguintes opções:

    • DeliveryGuarantee.NONE: (Padrão) O Flink não oferece garantias. Dados podem ser perdidos ou duplicados.

    • DeliveryGuarantee.AT_LEAST_ONCE: Garante que nenhum dado seja perdido, mas pode ocorrer duplicação.

    • DeliveryGuarantee.EXACTLY_ONCE: Usa transações do Kafka para fornecer semântica exactly-once.

      Nota

      Ao usar a semântica EXACTLY_ONCE, consulte Considerações para semântica exactly-once.

Flink CDC

Use o conector do Kafka como origem ou sink para criar jobs YAML para o Flink CDC.

Limitações

  • Utilize o Realtime Compute for Apache Flink (VVR) 11.1 ou posterior para ingerir dados do Flink CDC a partir de uma fonte de dados Kafka.

  • Somente JSON, Debezium JSON e Canal JSON são suportados.

  • Apenas o Realtime Compute for Apache Flink (VVR) 8.0.11 e versões posteriores oferecem suporte à leitura de dados de uma única tabela distribuída em várias Partitions.

Sintaxe

source:
  type: kafka
  name: Kafka source
  properties.bootstrap.servers: localhost:9092
  topic: ${kafka.topic}
sink:
  type: kafka
  name: Kafka Sink
  properties.bootstrap.servers: localhost:9092

Parâmetro

  • Geral

    Parâmetro

    Descrição

    Obrigatório

    Tipo

    Padrão

    Observações

    type

    Tipo de source ou sink.

    Sim

    String

    O valor deve ser kafka.

    name

    Nome do source ou sink.

    Não

    String

    properties.bootstrap.servers

    Endereços dos brokers Kafka.

    Sim

    String

    O formato é host:port,host:port,host:port, separado por vírgulas (,).

    properties.*

    Propriedades de configuração para o cliente Kafka.

    Não

    String

    As chaves de propriedade devem ser opções válidas conforme definido na documentação oficial do Apache Kafka para Producer Configs e Consumer Configs.

    O Realtime Compute for Apache Flink (VVR) remove o prefixo properties. antes de passar os pares chave-valor restantes para o cliente Kafka subjacente. Por exemplo, defina 'properties.allow.auto.create.topics' = 'false' para desativar a criação automática de tópicos.

    key.format

    Formato de serialização e desserialização da chave da mensagem Kafka.

    Não

    String

    • Para o source, apenas o formato json é suportado.

    • Para o sink, os valores válidos são:

      • csv

      • json

    Nota

    Esta opção é suportada apenas no Realtime Compute for Apache Flink (VVR) 11.0.0 e versões posteriores.

    value.format

    Formato de serialização e desserialização do valor da mensagem Kafka.

    Não

    String

    debezium-json

    • Para o source, os valores válidos são:

      • debezium-json

      • canal-json

      • json

    • Para o sink, os valores válidos são:

      • debezium-json

      • canal-json

      • canal-protobuf

    Nota
    • Os formatos debezium-json e canal-json exigem a versão 8.0.10 ou posterior do Realtime Compute for Apache Flink (VVR).

    • O formato json exige a versão 11.0.0 ou posterior do Realtime Compute for Apache Flink (VVR).

  • Parâmetros de source

    Parâmetro

    Descrição

    Obrigatório

    Tipo

    Padrão

    Observações

    topic

    O tópico ou tópicos de onde ler.

    Não

    String

    Para assinar vários tópicos, separe seus nomes com ponto e vírgula (;), por exemplo, topic-1;topic-2.

    Nota

    Especifique este parâmetro ou topic-pattern, mas não ambos.

    topic-pattern

    Uma expressão regular que corresponde aos nomes dos tópicos a serem assinados.

    Não

    String

    Exemplos:

    • user_event_.*: Corresponde a todos os tópicos com o prefixo user_event_.

    • prod\.logs\..*: Corresponde a tópicos com o prefixo prod.logs. (o caractere . deve ser escapado).

    Nota

    Especifique este parâmetro ou topic, mas não ambos.

    properties.group.id

    ID do grupo de consumidores.

    Não

    String

    Ao especificar um novo ID de grupo de consumidores, você deve definir o parâmetro properties.auto.offset.reset como earliest ou latest para determinar o offset inicial de leitura.

    scan.startup.mode

    Offset inicial do consumidor Kafka.

    Não

    String

    group-offsets

    Valores válidos:

    • earliest-offset: Inicia a leitura a partir do offset mais antigo disponível.

    • latest-offset: Inicia a leitura a partir do offset mais recente.

    • group-offsets (Valor padrão): Inicia a leitura a partir dos offsets confirmados para o properties.group.id especificado.

    • timestamp: Inicia a leitura a partir do timestamp especificado por scan.startup.timestamp-millis.

    • specific-offsets: Inicia a leitura a partir dos offsets especificados por scan.startup.specific-offsets.

    Nota

    Este parâmetro se aplica apenas quando um job inicia sem estado (stateless). Quando um job com estado inicia, ele sempre consome a partir dos offsets armazenados em seu estado.

    scan.startup.specific-offsets

    Offset inicial por partição quando scan.startup.mode está definido como specific-offsets.

    Não

    String

    Por exemplo, partition:0,offset:42;partition:1,offset:300

    scan.startup.timestamp-millis

    O timestamp inicial em milissegundos quando scan.startup.mode está definido como timestamp.

    Não

    Long

    A unidade é milissegundos.

    scan.topic-partition-discovery.interval

    Intervalo para descoberta dinâmica de novas partições dentro dos tópicos.

    Não

    Duration

    5 minutos

    O conector descobre periodicamente e lê novas partições. Ao usar topic-pattern, o conector também descobre novos tópicos que correspondem ao padrão. Para desativar a descoberta, defina este valor como 0 ou menos.

    scan.check.duplicated.group.id

    Verifica se o grupo de consumidores especificado por properties.group.id é duplicado.

    Não

    Boolean

    false

    Valores válidos:

    • true: Verifica a existência de um grupo de consumidores duplicado antes do início do job. Se uma duplicidade for encontrada, o job falhará.

    • false: Inicia o job sem verificar conflitos.

    schema.inference.strategy

    Estratégia de análise de schema.

    Não

    String

    continuous

    Valores válidos:

    • continuous: Analisa o schema de cada registro de dados. Se os schemas forem incompatíveis, o sistema infere um schema mais amplo e gera um evento de alteração de schema.

    • static: Executa a análise do schema apenas uma vez no início do job. Os dados são então analisados com base neste schema inicial, e nenhum evento de alteração de schema é gerado.

    Nota

    scan.max.pre.fetch.records

    Número máximo de mensagens consumidas por partição para inferência inicial de schema.

    Não

    Int

    50

    Antes que o processamento de dados comece, o sistema pré-busca e consome o número especificado de mensagens recentes de cada partição para inicializar o schema.

    key.fields-prefix

    Prefixo para nomes de campos de chave de mensagem para evitar conflitos de nomes.

    Não

    String

    Por exemplo, se este parâmetro estiver definido como key_ e a chave da mensagem contiver um campo chamado a, o nome do campo analisado se tornará key_a.

    Nota

    O valor de key.fields-prefix não pode ser um prefixo do valor de value.fields-prefix.

    value.fields-prefix

    Prefixo para nomes de campos de valor de mensagem para evitar conflitos de nomes.

    Não

    String

    Por exemplo, se este parâmetro estiver definido como value_ e o valor da mensagem contiver um campo chamado b, o nome do campo analisado se tornará value_b.

    Nota

    O valor de value.fields-prefix não pode ser um prefixo do valor de key.fields-prefix.

    metadata.list

    Colunas de metadados passadas para o sink downstream.

    Não

    String

    As colunas de metadados disponíveis incluem topic, partition, offset, timestamp, timestamp-type, headers e leader-epoch. Separe os nomes das colunas com vírgulas.

    scan.value.initial-schemas.ddls

    Instruções DDL que definem o schema inicial para tabelas específicas.

    Não

    String

    Use ponto e vírgula (;) para separar várias instruções DDL. Por exemplo, use CREATE TABLE db1.t1 (id BIGINT, name VARCHAR(10)); CREATE TABLE db1.t2 (id BIGINT); para especificar o schema inicial para as tabelas db1.t1 e db1.t2, respectivamente.

    O schema da tabela definido no DDL deve ser consistente com a tabela sink de destino e estar em conformidade com a sintaxe do Flink SQL.

    Nota

    Esta opção de configuração é suportada apenas no Ververica Runtime (VVR) 11.5 e versões posteriores.

    ingestion.ignore-errors

    Ignora erros de análise de dados.

    Não

    Boolean

    false

    Nota

    Esta opção de configuração é suportada apenas no Ververica Runtime (VVR) 11.5 e versões posteriores.

    ingestion.error-tolerance.max-count

    Número máximo de erros de análise tolerados antes que o job falhe. Tem efeito apenas quando ingestion.ignore-errors é true.

    Não

    Integer

    -1

    Este parâmetro se aplica apenas quando ingestion.ignore-errors está definido como true. Um valor de -1 indica tolerância ilimitada, o que significa que exceções de análise não causarão falha no job.

    Nota

    Esta opção de configuração é suportada apenas no Ververica Runtime (VVR) 11.5 e versões posteriores.

    scan.duplicate-field.strategy

    Define como lidar com nomes de campos duplicados analisados nas partes de chave e valor.

    Não

    String

    EXCEPTION

    Valores válidos:

    • EXCEPTION: Lança uma exceção quando existem campos duplicados na chave e no valor. Este é o comportamento padrão no VVR 11.6 e anteriores.

    • PREFER_KEY: Usa o valor do campo de chave quando os campos estão duplicados.

    • PREFER_VALUE: Usa o valor do campo de valor quando os campos estão duplicados.

    Nota

    Esta opção de configuração é suportada apenas no Ververica Runtime (VVR) 11.7 e versões posteriores.

    • Parâmetros do formato Debezium JSON

      Parâmetro

      Obrigatório

      Tipo

      Padrão

      Descrição

      debezium-json.distributed-tables

      Não

      Boolean

      false

      Defina como true se os dados de uma única tabela Debezium JSON estiverem distribuídos em várias partições.

      Nota

      Esta opção de configuração é suportada apenas no Ververica Runtime (VVR) 8.0.11 e versões posteriores.

      Importante

      Modificar este parâmetro requer uma inicialização sem estado (stateless startup).

      debezium-json.schema-include

      Não

      Boolean

      false

      Inclui um schema na mensagem Debezium JSON. Isso corresponde à propriedade value.converter.schemas.enable na configuração do Debezium Kafka Connect.

      Valores válidos:

      • true: A mensagem Debezium JSON contém um schema.

      • false: A mensagem Debezium JSON não contém um schema.

      debezium-json.ignore-parse-errors

      Não

      Boolean

      false

      Valores válidos:

      • true: Ignora linhas que causam uma exceção de análise.

      • false: Lança um erro e o job falha.

      debezium-json.infer-schema.primitive-as-string

      Não

      Boolean

      false

      Analisa todos os tipos primitivos como String ao analisar o schema da tabela.

      Valores válidos:

      • true: Analisa todos os tipos primitivos como String.

      • false: Analisa os tipos com base nas regras padrão.

    • Parâmetros do formato Canal JSON

      Parâmetro

      Obrigatório

      Tipo

      Padrão

      Descrição

      canal-json.distributed-tables

      Não

      Boolean

      false

      Se os dados de uma única tabela em Canal JSON estiverem distribuídos em várias partições, você deve ativar esta opção.

      Nota

      Esta opção de configuração é suportada apenas no Ververica Runtime (VVR) 8.0.11 e versões posteriores.

      Importante

      Modificar este parâmetro requer uma inicialização sem estado (stateless startup).

      canal-json.database.include

      Não

      String

      Uma expressão regular opcional para filtrar changelogs pelo campo de metadados database nos registros Canal. Apenas registros de bancos de dados correspondentes são processados. A expressão regular é compatível com a classe Pattern do Java.

      canal-json.table.include

      Não

      String

      Uma expressão regular opcional para filtrar changelogs pelo campo de metadados table nos registros Canal. Apenas registros de tabelas correspondentes são processados. A expressão regular é compatível com a classe Pattern do Java.

      canal-json.ignore-parse-errors

      Não

      Boolean

      false

      Valores válidos:

      • true: Ignora a linha atual se ocorrer uma exceção de análise.

      • false: Lança um erro e o job falha ao iniciar.

      canal-json.infer-schema.primitive-as-string

      Não

      Boolean

      false

      Analisa todos os tipos primitivos como String ao analisar o schema da tabela.

      Valores válidos:

      • true: Analisa todos os tipos primitivos como String.

      • false: Analisa os tipos com base nas regras padrão.

      canal-json.infer-schema.strategy

      Não

      String

      AUTO

      Estratégia de análise de schema da tabela.

      Valores válidos:

      • AUTO: Analisa automaticamente o schema a partir dos dados JSON. Recomendado se os dados não contiverem um campo sqlType, para evitar falhas na análise.

      • SQL_TYPE: Analisa o schema a partir do array sqlType nos dados Canal JSON. Recomendamos definir isso como SQL_TYPE para obter tipos mais precisos se os dados contiverem um campo sqlType.

      • MYSQL_TYPE: Analisa o schema a partir do array mysqlType nos dados Canal JSON.

      Para obter mais informações sobre as regras de mapeamento de tipo sqlType, consulte Análise de Schema do Canal JSON.

      Nota
      • Esta configuração é suportada apenas no Ververica Runtime (VVR) 11.1 e versões posteriores.

      • O valor MYSQL_TYPE é suportado no Ververica Runtime (VVR) 11.3 e versões posteriores.

      canal-json.mysql.treat-mysql-timestamp-as-datetime-enabled

      Não

      Boolean

      true

      Mapeia o tipo MySQL TIMESTAMP para o tipo CDC TIMESTAMP.

      • true: O tipo MySQL TIMESTAMP é mapeado para o tipo CDC TIMESTAMP.

      • false: O tipo MySQL TIMESTAMP é mapeado para o tipo CDC TIMESTAMP_LTZ.

      canal-json.mysql.treat-tinyint1-as-boolean.enabled

      Não

      Boolean

      true

      Ao usar a estratégia de análise MYSQL_TYPE, controla se deve mapear o tipo MySQL TINYINT(1) para o tipo CDC BOOLEAN.

      • true: O tipo MySQL TINYINT(1) é mapeado para o tipo CDC BOOLEAN.

      • false: O tipo MySQL TINYINT(1) é mapeado para o tipo CDC TINYINT(1).

      Esta opção se aplica apenas quando canal-json.infer-schema.strategy está definido como MYSQL_TYPE.

    • Parâmetros do formato JSON

      Parâmetro

      Obrigatório

      Tipo

      Padrão

      Descrição

      json.timestamp-format.standard

      Não

      String

      SQL

      O formato de timestamp para dados de entrada e saída.

      • SQL: Analisa timestamps de entrada no formato yyyy-MM-dd HH:mm:ss.s{precision}, como 2020-12-30 12:13:14.123.

      • ISO-8601: Analisa timestamps de entrada no formato yyyy-MM-ddTHH:mm:ss.s{precision}, como 2020-12-30T12:13:14.123.

      json.ignore-parse-errors

      Não

      Boolean

      false

      Valores válidos:

      • true: Ignora a linha atual se ocorrer uma exceção de análise.

      • false: Lança um erro e o job falha ao iniciar.

      json.infer-schema.primitive-as-string

      Não

      Boolean

      false

      Analisa todos os tipos primitivos como String ao analisar o schema da tabela.

      Valores válidos:

      • true: Analisa todos os tipos primitivos como String.

      • false: Analisa os tipos com base nas regras padrão.

      json.infer-schema.flatten-nested-columns.enable

      Não

      Boolean

      false

      Expande recursivamente colunas aninhadas em dados JSON. Valores válidos:

      • true: Expande recursivamente colunas aninhadas.

      • false: Trata colunas aninhadas como String.

      json.decode.parser-table-id.fields

      Não

      String

      Usa os valores de campos JSON especificados para gerar um tableId ao analisar dados no formato JSON. Os valores de vários campos são concatenados por uma vírgula ,. Por exemplo, se os dados JSON forem {"col0":"a", "col1","b", "col2","c"}, o resultado gerado será o seguinte:

      Configuração

      tableId

      col0

      a

      col0,col1

      a.b

      col0,col1,col2

      a.b.c

      json.infer-schema.fixed-types

      Não

      String

      Ao analisar dados JSON, você pode especificar os tipos de dados para campos específicos. Use uma vírgula , para separar vários campos. Por exemplo, id BIGINT, name VARCHAR(10) especifica que o campo id é do tipo BIGINT e o campo name é do tipo VARCHAR(10).

      Nota
      • Esta opção de configuração é suportada apenas no Ververica Runtime (VVR) 11.5 e versões posteriores.

      • Ao usar esta configuração com o Ververica Runtime (VVR) versão 11.5, você também deve adicionar a configuração scan.max.pre.fetch.records: 0.

      json.decode.empty-value-as-delete.enabled

      Não

      Boolean

      false

      Especifica se deve analisar mensagens tombstone (com valor vazio) em um tópico compactado do Kafka como eventos DELETE. Usado para cenários onde um valor vazio representa semântica de exclusão, como espelhamento de tópicos compactados ou sinais de exclusão CDC.

      Nota

      Esta opção de configuração é suportada apenas no Ververica Runtime (VVR) 11.7 e versões posteriores.

  • Parâmetros da tabela sink

    Parâmetro

    Descrição

    Obrigatório

    Tipo

    Padrão

    Observações

    type

    Tipo de sink.

    Sim

    String

    O valor deve ser kafka.

    name

    Nome do sink.

    Não

    String

    topic

    Nome do tópico Kafka.

    Não

    String

    Se este parâmetro for especificado, todos os dados serão gravados neste tópico.

    Nota

    Se este parâmetro não for especificado, cada registro será gravado em um tópico nomeado de acordo com seu TableID. O TableID é construído unindo os nomes do banco de dados e da tabela com um ponto (.), por exemplo, databaseName.tableName.

    partition.strategy

    Estratégia de gravação de partição Kafka.

    Não

    String

    all-to-zero

    Valores válidos:

    • all-to-zero (padrão): Grava todos os dados na Partição 0.

    • hash-by-key: Grava dados em partições com base no valor hash da chave primária. Isso garante que registros com a mesma chave primária sejam gravados na mesma partição, preservando sua ordem.

    sink.tableId-to-topic.mapping

    Mapeamento de nomes de tabelas upstream para nomes de tópicos Kafka downstream.

    Não

    String

    Separe os mapeamentos com ponto e vírgula (;). Dentro de cada mapeamento, separe o nome da tabela upstream e o nome do tópico Kafka downstream com dois pontos (:). Você pode usar uma expressão regular para o nome da tabela. Para mapear várias tabelas para o mesmo tópico, separe os nomes das tabelas com vírgulas (,). Por exemplo: mydb.mytable1:topic1;mydb.mytable2:topic2.

    Nota

    Este parâmetro permite modificar o tópico mapeado enquanto preserva as informações originais do nome da tabela.

    • Parâmetros do formato Debezium JSON

      Parâmetro

      Obrigatório

      Tipo

      Padrão

      Descrição

      debezium-json.include-schema.enabled

      Não

      Boolean

      false

      Inclui informações de schema nos dados Debezium JSON.

      debezium-json.emit.full-table-id.enabled

      Não

      Boolean

      false

      Grava o ID completo da tabela em três partes nos campos de metadados Debezium JSON.

      Se este parâmetro estiver ativado, o mapeamento será o seguinte:

      Parte do ID da Tabela CDC

      Chave Debezium JSON

      Namespace

      db

      Schema

      schema

      Table

      table

      Se este parâmetro estiver desativado, o mapeamento será o seguinte:

      Parte do ID da Tabela CDC

      Chave Debezium JSON

      Namespace

      Não mapeado

      Schema

      db

      Table

      table

      Nota

      Este parâmetro é suportado apenas no Ververica Runtime (VVR) 11.6 e versões posteriores.

Exemplos

  • Use o Kafka como source Flink CDC:

    source:
      type: kafka
      name: Kafka source
      properties.bootstrap.servers: ${kafka.bootstraps.server}
      topic: ${kafka.topic}
      value.format: ${value.format}
      scan.startup.mode: ${scan.startup.mode}
     
    sink:
      type: hologres
      name: Hologres sink
      endpoint: <yourEndpoint>
      dbname: <yourDbname>
      username: ${secret_values.ak_id}
      password: ${secret_values.ak_secret}
      sink.type-normalize-strategy: BROADEN
  • Use o Kafka como sink Flink CDC:

    source:
      type: mysql
      name: MySQL Source
      hostname: ${secret_values.mysql.hostname}
      port: ${mysql.port}
      username: ${secret_values.mysql.username}
      password: ${secret_values.mysql.password}
      tables: ${mysql.source.table}
      server-id: 8601-8604
    
    sink:
      type: kafka
      name: Kafka Sink
      properties.bootstrap.servers: ${kafka.bootstraps.server}
    
    route:
      - source-table: ${mysql.source.table}
        sink-table: ${kafka.topic}

    O módulo route especifica o Tópico Kafka de destino para a Tabela Source.

Nota

Por padrão, o recurso de criação automática de tópicos está desativado para o ApsaraMQ for Kafka. Para obter mais informações, consulte FAQ sobre criação automática de tópicos. Você deve criar o tópico antes de gravar dados no ApsaraMQ for Kafka. Para obter mais informações, consulte Etapa 3: Criar recursos.

Políticas para análise e evolução de schema

O conector Kafka mantém os schemas de todas as tabelas conhecidas atualmente.

Inicialização do schema da tabela

O schema de uma tabela inclui colunas e tipos de dados, nomes de banco de dados e tabelas, além de chaves primárias. As seções a seguir descrevem como inicializar cada um desses elementos.

  • Informações de coluna e tipo de dados

Um job Flink CDC pode inferir automaticamente colunas e tipos de dados a partir dos dados, mas talvez você queira defini-los explicitamente para determinadas tabelas. Existem três estratégias de inicialização de schema, dependendo do nível de controle necessário sobre os tipos:

  1. Inferência de schema totalmente automática

Antes de ler dados do Kafka, o conector tenta consumir até scan.max.pre.fetch.records mensagens de cada partição, analisa o schema de cada mensagem e mescla esses schemas para inicializar o schema da tabela. Em seguida, um evento de criação de tabela é gerado com base nesse schema inicializado antes que os dados sejam realmente consumidos.

Nota

Para os formatos Debezium JSON e Canal JSON, as informações da tabela estão contidas em cada mensagem. As mensagens pré-buscadas com base no parâmetro scan.max.pre.fetch.records podem conter dados de várias tabelas. Portanto, não é possível determinar o número de registros pré-buscados para uma única tabela específica. A pré-busca e a inicialização do schema ocorrem apenas uma vez para cada partição antes que suas mensagens sejam consumidas e processadas. Se dados de uma nova tabela aparecerem posteriormente, o schema analisado a partir do primeiro registro dessa tabela será usado como seu schema inicial, sem nova pré-busca ou reinicialização.

Importante

A distribuição de dados de uma única tabela em várias partições tem suporte apenas no Ververica Runtime (VVR) 8.0.11 e versões posteriores. Além disso, exige que você defina a opção de configuração debezium-json.distributed-tables ou canal-json.distributed-tables como true.

  1. Especificação de um schema inicial de tabela

Em alguns casos, pode ser necessário definir explicitamente o schema inicial da tabela, por exemplo, ao gravar dados do Kafka em uma tabela downstream pré-existente. Nesse cenário, adicione o parâmetro scan.value.initial-schemas.ddls. Veja abaixo um exemplo de configuração:

source:
  type: kafka
  name: Kafka Source
  properties.bootstrap.servers: host:9092
  topic: test-topic
  value.format: json
  scan.startup.mode: earliest-offset
  # Set the initial table schema
  scan.value.initial-schemas.ddls: CREATE TABLE db1.t1 (id BIGINT, name VARCHAR(10)); CREATE TABLE db1.t2 (id BIGINT);

A instrução DDL deve corresponder ao schema da tabela de destino. Esta configuração define o tipo inicial da coluna id como BIGINT e da coluna name como VARCHAR(10) para a tabela db1.t1, bem como o tipo inicial da coluna id como BIGINT para a tabela db1.t2.

As instruções DDL utilizam a sintaxe Flink SQL.

  1. Definição de tipos fixos para campos específicos

Talvez você precise bloquear certos campos em um tipo de dados fixo. Por exemplo, campos que normalmente seriam inferidos como TIMESTAMP podem precisar ser gerados como strings. Para isso, adicione o parâmetro json.infer-schema.fixed-types para especificar o schema inicial da tabela. Esse parâmetro é válido apenas quando o formato da mensagem é JSON. Confira um exemplo de configuração:

source:
  type: kafka
  name: Kafka Source
  properties.bootstrap.servers: host:9092
  topic: test-topic
  value.format: json
  scan.startup.mode: earliest-offset
  # Set specific fields to a fixed type
  json.infer-schema.fixed-types: id BIGINT, name VARCHAR(10)
  scan.max.pre.fetch.records: 0

Essa configuração determina que todos os campos id são do tipo BIGINT e todos os campos name são do tipo VARCHAR(10).

Os tipos de dados seguem os padrões do Flink SQL.

  • Informações de banco de dados e tabela

    • Nos formatos Canal JSON e Debezium JSON, o conector extrai as informações da tabela, incluindo nome do banco de dados e da tabela, diretamente de cada mensagem.

    • No formato JSON, por padrão, as informações da tabela contêm apenas o nome da tabela, que corresponde ao nome do tópico onde os dados residem. Caso seus dados incluam informações de banco de dados e tabela, utilize o parâmetro json.infer-schema.fixed-types para indicar os campos que armazenam essas informações. O sistema mapeará esses campos para os nomes do banco de dados e da tabela. Veja um exemplo de configuração:

      source:
        type: kafka
        name: Kafka Source
        properties.bootstrap.servers: host:9092
        topic: test-topic
        value.format: json
        scan.startup.mode: earliest-offset
        # Use the value of the col1 field as the database name and the value of the col2 field as the table name
        json.decode.parser-table-id.fields: col1,col2

      Com essa configuração, o conector envia cada registro para uma tabela cujo nome do banco de dados corresponde ao valor do campo col1 e o nome da tabela corresponde ao valor do campo col2.

  • Informações de chave primária

    • No formato Canal JSON, o campo pkNames nos dados JSON define a chave primária da tabela.

    • Nos formatos Debezium JSON e JSON, os dados não contêm informações de chave primária. Adicione chaves primárias manualmente às tabelas usando regras de transform:

      transform:
        - source-table: \.*.\.*
          projection: \*
          primary-keys: key1, key2

Análise e evolução de schema

Após a inicialização do schema da tabela, se schema.inference.strategy estiver definido como static, o conector Kafka analisa o valor de cada mensagem com base no schema inicial da tabela e não gera eventos de alteração de schema. Quando schema.inference.strategy está configurado como continuous, o conector examina o valor de cada mensagem Kafka, identifica suas colunas físicas e compara o schema resultante com o schema mantido atualmente. Se houver inconsistência entre os schemas, o conector tenta mesclá-los e gera um evento correspondente de alteração de schema da tabela. As regras de mesclagem funcionam da seguinte forma:

  • Caso as colunas físicas analisadas contenham campos ausentes no schema atual, o sistema adiciona esses campos ao schema e gera um evento para incluí-los como colunas anuláveis.

  • Se as colunas físicas analisadas não incluírem campos presentes no schema atual, tais campos permanecem e seus valores são preenchidos com NULL. Nenhum evento de exclusão de coluna é gerado.

  • Colunas com o mesmo nome recebem o seguinte tratamento:

    • Quando as colunas possuem o mesmo tipo de dados, mas precisões diferentes, o tipo com maior precisão prevalece e um evento de alteração de tipo de coluna é emitido.

    • Se as colunas apresentarem tipos de dados distintos, o sistema localiza o menor tipo pai comum na árvore hierárquica de tipos abaixo. Esse tipo pai comum passa a ser usado para a coluna, gerando-se um evento de alteração de tipo.

      image

  • Políticas de evolução de schema suportadas:

    • Adição de coluna: O conector insere a nova coluna ao final do schema e sincroniza seus dados, definindo-a como anulável.

    • Remoção de coluna: Não há geração de evento de exclusão. Em vez disso, os dados subsequentes para essa coluna são preenchidos com NULL.

    • Renomeação de coluna: O conector interpreta essa ação como a remoção da coluna antiga e a adição de uma nova. A nova coluna vai para o final do schema, enquanto os valores da coluna original recebem NULL.

    • Alteração de tipo de coluna:

      • Para sinks downstream compatíveis com mudanças de tipo, um job Flink CDC consegue lidar com alterações (por exemplo, de INT para BIGINT) desde que o sink esteja configurado para processá-las. Essa capacidade depende das regras de alteração de tipo suportadas pelo sink específico. Consulte a documentação do seu sink para verificar as regras aplicáveis.

      • Para sinks downstream que não aceitam alterações de tipo de coluna, como o Hologres, utilize o recurso de Ampliação de tipo. Ele cria uma tabela com tipos de dados mais amplos no sink downstream durante o início do job. Assim, quando ocorre uma mudança de tipo, o sistema tolera a alteração contanto que o novo tipo caiba dentro do tipo mais amplo definido no sink.

  • Alterações de schema não suportadas:

    • Modificações em restrições, como chaves primárias ou índices.

    • Mudança de uma coluna de NOT NULL para NULLABLE.

  • Análise de schema Canal JSON

    Dados Canal JSON podem conter um campo opcional sqlType, que registra informações precisas de tipo para as colunas de dados. Para obter um schema mais preciso, defina canal-json.infer-schema.strategy como SQL_TYPE e utilize os tipos provenientes do campo sqlType. Os mapeamentos de tipo são:

    Tipo JDBC

    Código do tipo

    Tipo CDC

    BIT

    -7

    BOOLEAN

    BOOLEAN

    16

    TINYINT

    -6

    TINYINT

    SMALLINT

    5

    SMALLINT

    INTEGER

    4

    INT

    BIGINT

    -5

    BIGINT

    DECIMAL

    3

    DECIMAL(38,18)

    NUMERIC

    2

    REAL

    7

    FLOAT

    FLOAT

    6

    DOUBLE

    8

    DOUBLE

    BINARY

    -2

    BYTES

    VARBINARY

    -3

    LONGVARBINARY

    -4

    BLOB

    2004

    DATE

    91

    DATE

    TIME

    92

    TIME

    TIMESTAMP

    93

    TIMESTAMP

    CHAR

    1

    STRING

    VARCHAR

    12

    LONGVARCHAR

    -1

    Outros tipos de dados

Tolerância e coleta de dados incorretos

Sua fonte de dados Kafka pode conter registros malformados, conhecidos como dados incorretos. Para evitar que seu job falhe e reinicie repetidamente, configure-o para ignorar esses registros inválidos. Exemplo:

source:
  type: kafka
  name: Kafka Source
  properties.bootstrap.servers: host:9092
  topic: test-topic
  value.format: json
  scan.startup.mode: earliest-offset
  # Enable Dirty Data Tolerance
  ingestion.ignore-errors: true
  # Tolerate up to 1000 dirty data records
  ingestion.error-tolerance.max-count: 1000

Com essa configuração, o job continua em execução desde que não encontre mais de 1.000 registros incorretos. Assim que a contagem ultrapassa esse limiar, o job falha para permitir a investigação dos dados.

Para garantir que o job nunca falhe devido a dados incorretos, use a seguinte configuração:

source:
  type: kafka
  name: Kafka Source
  properties.bootstrap.servers: host:9092
  topic: test-topic
  value.format: json
  scan.startup.mode: earliest-offset
  # Enable Dirty Data Tolerance
  ingestion.ignore-errors: true
  # Tolerate all dirty data records
  ingestion.error-tolerance.max-count: -1

Embora a tolerância a dados incorretos mantenha o job ativo, convém inspecionar os registros problemáticos. Analisar esses dados também ajuda a melhorar seus produtores Kafka. Conforme descrito em Coleta de Dados Incorretos, visualize os dados incorretos do job nos logs do TaskManager. Exemplo:

source:
  type: kafka
  name: Kafka Source
  properties.bootstrap.servers: host:9092
  topic: test-topic
  value.format: json
  scan.startup.mode: earliest-offset
  # Enable Dirty Data Tolerance
  ingestion.ignore-errors: true
  # Tolerate all dirty data records
  ingestion.error-tolerance.max-count: -1

pipeline:
  dirty-data.collector:
    # Write dirty data to the TaskManager log file
    type: logger

Mapeamento de nome de tabela e tópico

Quando o Kafka atua como sink Flink CDC, o formato da mensagem (como Debezium JSON ou Canal JSON) incorpora o nome original da tabela. Consumidores downstream geralmente usam esse nome incorporado como identificador da tabela em vez do nome do tópico, portanto, configurar corretamente o mapeamento entre nomes de tabelas e tópicos é essencial.

Suponha que você precise sincronizar duas tabelas de um banco de dados MySQL: mydb.mytable1 e mydb.mytable2. As seguintes estratégias de mapeamento estão disponíveis:

1. Sem estratégia de mapeamento

Sem nenhuma estratégia de mapeamento, os dados de cada tabela são gravados em um tópico nomeado no formato <Nome do Banco de Dados>.<Nome da Tabela>. Assim, os dados de mydb.mytable1 vão para um tópico chamado mydb.mytable1, e os dados de mydb.mytable2 vão para um tópico chamado mydb.mytable2. Veja um exemplo de configuração:

source:
  type: mysql
  name: MySQL Source
  hostname: ${secret_values.mysql.hostname}
  port: ${mysql.port}
  username: ${secret_values.mysql.username}
  password: ${secret_values.mysql.password}
  tables: mydb.mytable1,mydb.mytable2
  server-id: 8601-8604

sink:
  type: kafka
  name: Kafka Sink
  properties.bootstrap.servers: ${kafka.bootstraps.server}

2. Mapeamento por regra de rota (Não recomendado)

Caso prefira gravar dados em um tópico específico em vez de usar o formato padrão <Nome do Banco de Dados>.<Nome da Tabela>, configure uma regra de rota. Confira este exemplo de configuração:

source:
  type: mysql
  name: MySQL Source
  hostname: ${secret_values.mysql.hostname}
  port: ${mysql.port}
  username: ${secret_values.mysql.username}
  password: ${secret_values.mysql.password}
  tables: mydb.mytable1,mydb.mytable2
  server-id: 8601-8604

sink:
  type: kafka
  name: Kafka Sink
  properties.bootstrap.servers: ${kafka.bootstraps.server}
  
 route:
  - source-table: mydb.mytable1,mydb.mytable2
    sink-table: mytable

Neste caso, todos os dados de mydb.mytable1 e mydb.mytable2 são gravados em um único tópico chamado mytable.

No entanto, uma regra de rota que altera o tópico de destino também modifica o nome da tabela na mensagem Kafka (no formato Debezium JSON ou Canal JSON). O nome da tabela em todas as mensagens Kafka torna-se mytable. Isso pode causar comportamento inesperado em sistemas que consomem mensagens desse tópico.

3. Mapeamento com sink.tableId-to-topic.mapping (Recomendado)

Para mapear nomes de tabelas para tópicos preservando o nome original da tabela de origem, utilize o parâmetro sink.tableId-to-topic.mapping. Veja um exemplo de configuração:

source:
  type: mysql
  name: MySQL Source
  hostname: ${secret_values.mysql.hostname}
  port: ${mysql.port}
  username: ${secret_values.mysql.username}
  password: ${secret_values.mysql.password}
  tables: mydb.mytable1,mydb.mytable2
  server-id: 8601-8604
  sink.tableId-to-topic.mapping: mydb.mytable1,mydb.mytable2:mytable

sink:
  type: kafka
  name: Kafka Sink
  properties.bootstrap.servers: ${kafka.bootstraps.server}

Alternativamente, utilize a seguinte configuração:

source:
  type: mysql
  name: MySQL Source
  hostname: ${secret_values.mysql.hostname}
  port: ${mysql.port}
  username: ${secret_values.mysql.username}
  password: ${secret_values.mysql.password}
  tables: mydb.mytable1,mydb.mytable2
  server-id: 8601-8604
  sink.tableId-to-topic.mapping: mydb.mytable1:mytable;mydb.mytable2:mytable

sink:
  type: kafka
  name: Kafka Sink
  properties.bootstrap.servers: ${kafka.bootstraps.server}

Dessa forma, todos os dados de mydb.mytable1 e mydb.mytable2 são gravados no tópico mytable, e o nome da tabela dentro das mensagens Kafka (no formato Debezium JSON ou Canal JSON) permanece como mydb.mytable1 ou mydb.mytable2. Assim, os sistemas downstream ainda conseguem identificar a tabela de origem original de cada registro.

Semântica exactly-once

  • Configuração do nível de isolamento do consumidor

    Todas as aplicações que consomem dados Kafka devem definir a propriedade isolation.level:

    • read_committed: Lê apenas dados confirmados.

    • read_uncommitted (Padrão): Pode ler dados não confirmados.

    EXACTLY_ONCE depende de read_committed. Caso contrário, os consumidores podem visualizar dados não confirmados, quebrando a consistência.

  • Timeout de transação e perda de dados

    Ao recuperar de um checkpoint, o Realtime Compute for Apache Flink considera apenas transações confirmadas antes do início desse checkpoint. Se o tempo entre a falha de um job e sua reinicialização exceder o timeout de transação do Kafka, o Kafka aborta automaticamente a transação aberta, o que pode resultar em perda de dados.

    • O valor padrão de transaction.max.timeout.ms para um broker Kafka é de 15 minutos.

    • Por padrão, o Flink Kafka Sink define o parâmetro transaction.timeout.ms como 1 hora.

    • Aumente transaction.max.timeout.ms no broker para que seja maior ou igual à configuração no Flink.

  • Pool de produtores e checkpoints concorrentes

    O modo EXACTLY_ONCE utiliza um pool de produtores Kafka de tamanho fixo. Cada checkpoint usa um produtor desse pool. Se o número de checkpoints concorrentes exceder o tamanho do pool, o job falhará.

    Configure o tamanho do pool de produtores com base no número máximo de checkpoints concorrentes.

  • Restrições de redução de paralelismo

    Se um job falhar antes da conclusão do primeiro checkpoint, as informações originais do pool de produtores serão perdidas na reinicialização. Portanto, não reduza o paralelismo do job antes que o primeiro checkpoint seja concluído. Caso a redução seja necessária, o novo paralelismo não deve ser inferior a FlinkKafkaProducer.SAFE_SCALE_DOWN_FACTOR.

  • Transações bloqueiam leituras

    No modo read_committed, qualquer transação que não tenha sido confirmada ou abortada bloqueia operações de leitura em todo o tópico.

    Por exemplo:

    • A Transação 1 grava dados.

    • A Transação 2 grava mais dados e é confirmada.

    • Enquanto a Transação 1 permanecer aberta, os dados da Transação 2 confirmada ficam invisíveis para os consumidores.

    Isso gera as seguintes implicações:

    • Durante a operação normal, a latência de visibilidade dos dados é aproximadamente igual ao intervalo de checkpoint.

    • Se um job falhar, qualquer tópico em que ele estava gravando ficará bloqueado para consumidores até que o job reinicie ou a transação expire. Em casos extremos, o próprio processo de timeout da transação também pode afetar as operações de leitura.

Perguntas frequentes