Basé sur les pratiques récentes dans les environnements de production utilisant SeaTunnel CDC (Change Data Capture) pour synchroniser des scénarios tels que Oracle, MySQL et SQL Server, et combiné avec les commentaires d'un large éventail d'utilisateurs, j'ai écrit cet article pour vous aider à comprendre le processus par lequel SeaTunnel met en œuvre CDC. Les trois étapes du CDC Le processus global de lecture des données CDC peut être divisé en trois étapes principales : Télécharger Snapshot (Full Load) Récupération Augmentation 1ère étape Snapshot La signification de la phase Snapshot est très intuitive: prenez une capture d'écran des données de la table de base actuelle et effectuez une numérisation de la table complète via JDBC. Prenant MySQL comme exemple, la position du binlog actuel est enregistrée lors de la capture d'écran : SHOW MASTER STATUS; File Position Binlog_Do_DB Binlog_Ignore_DB Executed_Gtid_Set binlog.000011 1001373553 Bénévole 0011 1001373553 SeaTunnel enregistre le fichier et la position en tant que . low watermark Remarque : Ceci n’est pas exécuté une seule fois, car SeaTunnel a mis en œuvre sa propre logique de coupe par division pour accélérer les snapshots. Remarque : Ceci n’est pas exécuté une seule fois, car SeaTunnel a mis en œuvre sa propre logique de coupe par division pour accélérer les snapshots. Mécanisme de partage de snapshot MySQL (Split) Supposons que le parallélisme global soit de 10 : SeaTunnel analysera d'abord toutes les tables et leurs rangs de clés primaires/uniques et sélectionnera une colonne de division appropriée. Il se divise en fonction des valeurs maximales et minimales de cette colonne, avec une valeur par défaut de snapshot.split.size = 8096. Les grandes tables peuvent être coupées en des centaines de divisions, qui sont allouées à 10 canaux parallèles par l'énumérateur selon l'ordre des demandes de sous-task (tendant vers une distribution équilibrée dans l'ensemble). Table-level sequential processing (schematic): // Processing sequence: // 1. Table1 -> Generate [Table1-Split0, Table1-Split1, Table1-Split2] // 2. Table2 -> Generate [Table2-Split0, Table2-Split1] // 3. Table3 -> Generate [Table3-Split0, Table3-Split1, Table3-Split2, Table3-Split3] Split-level parallel allocation: // Allocation to different subtasks: // Subtask 0: [Table1-Split0, Table2-Split1, Table3-Split2] // Subtask 1: [Table1-Split1, Table3-Split0, Table3-Split3] // Subtask 2: [Table1-Split2, Table2-Split0, Table3-Split1] Chaque Split est en fait une requête avec une condition de gamme, par exemple : SELECT * FROM user_orders WHERE order_id >= 1 AND order_id < 10001; Chaque Split enregistre séparément sa propre marque d'eau basse/marque d'eau haute. Crucial: Ne faites pas le trop petit; avoir trop de divisions n'est pas nécessairement plus rapide, et la planification et la mémoire seront très grandes. Practical Advice: split_size 2 - La phase de reprise Imaginez que vous prenez une capture d'écran complète d'une table à laquelle on écrit fréquemment.Lorsque vous lisez la 100ème ligne, les données de la 1ère ligne ont peut-être déjà été modifiées.Si vous lisez seulement la capture d'écran, les données que vous conservez lorsque vous terminez la lecture sont en fait "inconsistantes" (une partie est ancienne, une partie est nouvelle). Why is Backfill needed? The role of Backfill is to compensate for the "data changes that occurred during the snapshot" so that the data is eventually consistent. Le comportement de cette étape dépend principalement de la configuration du Le paramètre. exactly_once 2.2.1 Le mode de fonctionnement ( ) exactly_once = false Ceci est le mode par défaut; la logique est relativement simple et directe, et il ne nécessite pas de cache de mémoire: Direct Snapshot Emission: Lisse les données de snapshot et les envoie directement en aval sans entrer un cache. Émission de journaux directs: Il lit Binlog en même temps et l'envoie directement en aval. Conséquence éventuelle: Bien qu'il y ait des duplicats au milieu (ancien A envoyé d'abord, puis nouveau B), aussi longtemps que le flux en aval prend en charge les écrits idempotent (comme le REMPLACE INTO de MySQL), le résultat final est cohérent. 2.2.1 Les modes de fonctionnement des systèmes ( ) exactly_once = true C’est la partie la plus impressionnante de SeaTunnel CDC, et c’est le secret pour garantir que les données ne sont « jamais perdues, jamais répétées ». pour la dédoublement. memory buffer (Buffer) Imaginez que l'enseignant vous demande de compter combien de personnes sont dans la classe en ce moment (étape de snapshot). Cependant, les élèves de la classe sont très maladroits; tandis que vous comptez, les gens courent et sortent (changements de données). Simple Explanation: SeaTunnel le fait ainsi : Prenez une photo d'abord (Snapshot): comptez le nombre de personnes dans la classe d'abord et enregistrez-le dans un petit cahier de notes (buffer de mémoire); ne dites pas le principal (en bas) encore. Regardez la surveillance (Backfill): Récupérez la vidéo de surveillance (log de Binlog) pour la période que vous comptez. Corriger les enregistrements (merge) : Si la surveillance montre que quelqu'un vient d'entrer, mais que vous ne les avez pas comptés -> ajoutez-les. Si la surveillance montre que quelqu'un vient de sortir, mais que vous les avez comptés dans -> croisez-les. Si la surveillance montre que quelqu'un a changé ses vêtements -> changez l'enregistrement aux nouveaux vêtements. Soumettre les devoirs (Envoyer): Après la correction, le petit cahier dans votre main est une liste parfaitement précise; maintenant la remettre au principal. signifie Summary for Beginners: exactly_once = true "hold it in and don't send it until it's clearly verified." Avantage : Les données reçues en aval sont absolument propres, sans doublons ni désordre. Coût : Parce qu’il doit être « maintenu », il doit consommer une certaine mémoire pour stocker les données. 2.3 Deux questions et réponses clés Pourquoi n'y a-t-il pas d'événements READ pendant la phase de remplissage ? Q1: Why is case READ: throw Exception L’événement READ est défini par SeaTunnel lui-même, spécifiquement pour représenter « les données stock lues à partir de l’impression instantanée ». Binlog enregistre uniquement les «additions, suppressions et modifications» (INSERT/UPDATE/DELETE) et n'enregistre jamais «quelqu'un a demandé un morceau de données». Par conséquent, si vous lisez un événement READ pendant la phase Backfill, cela signifie que la logique du code est confuse. Q2: If it's placed in memory, can the memory hold it? Will it OOM? Ce n’est pas mettre toute la table en mémoire : SeaTunnel procède par divisions. Les divisions sont petites : une division par défaut ne contient que 8096 lignes de données. Jeter après utilisation: Après avoir traité une fracture, envoyez-la, effacez la mémoire et traitez la prochaine. Formule d'occupation de la mémoire ≈ : Parallélisme × Taille partagée × Taille de données de ligne unique. 2.4 Détail clé: Alignement de la marque d'eau entre plusieurs divisions Il s’agit d’une question très importante, mais si elle n’est pas traitée correctement, it will lead to data being either lost or repeated. Imaginez que deux étudiants (Split A et Split B) copient les devoirs (données de remplissage). Plain Language Explanation: Étudiant A (rapide): Copie à la page 100 et terminée à 10h00. Étudiant B (lente): copié à la page 200 et terminé à 10:05. Maintenant, l'enseignant (tâche incrémentale) doit continuer à enseigner une nouvelle leçon (lire Binlog) à partir de l'endroit où ils ont fini de copier. Si à partir de la page 200: Étudiant B est connecté, mais le contenu Étudiant A manqué entre les pages 100 et 200 (ce qui s'est passé entre 10h00 et 10h05), il est complètement perdu. Si, à partir de la page 100 : L’élève A est connecté, mais l’élève B se plaint : « Professeur, j’ai déjà copié le contenu de la page 100 à 200 ! » Solution de SeaTunnel : Commencez dès le plus tôt et couvrez vos oreilles pour ce que vous avez déjà entendu : SeaTunnel adopte un Stratégie : "Minimum Watermark Starting Point + Dynamic Filtering" Déterminer le Début : L’enseignant décide de commencer à partir de la page 100 (marque d’eau minimale parmi toutes les divisions). Filtration dynamique (ne pas écouter ce qui a été entendu): Pendant que l'enseignant est en cours de conférence (lire Binlog), ils tiennent une liste: { A: 100, B: 200 }. Lorsque le professeur atteint la page 150 : Regardez la liste; est-ce pour A? 150 > 100, A n'a pas entendu, enregistrez-le (envoyer). Regardez la liste; est-ce pour B? 150 < 200, B l'a déjà copié, sautez-le directement (discard). Mode de vitesse complète (tout le monde a terminé l'écoute): Lorsque l'enseignant atteint la page 201 et trouve que tout le monde l'a déjà entendu, ils n'ont plus besoin de la liste. avec : La phase incrémentale filtre strictement selon la combinaison de « départ d'offsets + gamme divisée + haute marque d'eau ». Summary in one sentence: exactly_once sans La phase incrémentale devient une simple "consommation séquentielle à partir d'un certain offset de départ". exactly_once 3 - La phase croissante Après la récupération (pour ) ou la phase Snapshot se termine, elle entre dans la phase incrémentale pure : exactly_once = true MySQL : basé sur le binlog. Oracle : Basé sur redo/logminer. SQL Server : Basé sur le journal de transaction / LSN. PostgreSQL : basé sur WAL. Le comportement de SeaTunnel au stade incrémental est très proche du Debezium natif : Consommez les journaux en ordre offset. Construit des événements tels que INSERT/UPDATE/DELETE pour chaque changement. Lorsque exact_once = vrai, l'état de compensation et de partage sont inclus dans le point de contrôle pour obtenir la sémantique "exactement une fois" après la récupération de l'échec. 4 Résumé La philosophie de conception de base de SeaTunnel CDC consiste à trouver l’équilibre parfait entre et "Fast" (parallel snapshots) "Stable" (data consistency). Examinons les points clés de l’ensemble du processus : La découpe (Split) est la base de l'accélération parallèle: couper de grandes tables en petits morceaux pour permettre à plusieurs fils de travailler en même temps. Snapshot est responsable du mouvement des stocks: Utilisation de tranches pour lire les données historiques en parallèle. Backfill est responsable de la couture des lacunes : c’est la étape la plus critique.Il compense les changements au cours de la capture d’écran et élimine les duplicats en utilisant des algorithmes de fusion de mémoire pour atteindre Exactly-Once. Incremental est responsable de la synchronisation en temps réel : connexion fluide à la phase Backfill et consommation continue des journaux de base de données. Pour comprendre cette trilogie de Le rôle de coordination de Il s’agit de maîtriser vraiment l’essence de SeaTunnel CDC. "Snapshot -> Backfill -> Incremental" "Watermarks"