Il 1° marzo, una availability zone della regione me-central-1 di AWS, mec1-az2, è stata colpita da quelli che AWS ha descritto come "objects that struck the data center, creating sparks and fire". Circa diciotto ore dopo, una seconda zona, mec1-az3, ha perso anch'essa l'alimentazione. La terza, mec1-az1, è rimasta in piedi per tutto il tempo. Con due zone su tre compromesse, S3 e DynamoDB hanno iniziato a fallire a livello regionale, e il consiglio di AWS ai clienti, con parole sue sulla Health Dashboard, era di "enact their disaster recovery plans and recover from remote backups into alternate AWS Regions, ideally in Europe". L'indipendenza delle availability zone è progettata contro guasti di alimentazione, guasti di raffreddamento e guasti di rete. A marzo ha incontrato una causa contro cui non era mai stata progettata, e la causa non si è curata dell'ingegneria.

Questa è la Parte 2 di Nothing Fails Alone. La Parte 1 ha esaminato l'incidente di us-east-1 di maggio e ha sostenuto che il confine di zona ha retto, e così è stato: un guasto al raffreddamento in una sala dati è rimasto dentro una zona, esattamente come previsto, e l'interruzione che ne è seguita è stata costruita dal cliente. Quell'argomento era corretto, e rispondeva a una domanda specifica: l'isolamento AZ contiene le modalità di guasto contro cui è progettato? L'evento di marzo in me-central-1 pone una domanda diversa. È accaduto prima che la Parte 1 fosse scritta, e all'epoca era facile archiviarlo come caso speciale di guerra, una nota a piè di pagina da atto bellico senza lezioni per l'architettura normale. L'incidente di maggio è ciò che ha reso visibile la forma generale: la Parte 1 riguardava ciò che il confine di zona protegge, e questa parte riguarda ciò che non può proteggere, ovvero qualsiasi causa che raggiunge più di una zona. Quelle cause esistono anche in tempo di pace. La guerra ha solo compresso la dimostrazione in due giorni.

Cosa è successo davvero in me-central-1

L'evento si è aperto sull'AWS Health Dashboard alle 04:51 PST del 1° marzo come indagine su "issues with AWS services in the ME-CENTRAL-1 Region", rapidamente ristretta a un "localized power issue" in una singola availability zone, mec1-az2. Il log della dashboard è insolitamente franco, e alle 09:41 PST ha spiegato perché mancava l'alimentazione: "At around 4:30 AM PST, one of our Availability Zones (mec1-az2) was impacted by objects that struck the data center, creating sparks and fire. The fire department shut off power to the facility and generators as they worked to put out the fire." Il giorno dopo AWS ha nominato la causa, in un aggiornamento che The Register ha coperto lo stesso giorno: attacchi con droni, parte del conflitto in Medio Oriente. "In the UAE, two of our facilities were directly struck", e gli attacchi hanno "caused structural damage, disrupted power delivery to our infrastructure, and in some cases required fire suppression activities that resulted in additional water damage".

Per tutto il primo giorno, l'incidente è sembrato un evento single-zone da manuale, e AWS lo ha detto nello stesso aggiornamento delle 09:41: "Customers who were running their applications redundantly across the AZs are not impacted by this event." Il multi-AZ era, a quell'ora, la risposta corretta e sufficiente, e un aggiornamento di meno di un'ora prima portava un caveat che hai già letto se hai letto la Parte 1: a causa dell'aumento di domanda nelle zone non colpite, "customers may experience longer than usual provisioning times". La stessa frase che AWS avrebbe pubblicato durante l'evento di us-east-1 di maggio, l'incidente che la Parte 1 ha coperto due settimane fa, anche se sul calendario marzo è venuto prima. Il failover di massa verso le zone superstiti è un thundering herd ovunque, in ogni regione, in ogni incidente.

Poi, alle 22:46 PST, circa diciotto ore dopo il primo attacco: "a localized power issue has affected another Availability Zone in the ME-CENTRAL-1 Region (mec1-az3) ... At this point it is not possible to launch new instances in the region ... Other AWS Services, such as DynamoDB and S3 are also experiencing significant error rates and latencies." Due zone su tre giù, e il guasto era uscito del tutto dal layer di zona.

Diciotto ore non è simultaneo, ed è questo il punto

Le due zone non sono cadute insieme. Sono cadute a circa diciotto ore di distanza, per la stessa causa. Quella distinzione è l'intero argomento di questo post, quindi vale la pena essere precisi. L'indipendenza di zona è un'affermazione di probabilità: AWS costruisce le zone su alimentazione separata, raffreddamento separato, aree alluvionali separate e percorsi di rete separati, in modo che i guasti interni di una struttura, un chiller guasto, un trasformatore guasto, uno switch fabric difettoso, restino dentro di essa e non coincidano con i guasti interni di un'altra. Nei termini di quell'affermazione, marzo non ha cambiato nulla. Nessuna zona ha messo giù l'altra. Non c'era alcun trasformatore condiviso, nessuna dipendenza a cascata. L'ingegneria dell'isolamento ha funzionato dall'inizio alla fine.

Ciò che è fallito è stata l'assunzione sotto la matematica della probabilità: che i guasti di zona siano eventi indipendenti. Lo sono solo quando la causa ha origine dentro una struttura. Una causa che ha origine fuori dalle strutture, una tempesta, un collasso della rete elettrica, un incendio boschivo, un conflitto armato, viene campionata una volta e applicata a ogni zona nel suo raggio. Le zone condividevano un'area metropolitana, una rete elettrica, uno spazio aereo e una guerra. Un guasto correlato non significa che due zone muoiono nello stesso istante; significa che una causa le raggiunge entrambe secondo il proprio calendario. Il divario di diciotto ore è come appare davvero la correlazione su una dashboard: non un crash sincronizzato, ma la stessa mano che bussa due volte.

È per questo che l'inquadramento del caso speciale di guerra fallisce. I droni sono esotici; l'infrastruttura metropolitana condivisa non lo è. Ogni regione multi-AZ concentra le sue zone entro pochi millisecondi a cifra singola l'una dall'altra, il che in pratica significa lo stesso blast radius su scala cittadina per meteo, utility e politica. L'evento di marzo è l'estremo di una famiglia di cause che include ogni evento abbastanza grande da prendere il nome dalla città in cui è accaduto. Quando più tardi quel mese InfoQ ha analizzato l'incidente sotto il titolo "War in Iran Damages Multiple AWS Data Centers, Challenging Multi-AZ Assumptions", la discussione della community che riassumeva era già andata oltre i droni fino al caso generale: le zone sono un gruppo di edifici nella stessa città, e le assunzioni che vale la pena mettere in discussione riguardano tutto ciò che può raggiungere una città.

Quando la regione stessa è il dominio di guasto

L'aggiornamento più istruttivo di tutto il log è arrivato alle 02:53 PST del 2 marzo, quando AWS ha spiegato cosa fanno due zone perse a S3: "Amazon S3 is a regional service and designed to withstand the total loss of a single Availability Zone ... As the second AZ became impaired, S3 error rates increased. With two Availability Zones significantly impacted, customers are seeing high failure rates for data ingest and egress."

Leggi quella frase come un documento di architettura, perché lo è. S3 e DynamoDB sono i servizi per cui non progetti contro il guasto di zona, perché lo fa AWS per te, replicando tra le zone in modo che la perdita di una zona sia invisibile. Quel design ha una tolleranza dichiarata: una zona. La seconda zona l'ha superata, e i servizi su cui ogni architettura "resiliente" della regione faceva affidamento, per lo stato, per i backup, per i dati di coordinamento del failover stesso, hanno iniziato a rifiutare letture e scritture a livello regionale. La tua applicazione multi-AZ non ha solo perso le sue istanze; ha perso il substrato regionale su cui pianificava di ripristinarsi. mec1-az1 era in salute, e non ha avuto importanza, perché una zona in salute attaccata a un control plane regionale compromesso è una stanza con le luci accese in un edificio senza impianto idraulico. Questa è la parte a cui il multi-AZ non può rispondere. I servizi regionali sono costruiti sulle stesse tre zone su cui sei costruito tu, e la loro tolleranza alla perdita correlata di zone è un numero che ha scelto AWS, non un numero che hai scelto tu.

"Ideally in Europe"

Alle 06:22 PST del 2 marzo, la guida di AWS era arrivata alla sua frase più brutale: "We recommend customers enact their disaster recovery plans and recover from remote backups into alternate AWS Regions, ideally in Europe."

Quella frase merita una lettura più lenta di quella che ha ricevuto a marzo. Primo, il provider di cui la regione è proprietà ha detto ai clienti di abbandonarla. È il soffitto della ridondanza in-region, dichiarato dal fornitore: esiste una classe di eventi per cui la quantità corretta di me-central-1 nel tuo piano di ripristino è zero, e scopri in quale classe ti trovi a incidente in corso, da una dashboard. Secondo, "ideally in Europe" sta svolgendo un lavoro silenzioso e attento. L'alternativa più vicina, me-south-1 in Bahrain, è a un salto di distanza e sarebbe la scelta riflessa di DR per motivi di latenza, e una struttura lì era stata colpita da un attacco vicino nella stessa campagna. AWS stava dicendo ai clienti, senza esplicitarlo, che la causa correlata aveva una geografia, e che una regione di ripristino utile è una fuori da quella geografia, non semplicemente fuori dall'ARN della regione. La distanza dal tuo primario non è una casella di compliance da spuntare; è una scommessa su quanto lontano viaggiano le tue cause correlate. Scegli la tua regione di DR chiedendoti cosa potrebbe plausibilmente colpire entrambe, non cosa mantiene bella la latenza di replica.

Terzo, il consiglio funziona solo per i clienti che potevano seguirlo. "Recover from remote backups" presuppone che i backup remoti esistano, creati prima del 1° marzo, perché lo stesso log di aggiornamento mostra S3 con "data ingest and egress" in fallimento a livello regionale durante l'evento. Copiare i tuoi dati fuori da una regione è un'attività di tempo di pace. Nel momento in cui il provider la sta consigliando, la finestra per iniziare si è chiusa.

Diversi mesi

L'ultimo aggiornamento dell'evento, datato 30 aprile, è lungo un paragrafo e chiude la storia senza chiuderla: la regione "has suffered damage as a result of the conflict in the Middle East and is currently unable to reliably support customer applications", i clienti dovrebbero "migrate all accessible resources to other Regions and restore inaccessible resources from remote backups as soon as possible", le operazioni di fatturazione sono sospese, e il ripristino "is expected to take several months".

Metti tutto ciò a confronto con un documento di DR standard. Un RTO si scrive come una durata, e quasi ogni RTO che ho revisionato presume in silenzio che il target di ripristino sia il posto in cui sei già: ripristina lo snapshot, rilancia la flotta, stessa regione, ore al massimo. "Several months" non mette sotto stress quel numero, cancella l'asse su cui è stato scritto. Se la regione non torna questo trimestre, il tuo tempo di ripristino effettivo è il tempo che serve a una ricostruzione cross-region a freddo, incluse le parti che nessuno ha provato: IAM e networking ricreati da codice che si spera tu abbia, dati ripristinati da repliche che si spera tu abbia fatto, DNS spostato, capacità trovata in una regione di destinazione che assorbe l'esodo di tutti gli altri in una volta sola. Per i team con la replica cross-region già in corso, marzo è stato una brutta settimana. Per i team il cui piano di DR erano snapshot in-region, è stato un progetto di migrazione annunciato dall'artiglieria.

Il lab: in quali zone fisiche ti trovi davvero?

La Parte 1 chiudeva la sua sezione lab notando che gli incident report di AWS nominano le zone per ID, use1-az4, e che senza la mappatura ID-verso-nome non puoi sapere se quella fosse la tua us-east-1a. Marzo è l'incidente in cui questo smette di essere un dettaglio. La dashboard diceva mec1-az2, poi mec1-az3. Per sapere se i tuoi workload stavano nelle zone colpite o in quella superstite, dovevi risolvere quegli ID rispetto al tuo account, a incidente in corso, perché un nome di zona come me-central-1a è un alias con scope di account: AWS assegna le lettere alle zone fisiche in modo indipendente per ogni account, quindi le me-central-1a di due account sono di solito zone fisiche diverse. "Siamo distribuiti su a, b e c" è un'affermazione sulla denominazione del tuo account, non sulla collocazione fisica.

Il lab per questa parte, 02-az-id-truth, è deliberatamente il più piccolo della serie: un singolo script read-only le cui uniche chiamate API sono DescribeAvailabilityZones e GetCallerIdentity, quest'ultima solo per etichettare l'output. Stampa la mappatura nome-verso-ID per l'account e la regione correnti. Questo è l'output reale per uno dei miei account:

$ python3 az_ids.py --region us-east-1
Region: us-east-1

ZONE NAME  | ZONE ID  | STATE
---------------------------------
us-east-1a | use1-az1 | available
us-east-1b | use1-az2 | available
us-east-1c | use1-az4 | available
us-east-1d | use1-az6 | available
us-east-1e | use1-az3 | available
us-east-1f | use1-az5 | available
...

In questo account, use1-az4, la zona nell'incident report di maggio, è us-east-1c. Un ingegnere qui che a maggio avesse letto "use1-az4" e dato un'occhiata a un diagramma etichettato "us-east-1a" si sarebbe rilassato sulla zona sbagliata e preoccupato per una in salute. Lo script accetta anche --compare <profile>, che legge la mappatura di un secondo account nella stessa regione e stampa le due affiancate con un verdetto per ogni nome sul fatto che risolvano alla stessa zona fisica, poi conta i disallineamenti; lo stesso nome che risolve a ID diversi tra account è il caso normale, non l'eccezione. Un runbook condiviso che dice "evacua us-east-1a" fa cose diverse in account diversi. Runbook, decisioni di collocazione e lookup durante gli incidenti appartengono agli ID di zona. C'è un flag --json per dare in pasto la mappatura al tooling di inventario, e l'exit code è 0 ogni volta che l'esecuzione si completa, riservando il 2 alle esecuzioni che non possono avvenire affatto: nessun boto3, nessuna credenziale, nessuna regione, un profilo sconosciuto, o la chiamata describe stessa che fallisce.

Modalità di guasto e cosa tenere d'occhio

Sii onesto prima sui limiti: un cliente non può architettare me-central-1 fuori da una guerra. Nulla nel tuo Terraform previene la causa correlata; ciò che controlli è se ti trova con i tuoi dati già altrove. La watchlist che segue da marzo è breve. Enumera le cause che raggiungono tutte le tue zone in una volta: la metropoli condivisa, la rete elettrica condivisa, il meteo condiviso, la giurisdizione condivisa, e tratta la risposta come la tua reale probabilità di perdita di regione, che è bassa ma non lo zero che la matematica delle zone assumeva in silenzio. Conserva backup cross-region per tutto ciò che non puoi rigenerare, in una regione scelta per essere fuori dalla geografia correlata, e testa il restore, perché la versione di marzo di quel test aveva dentro un corpo dei vigili del fuoco. Scrivi gli RTO due volte, una per il ripristino in-region e una assumendo che la regione sia sparita per un trimestre, e metti il secondo numero davanti a chiunque possieda il rischio. E tieni un inventario dei tuoi ID fisici di zona per account, perché quando il prossimo report nomina un ID di zona, il momento di imparare la tua mappatura non è durante l'evento. Il confine di zona è reale, e la Parte 1 lo ha mostrato reggere. Marzo ha mostrato la cosa sopra di esso: le zone possono essere perfettamente isolate l'una dall'altra e comunque non essere isolate dal mondo.

Leggi questo dopo

Per consulenza su AWS, architettura cloud, resilience review e lavoro di piattaforma, parti da ercanermis.com.

Riferimenti