Przejdź do głównej zawartości
GIFRÖST / Przetwarzanie CDC

Jak replikator przetwarza dane.

GIFRÖST działa w oparciu o Apache Kafka oraz Kafka Connect. Konektory źródłowe odczytują zmiany z bazy źródłowej lub narzędzi źródłowych, zapisują je do topiców Kafka, a konektory docelowe pobierają te rekordy i wykonują odpowiadające im operacje w bazie docelowej.

Log źródłaDML jest odczytywany z logu transakcyjnego.
Konektor źródłowyKafka Connect publikuje zdarzenia do Kafka.
Topiki KafkaZdarzenia są utrwalane i dostarczane w kolejności per partycja.
Konektor docelowyDML jest wykonywany na bazie docelowej.

Wprowadzenie

Dla baz transakcyjnych konektor źródłowy nie musi cyklicznie odpytywać tabel biznesowych. Odczytuje zmiany zapisane przez silnik bazy danych w logu transakcyjnym. W zależności od technologii bazy taka pozycja może być reprezentowana na przykład przez PostgreSQL LSN albo Oracle SCN. Konektor przechwytuje zatwierdzone operacje DML, takie jak INSERT, UPDATE, DELETE oraz TRUNCATE, zamienia je na rekordy Kafka Connect i zapisuje do Kafka.

Przepływ CDC GIFRÖST od logów transakcyjnych przez Kafka Connect i Kafka do bazy docelowej

Konektor źródłowy działa w Kafka Connect i odpowiada za opublikowanie zmian do Kafka. Konektor docelowy, również uruchomiony w Kafka Connect, konsumuje rekordy z Kafka i wykonuje odpowiadające im operacje DML na bazie docelowej.

Krok 01Odczyt logu transakcyjnego

Baza danych zapisuje zatwierdzone zmiany w logu transakcyjnym. Czytnik CDC pobiera zmiany wierszy z minimalnym wpływem na system źródłowy i bez zmian w aplikacji źródłowej.

Krok 02Konektor źródłowy w Kafka Connect

Konektor źródłowy zamienia wpisy z logu na ustrukturyzowane zdarzenia zmian i publikuje je do topiców Kafka. Na tym etapie można stosować mapowania i transformacje po stronie źródła.

Krok 03Kafka jako backbone zdarzeń

Kafka przechowuje strumień zmian, oddziela producentów od konsumentów i daje konektorom docelowym trwałe miejsce, z którego mogą kontynuować odczyt.

Krok 04Konektor docelowy wykonuje DML

Konektor docelowy odczytuje rekordy z Kafka, gdy tylko się pojawią, i wykonuje równoważne operacje DML w bazie docelowej.

Wpływ na wydajność bazy źródłowej

Mechanizm CDC opiera się na odczycie natywnych logów transakcyjnych baz danych, takich jak Oracle LogMiner, PostgreSQL WAL lub inne mechanizmy właściwe dla danej technologii. Dzięki temu replikacja nie wymaga stosowania triggerów na tabelach biznesowych ani wykonywania dodatkowych zapytań odczytujących dane bezpośrednio z tych tabel. Pozwala to ograniczyć wpływ na wydajność systemu źródłowego do minimum.

Bez triggerówBrak logiki dopisywanej do transakcji aplikacji

CDC nie wymaga instalowania triggerów na replikowanych tabelach, więc nie dodaje własnego kodu wykonywanego synchronicznie w każdej transakcji biznesowej.

Bez odpytywania tabelOdczyt z logu zamiast zapytań do tabel

Konektor korzysta z logu transakcyjnego, dlatego nie generuje cyklicznych zapytań skanujących tabele źródłowe w celu wykrycia zmian.

POCWeryfikacja na środowisku klienta

Rzeczywisty wpływ zależy od charakterystyki środowiska, wolumenu zmian i konfiguracji. Dlatego obciążenie może zostać potwierdzone na środowisku klienta w ramach POC.

Doświadczenia z wdrożeń i testów

Z naszych doświadczeń z testów wewnętrznych oraz prac prowadzonych u klientów wynika, że poprawnie skonfigurowany mechanizm CDC nie powodował przypadków wzrostu obciążenia bazy źródłowej większego niż 10%. Wartość tę należy traktować jako obserwację z dotychczasowych testów, a nie gwarancję dla każdego środowiska produkcyjnego.

Dla systemów krytycznych rekomendowane jest wykonanie POC z metrykami CPU, I/O, wait eventów, opóźnienia replikacji i wolumenu logów transakcyjnych, aby potwierdzić wpływ CDC w warunkach zbliżonych do produkcyjnych.

Kolejność zdarzeń

Kolejność zdarzeń jest zapewniana dla pojedynczej tabeli. Log transakcyjny jest odczytywany przez jednowątkowy proces, a zmiany tabel trafiają do jednopartycyjnych topiców Kafka. Ponieważ Kafka zachowuje kolejność w obrębie jednej partycji, konektor docelowy otrzymuje zdarzenia dla jednej tabeli w tej samej kolejności, w której zostały wyprodukowane.

Model kolejności

W obrębie jednej tabeli: zdarzenia DML są przetwarzane sekwencyjnie, więc update'y, inserty i delete'y dla tej samej tabeli są dostarczane w kolejności.

Między różnymi tabelami: mogą wystąpić wyścigi, ponieważ niezależne topiki i zadania po stronie docelowej mogą przetwarzać dane z minimalnie inną prędkością.

W obrębie jednej transakcji dla jednej tabeli: kolejność zdarzeń pozostaje stabilna dla tej tabeli. Kolejność transakcyjna między różnymi tabelami nie powinna być traktowana jako globalna gwarancja dostarczenia.

Wznawianie działania

Mechanizm wznawiania replikacji jest realizowany natywnie przez Apache Kafka Connect. Connect zapisuje postęp konektorów w dedykowanym topicu offsetowym Kafka. Dla konektorów źródłowych offset oznacza ostatnią przetworzoną pozycję źródłową, na przykład LSN dla PostgreSQL albo SCN dla Oracle. W przypadku zatrzymania lub awarii konektora, po ponownym uruchomieniu odczytywany jest zapisany offset, a replikacja jest automatycznie wznawiana od ostatnio przetworzonego miejsca, bez konieczności ponownego odczytu wszystkich danych i bez dodatkowego wpływu na działanie systemu źródłowego.

Offset źródłowyPozycja w logu transakcyjnym

Konektor źródłowy zapisuje ostatnią pozycję logu transakcyjnego, która została poprawnie przetworzona. Po restarcie kontynuuje pracę dokładnie od tego miejsca.

Offset docelowyOstatni przetworzony rekord Kafka

Analogiczny mechanizm dotyczy konektorów docelowych. Zapisują one informację o ostatnim przetworzonym rekordzie Kafka i wznawiają konsumpcję od właściwego miejsca.

Obsługa błędów po stronie bazy docelowej

Podczas używania konektora JDBC Sink rozwiązanie zapewnia mechanizm Dead Letter Queue (DLQ). Jest to dedykowany, trwały rejestr rekordów, których nie udało się zastosować w bazie docelowej. Każda operacja zakończona błędem, na przykład naruszeniem ograniczeń integralności, niezgodnością typów danych albo brakiem kolumny, jest automatycznie zapisywana w wydzielonym topicu Kafka pełniącym rolę rejestru błędnych transakcji.

DLQTrwały rejestr błędnych rekordów

Rekord, którego nie udało się zapisać w bazie docelowej, trafia do dedykowanego topicu Kafka wraz z informacją o błędzie. Retencja tego topicu jest konfigurowalna, dlatego DLQ może być utrzymywana zgodnie z wymaganiami operacyjnymi i audytowymi.

DiagnostykaPełny kontekst błędu

Do DLQ zapisywany jest kontekst pozwalający jednoznacznie zidentyfikować rekord źródłowy, etap przetwarzania oraz przyczynę błędu zgłoszoną przez bazę docelową.

ReprocessingPonowne przetworzenie po naprawie

Po usunięciu przyczyny błędu rekordy z DLQ mogą zostać ponownie przetworzone bez utraty danych, ponieważ rejestr zawiera oryginalny, kompletny obraz zmiany.

Zakres informacji zapisywanych w DLQ

Kompletna treść rekordu: obraz zmiany obejmujący typ operacji INSERT, UPDATE albo DELETE, klucz rekordu oraz wartości kolumn przed i po zmianie, jeśli są dostępne w zdarzeniu źródłowym.

Pochodzenie rekordu: topic, partycja i offset Kafka, które pozwalają jednoznacznie wskazać transakcję lub zdarzenie źródłowe.

Szczegóły błędu bazy docelowej: klasa wyjątku, komunikat błędu, kod błędu zgłoszony przez bazę, na przykład ORA-00001, oraz pełny stack trace.

Kontekst przetwarzania: etap, na którym wystąpił błąd, identyfikator konektora lub komponentu oraz dane diagnostyczne potrzebne do analizy incydentu.

Zawartość DLQ jest trwała, przeszukiwalna i dostępna z poziomu panelu administracyjnego oraz API. Opcjonalnie zawartość rejestru błędów może być odkładana również do tabeli relacyjnej wskazanej przez Zamawiającego. Równolegle każdy błąd wykonania jest rejestrowany w logach systemowych rozwiązania z konfigurowalnym poziomem szczegółowości, włącznie z możliwością logowania pełnej treści instrukcji SQL, jeśli taka konfiguracja jest dopuszczona przez politykę bezpieczeństwa środowiska.

Replikacja DDL

System GIFRÖST zapewnia przechwytywanie operacji DDL wykonywanych na źródłowej bazie Oracle. Instrukcje DDL są odczytywane ze strumienia redo przez LogMiner, parsowane i zapisywane w dedykowanym repozytorium historii schematu, czyli schema history. Dzięki temu system na bieżąco utrzymuje aktualną definicję struktur replikowanych tabel i kontynuuje replikację po zgodnych zmianach schematu na źródle.

InicjalizacjaAuto-create

System może automatycznie utworzyć schemat tabel na etapie inicjalizacji replikacji. Ta operacja nie gwarantuje odwzorowania struktury DDL 1:1, dlatego dla środowisk produkcyjnych zaleca się wykonanie jej ręcznie albo przy pomocy dedykowanych skryptów.

Zmiany addytywneAuto-evolve

System w ograniczony sposób umożliwia automatyczną propagację addytywnych zmian struktury. Typowym wspieranym przypadkiem jest dodanie nowych kolumn do replikowanych tabel.

Tryb kontrolowanyZłożone zmiany DDL

Zmiana nazwy kolumny, usunięcie kolumny oraz modyfikacja typów danych są obsługiwane w trybie kontrolowanym. System sygnalizuje zmianę schematu, konektor się zatrzymuje i wymaga ręcznej modyfikacji po stronie administratora bazy danych, po czym zasilanie można wznowić automatycznie albo manualnie.

Kompresja i szyfrowanie

GIFRÖST może korzystać z mechanizmów kompresji dostępnych na kilku poziomach potoku: w konfiguracji Kafka Connect, w ustawieniach konektorów źródłowych i docelowych, w Kafka oraz na warstwie zapisu danych na dysku Kafka. Pozwala to ograniczyć ruch sieciowy, zmniejszyć użycie przestrzeni dyskowej przez topiki oraz lepiej wykorzystać zasoby klastra przy dużym wolumenie zmian.

Kafka ConnectKompresja po stronie producerów i konektorów

Konektory źródłowe publikujące dane do Kafka mogą używać kompresji producenta, na przykład przez ustawienie compression.type. Typowe algorytmy to gzip, snappy, lz4 oraz zstd. Konfigurację można ustawiać na poziomie workerów Kafka Connect albo per konektor, jeśli polityka nadpisywania ustawień klienta na to pozwala.

KafkaKompresja topiców i danych na dysku

Kafka przechowuje rekordy w segmentach logu. Skompresowane batche wysłane przez producenta mogą pozostać skompresowane również podczas zapisu na dysku brokera, a ustawienia topicu lub brokera mogą wymuszać wybrany typ kompresji. Dzięki temu kompresja zmniejsza zarówno transfer sieciowy, jak i ilość danych przechowywanych w logach Kafka.

Konektory doceloweOdczyt skompresowanych rekordów i zapis do celu

Konektory docelowe konsumują rekordy z Kafka bez konieczności dodatkowej obsługi formatu kompresji - dekompresja jest wykonywana przez klienta Kafka. Po stronie zapisu do bazy docelowej można dodatkowo korzystać z batching'u oraz mechanizmów kompresji protokołu lub sterownika, jeśli są wspierane przez konkretną technologię docelową.

Szyfrowanie w obrębie Kafka Connect i Kafka jest realizowane przede wszystkim przez mechanizmy transportowe oraz kontrolę dostępu. Kompresja i szyfrowanie pełnią różne role: kompresja zmniejsza rozmiar przesyłanych i składowanych danych, a szyfrowanie chroni poufność komunikacji oraz dostęp do zasobów klastra.

Mechanizmy szyfrowania i ochrony danych

TLS/SSL między Kafka Connect a brokerami Kafka: komunikacja workerów, producerów i consumerów może działać po szyfrowanym kanale przez konfigurację security.protocol=SSL albo SASL_SSL oraz ustawienia truststore i keystore.

mTLS i uwierzytelnianie klientów: broker może wymagać certyfikatów klienta, dzięki czemu worker Kafka Connect i konektory potwierdzają swoją tożsamość przy połączeniu z Kafka.

SASL oraz ACL: uwierzytelnianie może być realizowane przez mechanizmy takie jak SCRAM, GSSAPI/Kerberos, OAUTHBEARER albo PLAIN uruchamiany wyłącznie przez TLS. Uprawnienia do topiców, grup konsumenckich i zasobów klastra mogą być ograniczane przez ACL.

HTTPS dla REST API Kafka Connect: interfejs REST workerów Connect może być wystawiony po HTTPS, a dostęp do operacji administracyjnych można ograniczyć przez warstwę uwierzytelniania i konfigurację sieciową.

Szyfrowane połączenia do baz źródłowych i docelowych: konektory mogą używać TLS/SSL w konfiguracji połączeń JDBC lub natywnych klientów bazodanowych, jeśli wspiera to dana baza danych.

Sekrety i szyfrowanie danych na dysku: hasła i tokeny powinny być przechowywane poza jawną konfiguracją konektorów, na przykład przez ConfigProvider albo zewnętrzny magazyn sekretów. Szyfrowanie logów Kafka na dysku realizuje się zwykle na poziomie wolumenu, systemu plików lub usługi storage/KMS, ponieważ Kafka sama odpowiada za zapis segmentów logu, a szyfrowanie at-rest jest domeną warstwy infrastruktury.

Skalowalność

GIFRÖST można skalować pionowo i poziomo. Zwiększenie zasobów CPU, RAM oraz wydajności dysku zwiększa możliwości przetwarzania Kafka, Kafka Connect i usług pomocniczych. Można także dodawać nowe instancje Kafka Connect, co zwiększa liczbę konektorów, które mogą działać równolegle.

Skalowanie pionoweWięcej CPU, RAM i przepustowości dysku

Zwiększenie zasobów serwera poprawia obsługę większego wolumenu zmian, większej liczby zadań konektorów oraz dłuższych okien retencji.

Skalowanie Kafka ConnectWięcej instancji workerów

Dodanie instancji Kafka Connect zwiększa pojemność klastra workerów i pozwala uruchamiać więcej konektorów źródłowych oraz docelowych.

Partycje KafkaWiększa równoległość, gdy kolejność nie jest wymagana

Jeśli nie zależy nam na ścisłej kolejności dostarczanych danych, można zwiększać liczbę partycji w Kafka, aby uzyskać większą równoległość. Dla replikacji z kolejnością na poziomie tabeli rekomendowanym modelem pozostają topiki jednopartycyjne.