Le 1er mars, une zone de disponibilité de la région me-central-1 d'AWS, mec1-az2, a été frappée par ce qu'AWS a décrit comme des "objects that struck the data center, creating sparks and fire". Environ dix-huit heures plus tard, une deuxième zone, mec1-az3, a perdu son alimentation elle aussi. La troisième, mec1-az1, est restée debout tout du long. Avec deux zones sur trois dégradées, S3 et DynamoDB ont commencé à défaillir à l'échelle de la région, et le conseil d'AWS à ses clients, selon ses propres mots sur le Health Dashboard, était d'"enact their disaster recovery plans and recover from remote backups into alternate AWS Regions, ideally in Europe". L'indépendance des zones de disponibilité est conçue contre les défaillances d'alimentation, de refroidissement et de réseau. En mars, elle a rencontré une cause contre laquelle elle n'avait jamais été conçue, et la cause n'avait que faire de l'ingénierie.

Ceci est la Partie 2 de Nothing Fails Alone. La Partie 1 a examiné l'incident us-east-1 de mai et soutenu que la frontière de zone avait tenu, et c'est le cas : une panne de refroidissement dans une salle de données est restée à l'intérieur d'une seule zone, exactement comme prévu, et la panne qui a suivi a été construite par le client. Cet argument était correct, et il répondait à une question précise : l'isolation des AZ contient-elle les modes de défaillance contre lesquels elle est conçue ? L'événement de mars dans me-central-1 pose une question différente. Il s'est produit avant que la Partie 1 ne soit écrite, et à l'époque il était facile de le classer comme un cas particulier de guerre, une note de bas de page relevant d'un acte de guerre, sans leçon pour une architecture normale. C'est l'incident de mai qui a rendu la forme générale visible : la Partie 1 portait sur ce que la frontière de zone protège, et cette partie porte sur ce qu'elle ne peut pas, c'est-à-dire toute cause qui atteint plus d'une zone. Ces causes existent aussi en temps de paix. La guerre n'a fait que compresser la démonstration en deux jours.

Ce qui s'est réellement passé dans me-central-1

L'événement s'est ouvert sur l'AWS Health Dashboard à 04:51 PST le 1er mars comme une investigation sur des "issues with AWS services in the ME-CENTRAL-1 Region", vite resserrée à un "localized power issue" dans une seule zone de disponibilité, mec1-az2. Le journal du dashboard est d'une franchise inhabituelle, et à 09:41 PST il a expliqué pourquoi l'alimentation était coupée : "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." Le lendemain, AWS a nommé la cause, dans une mise à jour que The Register a couverte le jour même : des frappes de drones, dans le cadre du conflit au Moyen-Orient. "In the UAE, two of our facilities were directly struck", et les frappes "caused structural damage, disrupted power delivery to our infrastructure, and in some cases required fire suppression activities that resulted in additional water damage".

Tout au long du premier jour, l'incident ressemblait à un événement single-zone de manuel, et AWS l'a dit dans cette même mise à jour de 09:41 : "Customers who were running their applications redundantly across the AZs are not impacted by this event." Le multi-AZ était, à cette heure-là, la réponse correcte et suffisante, et une mise à jour de moins d'une heure plus tôt portait une réserve que vous avez déjà lue si vous avez lu la Partie 1 : en raison d'une demande accrue dans les zones non affectées, "customers may experience longer than usual provisioning times". La même phrase qu'AWS publierait pendant l'événement us-east-1 de mai, l'incident que la Partie 1 a couvert il y a deux semaines, même si, au calendrier, mars est venu en premier. Le basculement de masse vers les zones survivantes est une ruée (thundering herd) partout, dans chaque région, dans chaque incident.

Puis, à 22:46 PST, environ dix-huit heures après la première frappe : "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." Deux zones sur trois à terre, et la défaillance était sortie entièrement de la couche zone.

Dix-huit heures, ce n'est pas simultané, et c'est tout l'enjeu

Les deux zones ne sont pas tombées ensemble. Elles sont tombées à environ dix-huit heures d'écart, pour la même cause. Cette distinction est tout l'argument de ce billet, alors il vaut la peine d'être précis. L'indépendance des zones est une affirmation de probabilité : AWS place les zones sur des alimentations séparées, des refroidissements séparés, des zones inondables séparées et des chemins réseau séparés, pour que les défaillances internes d'une installation, un chiller en panne, un transformateur en panne, un switch fabric défectueux, restent à l'intérieur et ne coïncident pas avec les défaillances internes d'une autre. Selon les termes mêmes de cette affirmation, mars n'a rien changé. Aucune zone n'a fait tomber l'autre. Il n'y avait pas de transformateur partagé, pas de dépendance en cascade. L'ingénierie d'isolation a fonctionné de bout en bout.

Ce qui a échoué, c'est l'hypothèse sous les maths de probabilité : que les défaillances de zone sont des événements indépendants. Elles ne sont indépendantes que lorsque la cause naît à l'intérieur d'une installation. Une cause qui naît à l'extérieur des installations, une tempête, un effondrement du réseau électrique, un incendie de forêt, un conflit armé, est tirée une fois et appliquée à chaque zone à sa portée. Les zones partageaient une agglomération, un réseau électrique, un espace aérien et une guerre. Une défaillance corrélée ne veut pas dire que deux zones meurent au même instant ; elle veut dire qu'une seule cause atteint les deux selon son propre calendrier. L'écart de dix-huit heures est ce à quoi la corrélation ressemble réellement sur un dashboard : pas un crash synchronisé, mais la même main qui frappe deux fois.

C'est pourquoi le cadrage « cas particulier de guerre » ne tient pas. Les drones sont exotiques ; l'infrastructure métropolitaine partagée ne l'est pas. Chaque région multi-AZ concentre ses zones à quelques millisecondes les unes des autres, ce qui, en pratique, signifie le même blast radius à l'échelle d'une ville pour la météo, les services publics et la politique. L'événement de mars est l'extrémité extrême d'une famille de causes qui inclut tout événement assez grand pour être nommé d'après la ville où il s'est produit. Quand InfoQ a analysé l'incident plus tard ce mois-là sous le titre "War in Iran Damages Multiple AWS Data Centers, Challenging Multi-AZ Assumptions", la discussion communautaire qu'il résumait avait déjà dépassé les drones pour le cas général : les zones sont un groupe de bâtiments dans la même ville, et les hypothèses qui méritent d'être remises en cause portent sur tout ce qui peut atteindre une ville.

Quand la région elle-même est le domaine de défaillance

La mise à jour la plus instructive de tout le journal est arrivée à 02:53 PST le 2 mars, quand AWS a expliqué ce que deux zones perdues font à 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."

Lisez cette phrase comme un document d'architecture, parce que c'en est un. S3 et DynamoDB sont les services pour lesquels vous ne concevez pas de tolérance à la panne de zone, parce qu'AWS le fait pour vous, en répliquant entre zones pour que la perte d'une zone soit invisible. Cette conception a une tolérance déclarée : une zone. La deuxième zone l'a dépassée, et les services sur lesquels chaque architecture « résiliente » de la région s'appuyait, pour l'état, pour les sauvegardes, pour les données de coordination du basculement lui-même, ont commencé à refuser lectures et écritures à l'échelle de la région. Votre application multi-AZ n'a pas seulement perdu ses instances ; elle a perdu le substrat régional sur lequel elle comptait se rétablir. mec1-az1 était saine, et cela n'a rien changé, parce qu'une zone saine rattachée à un plan de contrôle régional dégradé est une pièce éclairée dans un bâtiment sans plomberie. C'est la partie à laquelle le multi-AZ ne peut pas répondre. Les services régionaux sont construits sur les trois mêmes zones que vous, et leur tolérance à une perte de zone corrélée est un nombre choisi par AWS, pas un nombre que vous avez choisi.

"Ideally in Europe"

À 06:22 PST le 2 mars, les recommandations d'AWS étaient arrivées à leur phrase la plus abrupte : "We recommend customers enact their disaster recovery plans and recover from remote backups into alternate AWS Regions, ideally in Europe."

Cette phrase mérite une lecture plus lente que celle qu'elle a eue en mars. D'abord, le fournisseur dont c'est la région dit aux clients de la quitter. C'est le plafond de la redondance intra-région, énoncé par le vendeur : il existe une classe d'événements pour laquelle la bonne quantité de me-central-1 dans votre plan de reprise est zéro, et vous découvrez dans quelle classe vous êtes en plein incident, depuis un dashboard. Ensuite, "ideally in Europe" fait un travail discret et soigné. L'alternative la plus proche, me-south-1 à Bahreïn, est à un saut de puce et serait le choix de DR réflexe sur des critères de latence, et une installation là-bas avait été affectée par une frappe voisine dans la même campagne. AWS disait aux clients, sans l'épeler, que la cause corrélée avait une géographie, et qu'une région de reprise utile est une région située hors de cette géographie, pas seulement hors de l'ARN de la région. La distance à votre région primaire n'est pas une case de conformité à cocher ; c'est un pari sur la distance que parcourent vos causes corrélées. Choisissez votre région de DR en demandant ce qui pourrait plausiblement frapper les deux, pas ce qui garde une jolie latence de réplication.

Troisièmement, le conseil ne marche que pour les clients qui pouvaient le suivre. "Recover from remote backups" présume que les sauvegardes distantes existent, créées avant le 1er mars, parce que le même journal de mises à jour montre le "data ingest and egress" de S3 défaillir à l'échelle de la région pendant l'événement. Copier vos données hors d'une région est une activité de temps de paix. Au moment où le fournisseur le conseille, la fenêtre pour commencer s'est refermée.

Plusieurs mois

La dernière mise à jour de l'événement, datée du 30 avril, tient en un paragraphe et clôt l'histoire sans la clore : la région "has suffered damage as a result of the conflict in the Middle East and is currently unable to reliably support customer applications", les clients devraient "migrate all accessible resources to other Regions and restore inaccessible resources from remote backups as soon as possible", les opérations de facturation sont suspendues, et la récupération "is expected to take several months".

Mettez cela en regard d'un document de DR standard. Un RTO s'écrit comme une durée, et presque tous les RTO que j'ai revus supposent en silence que la cible de reprise est l'endroit où vous êtes déjà : restaurer le snapshot, relancer la flotte, même région, quelques heures au pire. "Several months" ne met pas ce nombre sous tension, il supprime l'axe sur lequel il était écrit. Si la région ne revient pas ce trimestre, votre vrai temps de reprise est la durée que prend une reconstruction inter-région à froid, y compris les parties que personne n'a répétées : IAM et réseau recréés à partir d'un code que vous avez, espérons-le, données restaurées depuis des réplicas que vous avez, espérons-le, faits, DNS basculé, capacité trouvée dans une région de destination qui absorbe l'exode de tout le monde d'un coup. Pour les équipes dont la réplication inter-région coulait déjà, mars a été une mauvaise semaine. Pour les équipes dont le plan de DR reposait sur des snapshots intra-région, ce fut un projet de migration annoncé par l'artillerie.

Le lab : dans quelles zones physiques êtes-vous réellement ?

La Partie 1 a clos sa section lab en notant que les rapports d'incident d'AWS nomment les zones par ID, use1-az4, et que sans la correspondance ID-vers-nom vous ne pouvez pas dire si c'était votre us-east-1a. Mars est l'incident où cela cesse d'être un détail. Le dashboard disait mec1-az2, puis mec1-az3. Pour savoir si vos charges se trouvaient dans les zones frappées ou dans la survivante, vous deviez résoudre ces ID contre votre compte, en plein incident, parce qu'un nom de zone comme me-central-1a est un alias propre au compte : AWS attribue les lettres aux zones physiques indépendamment par compte, donc le me-central-1a de deux comptes est en général une zone physique différente. « Nous sommes répartis sur a, b et c » est une affirmation sur le nommage de votre compte, pas sur le placement physique.

Le lab de cette partie, 02-az-id-truth, est délibérément le plus petit de la série : un unique script read-only dont les seuls appels d'API sont DescribeAvailabilityZones et GetCallerIdentity, ce dernier juste pour étiqueter la sortie. Il imprime la correspondance nom-vers-ID pour le compte et la région courants. Voici la vraie sortie pour l'un de mes comptes :

$ 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
...

Dans ce compte, use1-az4, la zone du rapport d'incident de mai, est us-east-1c. Un ingénieur ici qui aurait lu "use1-az4" en mai et jeté un œil à un schéma étiqueté "us-east-1a" se serait détendu à propos de la mauvaise zone et inquiété pour une zone saine. Le script accepte aussi --compare <profile>, qui lit la correspondance d'un second compte dans la même région et imprime les deux côte à côte avec, pour chaque nom, un verdict indiquant s'ils se résolvent vers la même zone physique, puis compte les décalages ; le même nom se résolvant vers des ID différents selon les comptes est le cas normal, pas l'exception. Un runbook partagé qui dit "evacuate us-east-1a" fait des choses différentes dans des comptes différents. Les runbooks, les décisions de placement et les recherches lors d'incident appartiennent aux ID de zone. Il y a un flag --json pour alimenter la correspondance dans un outillage d'inventaire, et le code de sortie est 0 chaque fois que l'exécution se termine, réservant 2 aux exécutions qui ne peuvent pas avoir lieu du tout : pas de boto3, pas d'identifiants, pas de région, un profil inconnu, ou l'appel describe lui-même qui échoue.

Modes de défaillance et ce qu'il faut surveiller

Soyez honnête sur les limites d'abord : un client ne peut pas concevoir me-central-1 pour la sortir d'une guerre. Rien dans votre Terraform n'empêche la cause corrélée ; ce que vous contrôlez, c'est si elle vous trouve avec vos données déjà ailleurs. La liste de surveillance qui découle de mars est courte. Énumérez les causes qui atteignent toutes vos zones à la fois : l'agglomération partagée, le réseau électrique partagé, la météo partagée, la juridiction partagée, et traitez la réponse comme votre vraie probabilité de perte de région, qui est faible mais pas le zéro que les maths de zone supposaient discrètement. Conservez des sauvegardes inter-région pour tout ce que vous ne pouvez pas régénérer, dans une région choisie parce qu'elle est hors de la géographie corrélée, et testez la restauration, parce que la version de mars de ce test comportait des pompiers. Écrivez les RTO deux fois, une fois pour une reprise intra-région et une fois en supposant que la région a disparu pour un trimestre, et mettez le second nombre sous les yeux de qui porte le risque. Et tenez un inventaire de vos ID de zone physiques par compte, parce que quand le prochain rapport donnera un ID de zone, le moment d'apprendre votre correspondance n'est pas pendant l'événement. La frontière de zone est réelle, et la Partie 1 l'a montrée en train de tenir. Mars a montré la chose au-dessus d'elle : les zones peuvent être parfaitement isolées les unes des autres et pourtant ne pas être isolées du monde.

À lire ensuite

Pour du conseil en AWS, architecture cloud, revues de résilience et travail de plateforme, commencez par ercanermis.com.

Références