Architekt systemówArchitektura systemów

Zaprojektuj platformę danych z geo-partitioningiem i wieloma aktywnymi węzłami, która egzekwuje zgodność z wymogami suwerenności danych, utrzymując jednocześnie opóźnienia odczytu poniżej 100 ms dla użytkowników rozproszonych na całym świecie oraz zapewniając integralność transakcyjną w różnych regionach chmurowych.

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage
  • Odpowiedź na pytanie.

Historia pytania

Przedsiębiorstwa rozwijające się na skalę globalną stają przed surowymi przepisami o miejscu przechowywania danych, takimi jak GDPR i CCPA. Tradycyjne monolityczne bazy danych centralizują dane w jednym regionie, łamiąc suwerenność lub powodując wysokie opóźnienia. Wczesne systemy rozproszone stosowały replikację aktywno-pasywną, ale to tworzyło pojedyncze punkty awarii i problemy z opóźnieniem zapisu. Nowoczesne architektury muszą wspierać wiele aktywnych regionów, w których użytkownicy w UE, USA i APAC mogą pisać lokalnie, szanując przy tym ograniczenia lokalizacji danych.

Problem

Głównym wyzwaniem jest kompromis w teorii CAP. Nie można jednocześnie mieć silnej spójności w regionach z niskim opóźnieniem i tolerancją na podziały. Dodatkowo, relacje klucza obcego obejmujące regiony stają się niemożliwe, gdy dane nie mogą przekraczać granic. Transakcje międzyregionowe niosą ryzyko naruszenia zgodności, jeśli PII wycieka podczas koordynacji. Utrzymanie odczytów poniżej 100 ms wymaga pamięci podręcznej, ale unieważnienie pamięci podręcznej w obrębie granic suwerennych jest skomplikowane.

Rozwiązanie

Zaimplementuj Architekturę opartą na komórkach używając geo-partycjonowania natywnego dla baz danych (np. CockroachDB lub Google Cloud Spanner). Partycjonuj tabele według kolumny region, zapewniając, że PII nigdy nie opuszcza swojej fizycznej komórki. Użyj Change Data Capture (CDC) przez Apache Kafka do replikacji tylko niesensytywnego metadanych na całym świecie. Dla transakcji międzyregionowych zaimplementuj wzorzec Saga z lokalnymi kompensacjami, aby uniknąć blokad rozproszonych. Rozmieść klastry Redis na brzegu z wzorcem Cache-Aside dla obciążenia z dużą ilością odczytów, używając unieważnienia opartego na TTL, aby uniknąć koordynacji pamięci podręcznej międzyregionowej.

  • Sytuacja z życia

Kontekst

Globalny procesor płatności potrzebował uruchomić działalność w Niemczech i Singapurze, jednocześnie utrzymując swoje centrum danych w USA. Wymogi regulacyjne wymagały, aby historie transakcji użytkowników z UE pozostawały fizycznie w Frankfurcie, podczas gdy dane z APAC pozostawały w Singapurze. Jednak transfery międzygraniczne wymagały pobrania funduszy z konta USA i zaksięgowania na konto UE w ramach tej samej logicznej transakcji, jednocześnie utrzymując zapytania o saldo poniżej 100 ms.

Rozwiązanie 1: Zcentralizowana baza danych z regionalnymi replikami odczytu

To podejście zakładało hostowanie głównej bazy danych w USA-Wschód z replikami do odczytu w UE i APAC, oferując prosty model spójności i jednoznaczne gwarancje ACID bez skomplikowanej synchronizacji. Jednak narusza to przepisy o suwerenności danych, ponieważ ruch zapisu kieruje do USA-Wschód, potencjalnie przechowując PII z UE na terytorium USA, podczas gdy zapisy z Singapuru mają opóźnienie przekraczające 200 ms, co nie spełnia wymagań dotyczących doświadczeń użytkownika. Architektura ta tworzy również pojedynczy punkt awarii w USA-Wschód, co czyni ją nieakceptowalną dla globalnej platformy płatniczej wymagającej autonomii regionalnej.

Rozwiązanie 2: Całkowicie izolowane silosy regionalne z nocnym ETL

Ten projekt działa w niezależnych klastrach PostgreSQL w każdym regionie, przetwarzając transfery międzyregionowe podczas nocnych okien konserwacyjnych w celu zapewnienia doskonałej izolacji zgodności i prostej autonomii regionalnej. To podejście nie wspiera rzeczywistych płatności międzynarodowych, co prowadzi do złego doświadczenia użytkownika i utrudnia wyjaśnianie błędów rozliczeniowych w trakcie przetwarzania zbiorczego. Dodatkowo architektura ta nie może obsługiwać globalnych agregacji sald kont bez znacznego opóźnienia, co czyni ją nieodpowiednią dla nowoczesnej platformy fintech.

Rozwiązanie 3: Baza danych z geo-partitioningiem i orkiestracją Saga

Ta strategia wdraża CockroachDB z tabelami geo-partycjonowanymi przy użyciu mapowania partition_key do regionalnych domów użytkowników, wdrażając workflow Temporal do zarządzania transferami międzyregionowymi jako lokalnymi transakcjami z akcjami kompensacyjnymi. Ten projekt egzekwuje natywną lokalizację danych poprzez ograniczenia partycjonowania, osiągając lokalne odczyty poniżej 50 ms poprzez wynajmujących przypisanych do regionalnych węzłów, chociaż wprowadza złożoność operacyjną wym requiring expert knowledge in distributed SQL. Rozwiązanie to radzi sobie z ostateczną spójnością dla metadanych międzyregionowych za pomocą strumieni Kafka CDC i zarządza tymczasową niespójnością podczas wykonywania sagi poprzez widoczność stanu oczekiwania opartą na TTL.

Wybrane podejście

Zespół wybrał Rozwiązanie 3, ponieważ unikalnie spełniało zarówno wymogi dotyczące zgodności, jak i ograniczenia opóźnienia, nie poświęcając semantyki transakcyjnej ani nie wymagając destrukcyjnych migracji danych. Skonfigurowali tabele CockroachDB REGIONAL BY ROW, przypisując wiersze UE do węzłów Frankfurt, wdrożyli klastry Redis w lokalizacjach brzegowych z 5-sekundowym TTL dla pamięci podręcznej metadanych oraz zaimplementowali sagi Temporal do orkiestracji transferów międzyregionowych z automatycznymi kompensacjami w przypadku błędu.

Wynik

System przeszedł audyty GDPR z zerowym wyciekiem PII międzygranicznych podczas przetwarzania 50,000 codziennych transakcji międzyregionowych z opóźnieniem odczytu w 99. percentylu wynoszącym 45 ms. Zespoły wsparcia klienta mogły zapytywać o stany oczekujących sagi za pośrednictwem punktów końcowych API, aby rozwiązywać przejściowe niespójności podczas awarii regionalnych. Architektura ta teraz wspiera ekspansję na nowe rynki poprzez po prostu dodawanie nowych komórek do klastra CockroachDB bez zmian w aplikacji.

  • Czego często brakuje kandydatom

Jak utrzymujesz integralność referencyjną, gdy relacja klucza obcego obejmuje dwa obszary suwerenności danych?

Nie można narzucić ograniczeń klucza obcego na poziomie bazy danych między regionami, gdy dane nie mogą fizycznie opuścić swojej strefy. Zaimplementuj integralność referencjonalną na poziomie aplikacji za pomocą referencji UUID oraz asynchronicznej walidacji przez Outbox Pattern, publikując do Kafka; konsumenci weryfikują referencje i publikują potwierdzenia, z detekcją sierot po upływie czasu. To poświęca natychmiastową spójność dla zgodności, ale zapewnia ostateczną integralność bez migracji danych, używając kompensacji Saga do wycofania transakcji odwołujących się do nieważnych kluczy obcych.

Co się dzieje z transakcjami w trakcie, gdy region ulega awarii podczas międzyregionowej sagi?

Wzorce Saga nie obsługują automatycznie awarii; musisz projektować pod kątem idempotencji używając kluczy idempotencji przechowywanych lokalnie w Redis lub Etcd w każdym regionie, aby zapobiec duplikacji przetwarzania podczas powtórek. Jeśli Region B zawiesza się podczas operacji kredytowej, czasy oczekiwania wyzwalają transakcje kompensacyjne w Regionie A, aby zwrócić odjęte kwoty, wykorzystując Advisory Locks PostgreSQL lub Locki Rozproszone ZooKeeper do zapobiegania wyścigom podczas awarii orkiestratora. System musi udostępnić stany oczekujących transakcji za pośrednictwem punktów końcowych API w celu interwencji wsparcia klienta, zapewniając, że częściowe stany awarii pozostają możliwe do zapytania i rozwiązania bez uszkodzenia danych.

Jak przeprowadzasz migracje schematu bez przestojów w całych komórkach z geo-partycjonowaniem z różnymi oknami konserwacyjnymi?

Zastosuj wzorzec Expand-Contract w połączeniu z Feature Flags zarządzanymi przez LaunchDarkly, najpierw wdrażając dodatnie zmiany DDL (nowe kolumny, tabele) we wszystkich regionach podczas ich odpowiednich okien, używając Flyway lub Liquibase, tego samego czasu zachowując zgodność wsteczną aplikacji. Migrację danych wykonuj asynchronicznie, używając strumieni Debezium CDC, a następnie włącz nowe ścieżki kodowe za pomocą flag funkcji dopiero po potwierdzeniu propagacji schematu za pomocą kontroli zdrowia, zapewniając, że żaden region nie obsługuje przestarzałych danych. Nigdy nie wykonuj destrukcyjnych DDL (usuwanie kolumn), dopóki wszystkie regiony nie potwierdzą zakończenia migracji, wykorzystując wdrożenia Blue-Green w każdej komórce, aby natychmiast cofnąć się, jeśli opóźnienie replikacji przekroczy progi.