Zapisy w wielu regionach: gdzie naprawdę następuje zatwierdzenie?
Routing doprowadza żądanie do regionu; tylko granica transakcji czyni zapis atomowym. Nazwij niezmiennik, wybierz właściciela, a potem zaprojektuj ponowienie wokół niego.
Dwa serwery aplikacji w dwóch regionach, jeden klient zapisujący przez VPN i pytanie, którego nikt nie zapisał: który komponent decyduje, że zapis nastąpił? Routing doprowadza żądanie do procesu. Granica transakcji decyduje, kiedy zmiana staje się trwała i widoczna. To różne zadania wykonywane przez różne systemy, a luka między nimi to miejsce, w którym żyje większość błędów zapisów w wielu regionach.
Zacznij od reguły biznesowej, nie od mapy
Zacznij od zdania o regule biznesowej, a nie o geografii: które odczyty i zapisy muszą się udać razem i które równoczesne zmiany muszą być w tym czasie niemożliwe. Dla rezerwacji zapasów oznacza to, że sprawdzenie stanu i rezerwacja albo oba wchodzą w życie, albo żadne, i żadne drugie zamówienie nie może w międzyczasie zużyć tej samej jednostki.
| Requirement | What satisfies it | What does not |
|---|---|---|
| All-or-nothing application | A transaction inside one owning system | A VPN path between regions |
| No double spend | Isolation strong enough to exclude the conflict | Atomicity alone |
| Survive a region loss | Replication the database itself documents | Two independent databases behind one client |
Właśnie ten środkowy wiersz zespoły pomijają. Atomowość bez wystarczającej izolacji pozwala dwóm transakcjom każdej poprawnie się zatwierdzić i mimo to wytworzyć stan, który biznes uznaje za niemożliwy, a żadna ilość logiki ponowień tego później nie naprawia.
Jedna granica władzy bije dwa serwery regionalne
Regionalne serwery aplikacji mogą zostać tam, gdzie są, o ile przekazują operację usłudze, która wykonuje ją w obrębie jednej obsługiwanej granicy transakcji. Warstwa aplikacji staje się routerem intencji; warstwa danych posiada prawdę.
Trzymaj tę granicę krótką i blisko danych, których dotyka. Transakcja utrzymywana otwarta, gdy człowiek odpowiada na monit albo gdy wywołanie przekracza dwa regiony, spędza czas na trzymaniu blokad i zwiększa szansę, że coś innego za nią przekroczy limit czasu. Ta awaria wygląda jak problem bazy danych, a w rzeczywistości jest problemem projektowym przebranym za taki. Przeniesienie decyzji do warstwy danych zwykle usuwa go całkowicie.
BEGIN;
UPDATE inventory SET reserved = reserved + 1
WHERE sku = 'A-100' AND available >= 1;
INSERT INTO reservation (sku, order_id) VALUES ('A-100', 'ord-9f');
COMMIT;
Czytaj ten szkic jako granicę, nie jako zalecenie wydajnościowe. Rzecz w tym, że sprawdzenie i wstawienie dzielą jedno zatwierdzenie, więc równoczesne zamówienie albo widzi zapas zużyty, albo nie widzi go wcale.
Co daje, a czego nie daje replikowana baza danych
Replikowana baza danych może zapewnić szerszą granicę, gdy pozwala na to jej własny model transakcji. Spanner dokumentuje atomowe transakcje odczytu i zapisu w obrębie jednej bazy danych na wielu tabelach, z określoną izolacją i zachowaniem ponowień. To gwarancja, którą się czyta, testuje i na której świadomie polega.
To także gwarancja, która pochodzi z produktu, a nie z trasy. VPN między regionami zmienia sposób podróżowania pakietów i sposób objawiania się awarii. Nie wydłuża granicy transakcji ani o jeden wiersz, niezależnie od tego, jak zdrowy wygląda tunel. Mylenie obu rzeczy daje architektury, w których każdy komponent przechodzi własne sprawdzenie, a dane wciąż się nie zgadzają.
Dwie bazy danych nie stają się jednym systemem
Dwie niezależnie zarządzane bazy danych nie zyskują wspólnego menedżera transakcji dlatego, że klienci mogą dotrzeć do obu. Jeśli biznes naprawdę potrzebuje atomowego zobowiązania w obrębie tej pary, mechanizm koordynacji, uczestnicy i proces odzyskiwania muszą zostać wybrane i zakwalifikowane, a nie założone.
Pomyśl o chwili, w której uczestnik albo łącze znika po przygotowaniu pracy. Obsługiwane rozproszone zatwierdzenie może pozostawić niepewny stan wymagający procedury odzyskiwania i ludzkiej decyzji, i nie przychodzi z obietnicą, że każdy region pozostanie zapisywalny przez każdy podział.
Jeśli zamiast tego akceptowalna jest koordynacja asynchroniczna, powiedz to wprost i zapisz stany pośrednie biznesu oraz reguły uzgadniania. Łańcuch lokalnie zatwierdzonych kroków z kompensacją jest uzasadnionym projektem; po prostu nie jest jedną atomową transakcją pod inną nazwą.
Zaprojektuj ponowienie przed pierwszą awarią
Klient może utracić odpowiedź po zatwierdzeniu operacji, więc wywołujący nie może traktować limitu czasu jako porażki. Zachowaj trwałą tożsamość żądania i przed ponowieniem zmiany użyj wyniku usługi albo mechanizmu idempotencji, inaczej ponowienie staje się drugim zapisem.
Automatyczne wywołania zwrotne transakcji mogą też wykonać się więcej niż raz po powtarzalnym przerwaniu, co czyni je złym miejscem dla nieodwracalnych efektów zewnętrznych. Trzymaj je poza wywołaniem zwrotnym, chyba że przepływ pracy definiuje dla nich wyraźny bezpieczny protokół. Ta sama ostrożność dotyczy wszystkiego, co kosztuje pieniądze albo wysyła wiadomość. Podwójne obciążenie to znacznie trudniejsza rozmowa niż podwójny wiersz logu.
Odbiór powinien odegrać cztery scenariusze: dwóch klientów ścigających się o ten sam wiersz, przerwanie, które usługa uznaje za powtarzalne, zatwierdzenie, którego odpowiedź nigdy nie nadchodzi, oraz utratę regionu albo łącza między nimi. Zapisz zatwierdzony wynik biznesowy i nierozwiązane stany obok projektu routingu, żeby nikt nie pomylił sieci z komponentem, który daje gwarancję.