Tous les produits
Search
Centre de documentation

Realtime Compute for Apache Flink:Upsert Kafka

Dernière mise à jour :Aug 09, 2026

Le connecteur Upsert Kafka lit et écrit dans des rubriques Kafka en utilisant la sémantique upsert. En tant que source, il convertit les enregistrements Kafka en un flux de journal des modifications (changelog). En tant que puits (sink), il écrit les données du journal des modifications dans Kafka, en utilisant des messages à valeur nulle (tombstones) pour représenter les suppressions.

Catégorie Détails
Types pris en charge Table source, table puits et puits d'ingestion de données
Mode d'exécution Mode streaming
Formats de données avro, avro-confluent, csv, json et raw
Types d'API SQL et job YAML d'ingestion de données
Mise à jour ou suppression des données dans une table puits Oui

Prérequis

Avant de commencer, assurez-vous de disposer des éléments suivants :

Fonctionnement

Le flux de journal des modifications upsert produit par la source contient uniquement des entrées +I (insertion), +U (mise à jour après) et -D (suppression). Contrairement à un flux retract, il ne contient jamais de messages -U (mise à jour avant).

Type d'entrée de changelog Nom long Sémantique
+I Insertion Un nouvel enregistrement dont la clé n'existait pas auparavant
+U Mise à jour après Un enregistrement dont la clé existe déjà — écrase la valeur précédente
-D Suppression Un enregistrement avec une valeur nulle — supprime l'entrée pour cette clé

En tant que table source, le connecteur lit les enregistrements Kafka et les convertit en un flux de journal des modifications :

  • Un enregistrement dont la clé existe déjà est interprété comme une MISE À JOUR (+U)

  • Un enregistrement dont la clé n'existe pas est interprété comme une INSERTION (+I)

  • Un enregistrement avec une valeur nulle est interprété comme une SUPPRESSION (-D)

En tant que table puits ou puits d'ingestion de données, le connecteur consomme un flux de journal des modifications en amont :

  • Les enregistrements INSERT et UPDATE_AFTER sont écrits sous forme de messages Kafka normaux

  • Les enregistrements DELETE sont écrits sous forme de messages tombstone (valeur nulle pour la clé correspondante)

Flink partitionne la sortie du puits par clé primaire, de sorte que tous les messages pour la même clé arrivent dans la même partition dans le bon ordre.

Exemple

L'exemple de bout en bout suivant lit les événements de consultation de pages web depuis une table source Kafka, agrège les vues de page (PV) et les visiteurs uniques (UV) par région, et écrit les résultats dans un puits Upsert Kafka.

Table source — lit les événements bruts de consultation de pages :

CREATE TABLE pageviews (
  user_id    BIGINT,
  page_id    BIGINT,
  viewtime   TIMESTAMP,
  user_region STRING,
  WATERMARK FOR viewtime AS viewtime - INTERVAL '2' SECOND
) WITH (
  'connector'                  = 'kafka',
  'topic'                      = '<yourTopicName>',
  'properties.bootstrap.servers' = '<host:port>',
  'format'                     = 'json'
);

Table puits — stocke les résultats agrégés avec la sémantique upsert :

CREATE TABLE pageviews_per_region (
  user_region STRING,
  pv          BIGINT,
  uv          BIGINT,
  PRIMARY KEY (user_region) NOT ENFORCED
) WITH (
  'connector'                  = 'upsert-kafka',
  'topic'                      = '<yourTopicName>',
  'properties.bootstrap.servers' = '<host:port>',
  'key.format'                 = 'avro',
  'value.format'               = 'avro'
);
Chaque table Upsert Kafka doit définir une clé primaire. Les colonnes de la clé primaire déterminent comment Flink partitionne la sortie et comment le connecteur identifie les opérations upsert.

Requête — agrège et écrit les résultats :

INSERT INTO pageviews_per_region
SELECT
  user_region,
  COUNT(*),
  COUNT(DISTINCT user_id)
FROM pageviews
GROUP BY user_region;

SQL

Syntaxe

CREATE TABLE upsert_kafka_sink (
  user_region STRING,
  pv          BIGINT,
  uv          BIGINT,
  PRIMARY KEY (user_region) NOT ENFORCED
) WITH (
  'connector'                  = 'upsert-kafka',
  'topic'                      = '<yourTopicName>',
  'properties.bootstrap.servers' = '...',
  'key.format'                 = 'avro',
  'value.format'               = 'avro'
);

Paramètres WITH

Paramètres généraux

Paramètre Obligatoire Par défaut Description
connector Oui — Définissez sur upsert-kafka.
properties.bootstrap.servers Oui — Liste séparée par des virgules des adresses des courtiers Kafka au format host:port.
topic Oui — La rubrique Kafka à partir de laquelle lire ou dans laquelle écrire.
key.format Oui — Format de sérialisation pour la clé du message. Valeurs valides : csv, json, avro, debezium-json, canal-json, maxwell-json, avro-confluent, raw.
value.format Oui — Format de sérialisation pour la valeur du message. Équivalent à format — configurez-en un seul.
value.fields-include Oui ALL Contrôle les colonnes incluses dans la valeur du message. ALL inclut toutes les colonnes ; EXCEPT_KEY exclut les champs de clé définis par key.fields.
properties.* Non — Paramètres client Kafka supplémentaires. Le préfixe properties. est supprimé avant de transmettre la configuration au client. Le suffixe doit être une clé de configuration producteur ou consommateur Kafka valide. N'utilisez pas ce mécanisme pour définir key.deserializer ou value.deserializer — le connecteur gère ces paramètres en interne.
key.fields-prefix Non — Un préfixe personnalisé appliqué à tous les noms de champs de clé dans le schéma de la table, utilisé pour éviter les collisions de noms avec les champs de valeur. Le préfixe est supprimé lors de l'analyse et de la génération de la clé. Si défini, value.fields-include doit être défini sur EXCEPT_KEY.

Paramètres spécifiques au puits

Paramètre Obligatoire Par défaut Description
sink.parallelism Non Hérité de l'opérateur en amont Parallélisme de l'opérateur de puits Kafka.
sink.buffer-flush.max-rows Non 0 (désactivé) Nombre maximal d'enregistrements à mettre en mémoire tampon avant vidage. Lorsque plusieurs mises à jour arrivent pour la même clé, seul le dernier enregistrement est conservé dans la mémoire tampon, ce qui réduit le volume d'écriture et évite les messages tombstone inutiles. sink.buffer-flush.max-rows et sink.buffer-flush.interval doivent tous deux être supérieurs à zéro pour activer la mise en mémoire tampon.
sink.buffer-flush.interval Non 0 (désactivé) Fréquence de vidage de la mémoire tampon. Unités prises en charge : ms, s, min, h — par exemple, '1 s'. Le même comportement de déduplication par clé que sink.buffer-flush.max-rows s'applique. Les deux paramètres doivent être supérieurs à zéro pour activer la mise en mémoire tampon.

Ingestion de données

Le connecteur Upsert Kafka peut servir de puits dans un job YAML d'ingestion de données. Les données sont écrites au format JSON, et les champs de clé primaire sont inclus dans le corps du message.

Syntaxe

sink:
  type: upsert-kafka
  name: upsert-kafka Sink
  properties.bootstrap.servers: localhost:9092
  # ApsaraMQ for Kafka
  aliyun.kafka.accessKeyId: ${secret_values.kafka-ak}
  aliyun.kafka.accessKeySecret: ${secret_values.kafka-sk}
  aliyun.kafka.instanceId: ${instancd-id}
  aliyun.kafka.endpoint: ${endpoint}
  aliyun.kafka.regionId: ${region-id}

Paramètres

Paramètre Obligatoire Par défaut Description
type Oui — Définissez sur upsert-kafka.
name Non — Nom d'affichage pour le puits.
properties.bootstrap.servers Oui — Liste séparée par des virgules des adresses des courtiers Kafka au format host:port.
properties.* Non — Paramètres de producteur Kafka supplémentaires. Le préfixe properties. est supprimé avant de transmettre la configuration au client. Le suffixe doit être une clé de configuration producteur Kafka valide.
sink.delivery-guarantee Non at-least-once Sémantique de livraison. Valeurs valides : none (aucune garantie ; les données peuvent être perdues ou dupliquées), at-least-once (par défaut ; aucune perte de données, mais des doublons sont possibles), exactly-once (utilise les transactions Kafka pour éliminer les doublons).
sink.add-tableId-to-header-enabled Non false Lorsqu'il est activé, écrit namespace, schemaName et tableName dans l'en-tête du message Kafka.
aliyun.kafka.accessKeyId Non — ID AccessKey de votre compte Alibaba Cloud. Requis lors de l'écriture dans ApsaraMQ for Kafka. Consultez Créer une paire de clés AccessKey.
aliyun.kafka.accessKeySecret Non — Secret AccessKey de votre compte Alibaba Cloud. Requis lors de l'écriture dans ApsaraMQ for Kafka. Consultez Créer une paire de clés AccessKey.
aliyun.kafka.instanceId Non — ID d'instance de l'instance ApsaraMQ for Kafka. Vous pouvez afficher les détails de l'instance dans la console Kafka d'Alibaba Cloud. Requis lors de l'écriture dans ApsaraMQ for Kafka.
aliyun.kafka.endpoint Non — Point de terminaison API pour ApsaraMQ for Kafka. Requis lors de l'écriture dans ApsaraMQ for Kafka. Consultez Points de terminaison.
aliyun.kafka.regionId Non — ID de région de l'instance ApsaraMQ for Kafka. Requis lors de l'écriture dans ApsaraMQ for Kafka. Consultez Points de terminaison.

Modifications de type prises en charge

Le connecteur d'ingestion de données Upsert Kafka prend en charge tous les types d'opération de journal des modifications. Pour consommer les données écrites en aval, utilisez le connecteur SQL Flink Upsert Kafka avec un schéma fixe.

Exemple d'ingestion de données

L'exemple suivant synchronise une table MySQL vers ApsaraMQ for Kafka à l'aide d'un job YAML d'ingestion de données :

source:
  type: mysql
  name: MySQL Source
  hostname: ${mysql.hostname}
  port: ${mysql.port}
  username: ${mysql.username}
  password: ${mysql.password}
  tables: ${mysql.source.table}
  server-id: 8601-8604

sink:
  type: upsert-kafka
  name: Upsert Kafka Sink
  properties.bootstrap.servers: ${upsert.kafka.bootstraps.server}
  aliyun.kafka.accessKeyId: ${upsert.kafka.aliyun.ak}
  aliyun.kafka.accessKeySecret: ${upsert.kafka.aliyun.sk}
  aliyun.kafka.instanceId: ${upsert.kafka.aliyun.instanceid}
  aliyun.kafka.endpoint: ${upsert.kafka.aliyun.endpoint}
  aliyun.kafka.regionId: ${upsert.kafka.aliyun.regionid}

route:
  - source-table: ${mysql.source.table}
    sink-table: ${upsert.kafka.topic}

Sémantique de livraison

Par défaut, le puits Upsert Kafka écrit avec des garanties au moins une fois (at-least-once). Flink peut écrire des enregistrements en double avec la même clé dans la rubrique. Comme le connecteur fonctionne en mode upsert, le dernier enregistrement pour une clé donnée prend effet lors de la relecture de la rubrique en tant que source. Les écritures en double sont donc idempotentes — elles ne corrompent pas l'état final.

Pour activer la sémantique exactement une fois (exactly-once), le cluster Kafka doit prendre en charge les transactions Kafka (Apache Kafka 0.11 ou version ultérieure) et la fonctionnalité de transaction doit être activée. Définissez sink.delivery-guarantee sur exactly-once dans la configuration YAML d'ingestion de données.

Limites

  • Nécessite Flink exécuté sur Ververica Runtime (VVR) 2.0.0 ou version ultérieure.

  • Prend en charge Apache Kafka 0.10 ou version ultérieure pour les lectures et les écritures.

  • Prend en charge uniquement les paramètres client documentés pour Apache Kafka 2.8. Consultez les références de configuration consommateur et producteur.

  • Les tables source Upsert Kafka commencent toujours à partir de earliest-offset — ce paramètre est fixe et non configurable. Le connecteur doit lire toutes les données de modification historiques pour reconstruire un journal des modifications complet. L'utilisation de tout autre mode de démarrage (tel que latest-offset ou par horodatage) entraînerait un journal des modifications incomplet et provoquerait des problèmes d'exactitude des données dans les calculs en aval.

  • Pour la sémantique de puits exactly-once, le cluster Kafka de destination doit exécuter Apache Kafka 0.11 ou version ultérieure avec les transactions activées.

Métriques de surveillance

Métriques de la table source

Métrique Description
numRecordsIn Nombre total d'enregistrements lus
numRecordsInPerSecond Enregistrements lus par seconde
numBytesIn Total des octets lus
numBytesInPerSecond Octets lus par seconde
currentEmitEventTimeLag Décalage entre l'heure de l'événement et l'heure d'émission
currentFetchEventTimeLag Décalage entre l'heure de l'événement et l'heure de récupération
sourceIdleTime Temps pendant lequel la source a été inactive
pendingRecords Nombre d'enregistrements en attente de traitement

Métriques de la table puits

Métrique Description
numRecordsOut Nombre total d'enregistrements écrits
numRecordsOutPerSecond Enregistrements écrits par seconde
numBytesOut Total des octets écrits
numBytesOutPerSecond Octets écrits par seconde
currentSendTime Temps nécessaire pour envoyer le dernier lot

Étapes suivantes