Due server applicativi in due regioni, un client che scrive attraverso una VPN e una domanda che nessuno ha scritto: quale componente decide che la scrittura è avvenuta? L’instradamento porta la richiesta a un processo. Un confine di transazione decide quando la modifica diventa durevole e visibile. Sono lavori diversi svolti da sistemi diversi, e lo spazio tra loro è dove vivono la maggior parte dei bug di scrittura multiregione.

Partite dalla regola di business, non dalla mappa

Partite da una frase sulla regola di business anziché sulla geografia: quali letture e scritture devono riuscire insieme e quali modifiche concorrenti devono essere impossibili mentre ciò accade. Per una prenotazione di magazzino significa che il controllo delle scorte e la prenotazione o hanno entrambi effetto o nessuno dei due, e nessun secondo ordine può consumare la stessa unità nel frattempo.

RequirementWhat satisfies itWhat does not
All-or-nothing applicationA transaction inside one owning systemA VPN path between regions
No double spendIsolation strong enough to exclude the conflictAtomicity alone
Survive a region lossReplication the database itself documentsTwo independent databases behind one client

È proprio quella riga centrale che i team saltano. L’atomicità senza un isolamento adeguato consente a due transazioni di confermarsi correttamente ciascuna e di produrre comunque uno stato che il business considera impossibile, e nessuna quantità di logica di nuovo tentativo lo ripara dopo.

Un confine autorevole batte due server regionali

I server applicativi regionali possono restare dove sono, purché inviino l’operazione a un servizio che la esegue entro un unico confine di transazione supportato. Il livello applicativo diventa un router di intento; il livello dati possiede la verità.

Mantenete quel confine breve e vicino ai dati che tocca. Una transazione tenuta aperta mentre una persona risponde a un prompt, o mentre una chiamata attraversa due regioni, passa il suo tempo a tenere blocchi e ad aumentare la probabilità che qualcos’altro scada dietro di essa. Quel guasto sembra un problema di database ed è in realtà un problema di progettazione travestito da tale. Spostare la decisione nel livello dati di solito lo elimina del tutto.

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;

Leggete quello schizzo come un confine, non come una raccomandazione sulle prestazioni. Il punto è che il controllo e l’inserimento condividono una conferma, così un ordine concorrente o vede le scorte consumate o non le vede affatto.

Ciò che un database replicato dà e ciò che non dà

Un database replicato può fornire un confine più ampio quando il suo stesso modello di transazione lo supporta. Spanner documenta transazioni atomiche di lettura e scrittura all’interno di un singolo database su più tabelle, con isolamento e comportamento di nuovo tentativo definiti. È una garanzia che si legge, si prova e su cui ci si appoggia deliberatamente.

È anche una garanzia che viene dal prodotto, non dalla rotta. Una VPN tra regioni cambia il modo in cui viaggiano i pacchetti e in cui si presentano i guasti. Non estende un confine di transazione nemmeno di una riga, per quanto sano sembri il tunnel. Confondere le due cose produce architetture in cui ogni componente supera il proprio controllo e i dati continuano a non concordare.

Due database non diventano un solo sistema

Due database gestiti in modo indipendente non acquisiscono un gestore di transazioni condiviso perché i client possono raggiungerli entrambi. Se il business ha davvero bisogno di un impegno atomico sulla coppia, il meccanismo di coordinamento, i partecipanti e il processo di recupero vanno tutti scelti e qualificati anziché dati per scontati.

Pensate al momento in cui un partecipante o un collegamento scompare dopo che il lavoro è stato preparato. Una conferma distribuita supportata può lasciare uno stato incerto che richiede una procedura di recupero e una decisione umana, e non arriva con la promessa che ogni regione resti scrivibile attraverso ogni partizione.

Se invece è accettabile un coordinamento asincrono, ditelo esplicitamente e annotate gli stati di business intermedi più le regole di riconciliazione. Una catena di passi confermati localmente con compensazione è una progettazione legittima; semplicemente non è una transazione atomica sotto un altro nome.

Progettate il nuovo tentativo prima del primo disservizio

Un client può perdere la risposta dopo che l’operazione è stata confermata, quindi il chiamante non può trattare un timeout come un guasto. Conservate un’identità di richiesta durevole e usate l’esito del servizio o un meccanismo di idempotenza prima di ritentare una mutazione, altrimenti il nuovo tentativo diventa una seconda scrittura.

Anche le callback automatiche delle transazioni possono essere eseguite più di una volta dopo un abort ritentabile, il che le rende un cattivo posto per effetti esterni irreversibili. Tenete quelli fuori dalla callback, a meno che il flusso di lavoro definisca per essi un protocollo sicuro esplicito. La stessa cautela vale per qualunque cosa costi denaro o invii un messaggio. Un addebito duplicato è una conversazione molto più difficile di una riga di log duplicata.

L’accettazione dovrebbe riprodurre quattro scenari: due client in gara per la stessa riga, un abort che il servizio dice ritentabile, una conferma la cui risposta non arriva mai e la perdita di una regione o del collegamento tra loro. Registrate il risultato di business confermato e gli stati irrisolti accanto alla progettazione dell’instradamento, così nessuno scambia la rete per il componente che fornisce la garanzia.

Articoli correlati