Baserat på senaste praxis i produktionsmiljöer som använder SeaTunnel CDC (Change Data Capture) för att synkronisera scenarier som Oracle, MySQL och SQL Server, och i kombination med feedback från ett brett spektrum av användare, har jag skrivit den här artikeln för att hjälpa dig att förstå den process genom vilken SeaTunnel implementerar CDC. De tre stadierna av CDC Den övergripande CDC-dataläsningsprocessen kan delas in i tre huvudsteg: Snabbbild (Full Load) Backfyllning ökande 1. snapshot steg Betydelsen av Snapshot-steget är mycket intuitivt: ta en snapshot av den aktuella databasens tabelldata och utföra en fullständig tabellskanning via JDBC. Ta MySQL som ett exempel, den aktuella binlog positionen registreras under snapshot: SHOW MASTER STATUS; File Position Binlog_Do_DB Binlog_Ignore_DB Executed_Gtid_Set binlog.000011 1001373553 Länkar 0011 1001373553 SeaTunnel registrerar filen och platsen som . low watermark Obs: Detta utförs inte bara en gång, eftersom SeaTunnel har implementerat sin egen split-cut-logik för att påskynda snapshots. Obs: Detta utförs inte bara en gång, eftersom SeaTunnel har implementerat sin egen split-cut-logik för att påskynda snapshots. MySQL Snapshot Splitting Mechanism (Split) Översikt Anta att den globala parallellismen är 10: SeaTunnel analyserar först alla tabeller och deras primärnyckel / unika nyckelintervall och väljer en lämplig uppdelningskolumn. Den är uppdelad baserat på de maximala och minimivärdena i den här kolumnen, med standardinställningen snapshot.split.size = 8096. Stora tabeller kan skäras in i hundratals Splits, som tilldelas till 10 parallella kanaler av numeratorn enligt ordningen av underuppgiftsförfrågningar (tenderar mot en balanserad fördelning överlag). 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] Varje Split är faktiskt en fråga med ett intervall villkor, till exempel: SELECT * FROM user_orders WHERE order_id >= 1 AND order_id < 10001; Varje Split registrerar separat sitt eget låga vattenmärke/högt vattenmärke. Crucial: Gör inte den för liten; att ha för många Splits är inte nödvändigtvis snabbare, och schemaläggningen och minnet överhuvud kommer att vara mycket stort. Practical Advice: split_size 2. backfill steg Föreställ dig att du gör en fullständig snapshot av en tabell som ofta skrivs till. När du läser den 100:e raden kan data i den 1:e raden redan ha ändrats. Om du bara läser snapshotet är data du håller när du slutar läsa faktiskt "inkonsekvent" (en del är gammal, en del är ny). 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. Uppförandet av detta stadium beror huvudsakligen på konfigurationen av och parametrar. exactly_once 2.1 Enkel metod ( ) exactly_once = false Detta är standardläget; logiken är relativt enkel och direkt, och det kräver inte minne caching: Direkt snapshot-utsläpp: Läser snapshot-data och skickar den direkt nedströms utan att ange en cache. Direkt Log Emission: Läser Binlog samtidigt och skickar den direkt nedströms. Eventuell Konsistens: Även om det kommer att finnas dubbletter i mitten (gammal A skickas först, sedan ny B), så länge nedströmningen stöder idempotent skriver (som MySQL: s REPLACE INTO), är slutresultatet konsekvent. 2.2 Exakt en gång-läge ( ) exactly_once = true Detta är den mest imponerande delen av SeaTunnel CDC, och det är hemligheten att garantera att data är "aldrig förlorad, aldrig upprepas." För att duplicera. memory buffer (Buffer) Föreställ dig att läraren ber dig att räkna hur många människor som är i klassen just nu (Snapshot scenen). emellertid är eleverna i klassen mycket dåliga; medan du räknar, människor springer in och ut (data förändras). Simple Explanation: SeaTunnel gör det så här: Ta ett foto först (Snapshot): Räkna antalet personer i klassen först och registrera det i en liten anteckningsbok (minnesbuffert); berätta inte huvudpersonen (nedström) ännu. Titta på övervakningen (Backfill): Hämta övervakningsvideon (Binlog logg) för den period du räknade. Korrigera de poster (Merge): Om övervakningen visar att någon just kom in, men du inte räknade dem -> lägg till dem. Om övervakningen visar någon bara sprang ut, men du räknade dem i -> korsa dem ut. Om övervakningen visar någon ändrade sina kläder -> ändra posten till de nya kläderna. Skicka in arbetsuppgifter (Skicka): Efter korrigering är den lilla anteckningsboken i din hand en perfekt exakt lista; nu överlämna den till huvudmannen. betyder Summary for Beginners: exactly_once = true "hold it in and don't send it until it's clearly verified." Fördel: De data som tas emot nedströms är helt rena, utan dubbletter eller störningar. Kostnad: Eftersom det måste "hållas in", behöver det förbruka lite minne för att lagra data. 2.3 Två viktiga frågor och svar Varför finns det inga READ-händelser under Backfill-fasen? Q1: Why is case READ: throw Exception READ-händelsen definieras av SeaTunnel själv, specifikt för att representera "lagerdata läst från ögonblicket." Binlog bara registrerar "tillägg, raderingar och modifieringar" (INSERT/UPDATE/DELETE) och aldrig registrerar "någon frågade en bit av data." Om du läser en READ-händelse under Backfill-fasen betyder det att kodlogiken är förvirrad. Q2: If it's placed in memory, can the memory hold it? Will it OOM? Det är inte att sätta hela tabellen i minnet: SeaTunnel processer genom splits. Delningar är små: En standarddelning har endast 8096 rader med data. Kasta bort efter användning: Efter bearbetning av en split, skicka den, rensa minnet och bearbeta nästa. Formel för minneskapacitet ≈ : Parallellism × Split storlek × Single row data storlek. 2.4 Viktig detalj: Watermark Alignment Between Multiple Splits Detta är en mycket dold men oerhört viktig fråga.Om det inte hanteras väl, it will lead to data being either lost or repeated. Problemet med snabb/långsam löpare: Föreställ dig att två elever (Split A och Split B) kopierar läxor (Backfill data). Plain Language Explanation: Student A (snabb): Kopierad till sida 100 och färdig vid 10:00. Student B (långsam): Kopierad till sida 200 och precis färdig vid 10:05. Nu behöver läraren (Incremental task) fortsätta att undervisa en ny lektion (läs Binlog) från där de slutade kopiera. Om du börjar på sidan 200: Student B är ansluten, men innehållet Student A missade mellan sidorna 100 och 200 (vilket hände mellan 10:00 och 10:05) är helt förlorad. Om Student A är ansluten, men Student B klagar: "Lärare, jag har redan kopierat innehållet från sidan 100 till 200!" SeaTunnels lösning: Börja från början och täck dina öron för vad du redan har hört: SeaTunnel antar en och strategi: "Minimum Watermark Starting Point + Dynamic Filtering" Bestäm Start (vård för den långsamma): Läraren bestämmer sig för att börja från sida 100 (det minsta vattenstämpeln bland alla splits). Dynamisk filtrering (lyssna inte på vad som har hörts): Medan läraren föreläsar (läser Binlog), håller de en lista: { A: 100, B: 200 }. När läraren når sida 150: Titta på listan; är det för A? 150 > 100, A har inte hört det, registrera det (sänd). Titta på listan; är det för B? 150 < 200, B redan kopierat det, hoppa över det direkt (discard). Full hastighetsläge (alla har slutat lyssna): När läraren når sidan 201 och finner att alla redan har hört det, behöver de inte längre listan. med : Det incrementella steget filtrerar strikt enligt kombinationen av "start offset + split intervall + hög vattenstämpel". Summary in one sentence: exactly_once utan Det incrementella steget blir en enkel "sekventiell förbrukning från en viss startoffset." exactly_once 3. ökande steg Efter återhämtningen (för ) eller Snapshot fasen slutar, det går in i den rena incrementella fasen: exactly_once = true MySQL: Baserat på binlogg Oracle: Baserat på redo / logminer. SQL Server: Baserat på transaktionslogg / LSN. PostgreSQL: Baserat på WAL SeaTunnels beteende i den incrementella etappen är mycket nära den inhemska Debezium: Konsumerar loggar i offsetordning. Konstruerar händelser som INSERT/UPDATE/DELETE för varje ändring. När exact_once = true ingår offset- och split-status i kontrollpunkten för att uppnå "exakt en gång" semantik efter felåterställning. 4 Sammanfattning Kärnfilosofin för SeaTunnel CDC är att hitta den perfekta balansen mellan och "Fast" (parallel snapshots) "Stable" (data consistency). Låt oss granska de viktigaste punkterna i hela processen: Slicing (Split) är grunden för parallell acceleration: Skärning av stora tabeller i små bitar för att låta flera trådar arbeta samtidigt. Snapshot är ansvarig för att flytta lager: Använda skivor för att läsa historiska data parallellt. Backfill är ansvarig för att sy luckorna: Detta är det mest kritiska steget. Det kompenserar för förändringar under snapshot och eliminerar dubbletter med hjälp av minnesfusion algoritmer för att uppnå Exactly-Once. Incremental ansvarar för realtidssynkronisering: sömlös anslutning till Backfill-fasen och kontinuerlig förbrukning av databasloggar. Förstå denna trilogi av Den samordnande rollen för Inom det är att verkligen behärska essensen av SeaTunnel CDC. "Snapshot -> Backfill -> Incremental" "Watermarks"