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 |
|
|
Métricas |
|
|
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.
ImportanteLimitaçõ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.idempotencetem como padrãotrue. 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:
O cliente usa os endereços especificados em
bootstrap.serverspara estabelecer uma conexão inicial com o cluster Kafka.O cluster Kafka retorna metadados de cada broker, incluindo seus endpoints.
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
-
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. -
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.
-
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
-
Use o recurso Network Probe
Esse recurso ajuda a descartar problemas de conectividade com o endereço
bootstrap.serverse a verificar se o endpoint interno ou público correto está sendo utilizado. -
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.
-
Verifique a configuração
Use a ferramenta zkCli.sh ou zookeeper-shell.sh para fazer login no cluster ZooKeeper utilizado pelo Kafka.
-
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.
-
Utilize o recurso Network Probe no console de desenvolvimento do Realtime Compute for Apache Flink para testar se esse endereço está acessível.
NotaSe o endereço não estiver acessível, entre em contato com os administradores do Kafka para verificar e corrigir as configurações
listenerseadvertised.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.
-
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:
|
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
NotaPara 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
NotaAo 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.
NotaSe você usar esta opção,
value.fields-includedeve ser definido comoEXCEPT_KEY.value.format
Formato para serializar e desserializar o valor de uma mensagem Kafka.
String
Não
–
Esta configuração equivale a
format. Defina apenasformatouvalue.format. Se ambos forem configurados,value.formatsubstituiformat.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 emkey.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'.NotaEspecifique 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 prefixouser_event_. -
prod\.logs\..*: Corresponde a tópicos com o prefixoprod.logs.(o caractere.deve ter escape).
NotaEspecifique 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
earliestoulatestpara 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.
NotaEsta 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:300scan.startup.timestamp-millis
Timestamp inicial em milissegundos quando
scan.startup.modeestá definido comotimestamp.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.
NotaNo 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:testretém dados Kafka se o cabeçalho contiverdepart=toyoudepart=booke não contiverenv=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.
NotaEsta 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.
NotaAo 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-guaranteeforexactly-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.locationeproperties.ssl.keystore.locationcom 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.
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.
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;
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
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-groupe 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). OKafkaRecordDeserializationSchemadefine como analisar umConsumerRecorddo 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. ODeserializationSchemadefine 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));
NotaPara analisar um
ConsumerRecordcompleto, implemente a interfaceKafkaRecordDeserializationSchema.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())NotaSe 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.NotaUma 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:setUnboundedpara modo de streaming esetBoundedpara 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.ImportanteO 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.
NotaSe 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.commiteauto.commit.interval.ms.NotaA 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)esetProperty(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
-1desativa a descoberta dinâmica de partições.NotaNo 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.
ImportantePara 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 peloOffsetsInitializer.
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 subgrupoKafkaSourceReader.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.metricspara 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
KafkaRecordSerializationSchemapara converter dados de entrada em umProducerRecorddo 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
ProducerRecordoferece 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.
NotaAo 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
-
NotaEsta 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-jsonecanal-jsonexigem a versão 8.0.10 ou posterior do Realtime Compute for Apache Flink (VVR). -
O formato
jsonexige 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.NotaEspecifique 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 prefixouser_event_. -
prod\.logs\..*: Corresponde a tópicos com o prefixoprod.logs.(o caractere.deve ser escapado).
NotaEspecifique 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
earliestoulatestpara 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.
NotaEste 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.modeestá definido comospecific-offsets.Não
String
–
Por exemplo,
partition:0,offset:42;partition:1,offset:300scan.startup.timestamp-millis
O timestamp inicial em milissegundos quando
scan.startup.modeestá definido comotimestamp.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-
Para obter mais informações sobre a análise de schema, consulte Políticas para análise e evolução de schema.
-
Esta opção de configuração é suportada apenas no Ververica Runtime (VVR) 8.0.11 e versões posteriores.
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 chamadoa, o nome do campo analisado se tornarákey_a.NotaO valor de
key.fields-prefixnão pode ser um prefixo do valor devalue.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 chamadob, o nome do campo analisado se tornarávalue_b.NotaO valor de
value.fields-prefixnão pode ser um prefixo do valor dekey.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,headerseleader-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, useCREATE 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.
NotaEsta 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
NotaEsta 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-errorsestá definido comotrue. Um valor de -1 indica tolerância ilimitada, o que significa que exceções de análise não causarão falha no job.NotaEsta 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.
NotaEsta 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
truese os dados de uma única tabela Debezium JSON estiverem distribuídos em várias partições.NotaEsta opção de configuração é suportada apenas no Ververica Runtime (VVR) 8.0.11 e versões posteriores.
ImportanteModificar 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.enablena 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
Stringao 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.
NotaEsta opção de configuração é suportada apenas no Ververica Runtime (VVR) 8.0.11 e versões posteriores.
ImportanteModificar 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
databasenos 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
tablenos 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
Stringao 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
sqlTypenos dados Canal JSON. Recomendamos definir isso como SQL_TYPE para obter tipos mais precisos se os dados contiverem um camposqlType. -
MYSQL_TYPE: Analisa o schema a partir do array
mysqlTypenos 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
TIMESTAMPpara o tipo CDCTIMESTAMP.-
true: O tipo MySQL
TIMESTAMPé mapeado para o tipo CDCTIMESTAMP. -
false: O tipo MySQL
TIMESTAMPé mapeado para o tipo CDCTIMESTAMP_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 MySQLTINYINT(1)para o tipo CDCBOOLEAN.-
true: O tipo MySQL
TINYINT(1)é mapeado para o tipo CDCBOOLEAN. -
false: O tipo MySQL
TINYINT(1)é mapeado para o tipo CDCTINYINT(1).
Esta opção se aplica apenas quando
canal-json.infer-schema.strategyestá definido comoMYSQL_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}, como2020-12-30 12:13:14.123. -
ISO-8601: Analisa timestamps de entrada no formato
yyyy-MM-ddTHH:mm:ss.s{precision}, como2020-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
Stringao 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 campoidé do tipo BIGINT e o camponameé 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.
NotaEsta 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.
NotaSe 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.NotaEste 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
dbSchema
schemaTable
tableSe este parâmetro estiver desativado, o mapeamento será o seguinte:
Parte do ID da Tabela CDC
Chave Debezium JSON
Namespace
Não mapeado
Schema
dbTable
tableNotaEste 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
routeespecifica o Tópico Kafka de destino para a Tabela Source.
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:
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.
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.
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.
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.
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,col2Com essa configuração, o conector envia cada registro para uma tabela cujo nome do banco de dados corresponde ao valor do campo
col1e o nome da tabela corresponde ao valor do campocol2.
-
Informações de chave primária
No formato Canal JSON, o campo
pkNamesnos 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.

-
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
INTparaBIGINT) 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 NULLparaNULLABLE.
-
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 comoSQL_TYPEe utilize os tipos provenientes do camposqlType. 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.mspara um broker Kafka é de 15 minutos.Por padrão, o Flink Kafka Sink define o parâmetro
transaction.timeout.mscomo 1 hora.Aumente
transaction.max.timeout.msno broker para que seja maior ou igual à configuração no Flink.
-
Pool de produtores e checkpoints concorrentes
O modo
EXACTLY_ONCEutiliza 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.