Cloud

Quatre pannes AWS en quatre mois, treize incidents Cloudflare en huit jours : concevoir le mode dégradé quand l'actif-actif coûte trop cher

La série d'incidents AWS et Cloudflare de l'été 2026 relance le débat sur la résilience cloud. Plutôt que de répéter « faites du multi-région », cet article chiffre le coût réel de l'actif-actif et traite le mode dégradé comme une discipline d'ingénierie à part entière : stabilité statique, cartographie des dépendances de plan de contrôle, patterns de repli, observabilité indépendante et game day mesurable.

| | | 14 min read · by
Schéma d'architecture cloud avec une région en panne et un service continuant à répondre en lecture seule depuis un cache

Point de situation

Le 15 août 2026, AWS a signalé une dégradation sur us-west-2 attribuée à des équipements réseau assurant le routage du trafic vers la zone métropolitaine de Seattle. C’est le quatrième événement de fiabilité notable depuis mai 2026, après l’incident thermique de Virginie du Nord en mai et la perte de connectivité us-west-2/us-west-1 de juillet. Les détails définitifs relèvent des post-event summaries publiés par le fournisseur, et il faut les lire avant de tirer des conclusions architecturales : la cause racine change complètement les contre-mesures pertinentes.

En parallèle, la page de statut de Cloudflare a enregistré treize incidents distincts entre le 7 et le 14 août, touchant R2, Durable Objects, Workers KV, Workers AI et les performances réseau sur quatre continents. Aucun de ces événements n’est, seul, spectaculaire. Cumulés sur huit jours, ils dessinent un profil de risque différent de celui d’une panne unique et médiatique : une succession de fenêtres courtes où un sous-système managé devient lent ou partiellement indisponible, sans bascule franche à opérer.

Forrester avait anticipé fin décembre deux pannes cloud majeures pour 2026. La presse spécialisée parle de « nouvelle normalité ». Le terme est discutable, mais la conséquence opérationnelle ne l’est pas : la question n’est plus « est-ce que mon fournisseur va tomber », c’est « qu’est-ce que mon produit fait pendant ce temps-là ».

Panne de connectivité ou panne de plan de contrôle : ce n’est pas le même incident

Il est utile de comparer avec la panne us-east-1 d’octobre 2025. Sa cause racine était une race condition dans le système de gestion automatisée des enregistrements DNS des endpoints DynamoDB, qui a abouti à un enregistrement vide. La résolution DNS échouant, tout ce qui dépendait de DynamoDB dans la région a échoué — puis l’effet en cascade a atteint le lancement d’instances EC2 et les health checks de load balancers. C’était une panne de plan de contrôle, avec propagation vers le plan de données.

Les événements de l’été 2026 relèvent plutôt de la connectivité et de la dégradation de services managés spécifiques. La distinction est structurante :

  • Contre une panne de connectivité, la redondance réseau et la capacité pré-provisionnée dans une autre zone ou région ont une valeur directe.
  • Contre une panne de plan de contrôle, la redondance ne sert à rien si votre procédure de reprise consiste à appeler l’API du fournisseur pour créer des ressources, scaler un groupe d’auto-scaling, obtenir un token STS ou mettre à jour un enregistrement DNS. Vous avez alors besoin de la chose même qui est en panne.

Autrement dit : votre plan de reprise ne doit pas avoir de dépendance sur le composant dont il vous protège.

Pourquoi le multi-AZ ne suffit pas — et pourquoi le multi-région reste minoritaire

Le multi-AZ protège de la perte d’un datacenter. Il ne protège pas d’une panne régionale de plan de contrôle, d’une erreur de configuration propagée à toute la région, ni d’un service managé régional par construction. C’est une défense nécessaire, pas suffisante.

Le multi-région actif-actif règle le problème et reste minoritaire. La raison est économique, et il faut l’énoncer honnêtement plutôt que de la traiter comme un défaut de maturité.

Prenons un modèle illustratif — pas un benchmark, une arithmétique à refaire avec vos propres volumes et les tarifs publics en vigueur, qui varient selon les paires de régions :

  • Transfert inter-région : de l’ordre de 0,02 $/Go sur les paires de régions US courantes. Un flux de réplication de 20 To/mois représente environ 400 $/mois — modeste. Mais si vous répliquez aussi les événements applicatifs, les logs, les caches et le trafic de cohérence, le volume réel est souvent un multiple du volume de données « utiles ».
  • Duplication du stockage : 50 To en S3 Standard répliqués coûtent le prix du stockage une seconde fois, plus les requêtes de réplication. À environ 0,023 $/Go-mois, cela ajoute de l’ordre de 1 150 $/mois.
  • Capacité de calcul : un actif-actif honnête maintient dans chaque région la capacité d’absorber 100 % du trafic. Vous payez donc à peu près deux fois le compute pour un débit inchangé, sauf si vous acceptez de dégrader les performances pendant la bascule — ce qui est déjà une forme de mode dégradé.
  • Coût opérationnel : deux fois les déploiements à valider, la gestion de la cohérence des données, les conflits d’écriture, les runbooks, les tests de bascule. C’est le poste le plus sous-estimé, et le seul qui ne baisse pas avec l’échelle.

Conclusion pragmatique : l’actif-actif se justifie pour un petit nombre de parcours critiques. Pour tout le reste, la bonne question est « quel est le comportement acceptable pendant l’indisponibilité », et c’est un travail de conception, pas un aveu de faiblesse.

Stabilité statique : survivre sans appeler le cloud

Le principe de stabilité statique consiste à concevoir un système dont l’état stable ne dépend pas d’actions de plan de contrôle pendant l’incident. Concrètement :

  • La capacité est déjà provisionnée, pas à provisionner. Un groupe d’auto-scaling qui doit lancer des instances pendant une panne d’API EC2 ne le fera pas.
  • Les images de container sont déjà présentes sur les nœuds (imagePullPolicy: IfNotPresent, pré-chargement des images critiques), pas à tirer depuis un registre qui peut être régional.
  • Les secrets et la configuration sont montés et mis en cache localement avec un TTL généreux, pas relus à chaque requête depuis un secrets manager.
  • Les credentials ont une durée de vie compatible avec la durée typique d’un incident, et le code tolère l’échec temporaire d’un renouvellement STS au lieu de crasher.
  • Les enregistrements DNS de repli existent déjà, avec des TTL courts établis à l’avance — modifier une zone DNS pendant l’incident est le scénario le plus fragile qui soit.

Un système statiquement stable ne fait rien de spécial pendant la panne. C’est exactement l’objectif.

Cartographier les dépendances cachées

Avant de concevoir un mode dégradé, il faut savoir ce qui casse. Les dépendances qui font tomber les architectures sont rarement les bases de données ; ce sont les services transverses :

Dépendance Symptôme en panne Contre-mesure statique
IAM / STS échec de renouvellement de credentials, 403 en cascade credentials longue durée en cache, tolérance à l’échec de refresh
DNS (résolution ou zone) tout échoue « sans raison » résolveur de secours, cache DNS local, TTL préparés
Stockage objet (S3, R2) uploads bloqués, assets manquants file d’attente locale, assets critiques inlinés ou en CDN tiers
Registre d’images impossible de redéployer ou de remplacer un pod images pré-chargées, mirror régional
Secrets manager démarrage de process impossible secrets injectés au boot, cache disque chiffré
Fournisseur d’identité (SSO/OIDC) plus personne ne se connecte, y compris les astreintes sessions longues, compte de secours hors SSO
Endpoints de télémétrie perte de visibilité, et parfois blocage applicatif export asynchrone, buffer borné, jamais bloquant

Le dernier point mérite insistance : un exporteur de traces synchrone sans timeout transforme une panne d’observabilité en panne de production. Cela s’est vu.

Concevoir le mode dégradé, concrètement

Le mode dégradé n’est pas « le site affiche une page d’erreur plus jolie ». C’est un ensemble d’états de fonctionnement définis, testés et déclenchables.

Lecture seule. Le parcours de consultation continue de fonctionner ; les écritures sont refusées avec un message explicite. C’est le mode le plus simple et le plus rentable : sur la plupart des produits, 80 à 95 % du trafic est en lecture.

Réponses depuis le cache, y compris périmées. Servir une donnée vieille de dix minutes est presque toujours préférable à une 503. Le pattern stale-while-revalidate / stale-if-error doit être une politique explicite, avec un âge maximal par type de ressource.

File d’attente d’écritures avec réconciliation. Les écritures non critiques sont acceptées, persistées localement (disque local, queue régionale indépendante) et rejouées plus tard. Cela n’est acceptable que si les écritures sont idempotentes et si l’utilisateur est informé du différé.

Feature flags de dégradation. Chaque fonctionnalité coûteuse ou dépendante d’un tiers doit pouvoir être coupée sans déploiement — donc via un flag dont l’évaluation a une valeur par défaut locale, en dur dans le binaire. Un système de feature flags qui exige un appel réseau pour dire « désactive-toi » est inutile pendant une panne réseau.

Budgets d’erreur explicites. Ce sont eux qui rendent la décision non politique : si le budget d’erreur du trimestre est consommé, on arrête les changements et on investit dans la résilience. Sans cela, le mode dégradé reste un ticket au backlog.

Patterns de code

Trois règles suffisent à éliminer la majorité des cascades : borner le temps, arrêter d’insister, avoir une réponse de repli.

// Timeouts explicites à tous les niveaux : jamais de client HTTP par défaut.
var client = &http.Client{
    Timeout: 800 * time.Millisecond, // budget total, DNS + TCP + TLS + réponse
    Transport: &http.Transport{
        DialContext:           (&net.Dialer{Timeout: 200 * time.Millisecond}).DialContext,
        TLSHandshakeTimeout:   200 * time.Millisecond,
        ResponseHeaderTimeout: 400 * time.Millisecond,
        MaxIdleConnsPerHost:   64,
    },
}

// Le budget de la requête entrante est propagé, pas réinventé.
func handler(w http.ResponseWriter, r *http.Request) {
    ctx, cancel := context.WithTimeout(r.Context(), 1500*time.Millisecond)
    defer cancel()

    profile, err := fetchProfile(ctx, r)
    if err != nil {
        // Repli : cache local périmé, puis valeur minimale viable.
        if cached, ok := localCache.GetStale(r); ok {
            w.Header().Set("X-Data-Freshness", "stale")
            writeJSON(w, cached)
            return
        }
        writeJSON(w, minimalProfile(r)) // dégradé, pas en erreur
        return
    }
    writeJSON(w, profile)
}

Le circuit breaker complète le dispositif : après un seuil d’échecs, on cesse d’appeler la dépendance pendant une fenêtre de repos, ce qui protège à la fois l’appelant (latence) et l’appelé (qui n’est pas achevé par les retries).

// Retry borné, jitter obligatoire, uniquement sur erreurs transitoires
// et uniquement si l'opération est idempotente.
func withRetry(ctx context.Context, op func(context.Context) error) error {
    backoff := 50 * time.Millisecond
    for attempt := 0; attempt < 3; attempt++ {
        if err := op(ctx); err == nil {
            return nil
        } else if !isTransient(err) {
            return err
        }
        jitter := time.Duration(rand.Int63n(int64(backoff)))
        select {
        case <-time.After(backoff + jitter):
        case <-ctx.Done():
            return ctx.Err()
        }
        backoff *= 2
    }
    return errExhausted
}

Côté écritures rejouées, l’idempotence n’est pas optionnelle. Une clé fournie par le client, stockée avec contrainte d’unicité, suffit :

-- Le rejeu d'une écriture différée ne doit jamais créer de doublon.
INSERT INTO payments (idempotency_key, account_id, amount_cents, status)
VALUES ($1, $2, $3, 'pending')
ON CONFLICT (idempotency_key) DO NOTHING
RETURNING id;
-- Aucune ligne retournée => l'opération avait déjà été appliquée.

Edge et stockage objet : quand le cache devient le point unique de défaillance

La série Cloudflare d’août illustre un risque spécifique aux architectures edge : R2, Workers KV et Durable Objects ne sont pas de simples caches, ce sont souvent la source de vérité de la configuration, du routage ou des sessions. Quand KV répond lentement, ce n’est pas une couche de performance qui se dégrade, c’est le chemin critique.

Quelques garde-fous :

  • Valeurs par défaut compilées. Toute lecture de configuration depuis KV doit avoir un fallback en dur dans le bundle du Worker. Le déploiement devient alors le mécanisme de secours.
  • Cache en mémoire dans l’isolate. Un cache process-local avec TTL court absorbe une grande partie des à-coups de latence de la couche distribuée.
  • Dégradation choisie plutôt que timeout subi. Promise.race avec un timeout court et un repli déterministe vaut mieux qu’un appel qui traîne.
const DEFAULTS = { experiments: [], rateLimit: 100 }; // repli compilé

async function loadConfig(env) {
  const timeout = new Promise((resolve) =>
    setTimeout(() => resolve(null), 120) // 120 ms, pas plus
  );
  try {
    const raw = await Promise.race([env.CONFIG.get("live", "json"), timeout]);
    return raw ?? DEFAULTS;
  } catch {
    return DEFAULTS;
  }
}
  • Stockage objet : découpler l’upload de l’ingestion. Accepter le fichier dans une queue ou un stockage régional distinct, puis pousser vers R2/S3 en asynchrone. L’utilisateur voit un « traitement en cours », pas une erreur.
  • Ne jamais faire du cache une dépendance dure. Si un miss de cache provoque une tempête de requêtes qui écroule l’origine, votre cache est un point unique de défaillance déguisé. Coalescing des requêtes (single flight) et jitter des TTL sont les contre-mesures minimales.

Observabilité indépendante du fournisseur

Une supervision hébergée dans la région qu’elle surveille cesse de fonctionner exactement quand vous en avez besoin. Le minimum viable :

  • des probes synthétiques exécutées depuis l’extérieur de la région et, idéalement, depuis un autre fournisseur ;
  • une route d’alerting qui ne traverse pas l’infrastructure surveillée, y compris pour le SSO de l’outil d’astreinte ;
  • un endpoint de santé /health/deep qui expose l’état de chaque dépendance et le mode de fonctionnement courant (normal, read_only, cache_only), afin que la page de statut publique soit dérivée de faits et non d’hypothèses ;
  • des buffers de télémétrie bornés, non bloquants, avec dégradation en échantillonnage agressif plutôt qu’en blocage.

Un game day de 90 minutes

Un mode dégradé non testé est une hypothèse. Le format suivant est court et suffisant pour révéler l’essentiel :

  • 0–10 min — Annonce du périmètre, gel des déploiements, désignation d’un observateur qui ne touche à rien et prend des notes horodatées.
  • 10–25 min — Coupure réseau vers une région ou un service managé, en environnement de préproduction avec trafic synthétique réaliste. Sur AWS, une NACL bloquante ou un security group vide isole proprement ; ne comptez pas sur l’arrêt des instances, qui ne simule pas la panne de plan de contrôle.
  • 25–55 min — Observation sans intervention. Combien de temps avant détection ? Le circuit breaker s’ouvre-t-il ? Le mode dégradé s’active-t-il, et se voit-il dans les métriques ?
  • 55–75 min — Rétablissement, et surveillance du thundering herd au retour : les retries accumulés, les caches vides et les files d’attente à rejouer produisent souvent un second incident.
  • 75–90 min — Debrief à chaud, une liste d’actions avec propriétaires et dates.

Critères de réussite mesurables, décidés avant l’exercice :

  • détection automatique en moins de 2 minutes, sans intervention humaine ;
  • aucune alerte perdue, y compris si l’IdP est indisponible ;
  • le parcours critique en lecture reste disponible avec un taux de succès supérieur à 99 % pendant la panne ;
  • aucune perte ni duplication de données après réconciliation des écritures différées ;
  • retour au régime normal sans dépassement de latence au-delà de la fenêtre annoncée.

Si l’un de ces critères n’est pas mesurable avec les métriques existantes, c’est le premier chantier.

Grille de décision

Classe de service Stratégie Justification
Authentification, paiement, chemin de commande Actif-actif multi-région Une indisponibilité se traduit directement en perte de revenu et en perte de confiance ; le surcoût est absorbable
Consultation de catalogue, API de lecture, contenu Mono-région + cache et lecture seule Le mode dégradé couvre l’essentiel du trafic pour une fraction du coût
Écritures non transactionnelles (préférences, commentaires, télémétrie produit) File d’attente + réconciliation idempotente Le différé est invisible pour l’utilisateur s’il est annoncé
Batch, analytics, ETL, reporting Peut simplement tomber Rattrapage naturel ; investir ici est un mauvais arbitrage
Back-office interne, outils d’administration Mono-région, accès de secours documenté À l’exception du tooling d’astreinte, qui doit être hors du périmètre en panne

Ce que change réellement l’été 2026

La leçon des incidents d’août n’est pas qu’il faut du multi-région : c’est que la fréquence des dégradations partielles dépasse désormais la capacité des organisations à opérer une bascule manuelle à chaque fois. Un événement de trente minutes sur Workers KV ne laisse pas le temps d’un failover ; il laisse le temps qu’un fallback compilé s’exécute, ou pas.

Le vrai livrable n’est donc pas un diagramme d’architecture redondante, mais une liste : pour chaque parcours utilisateur, quel est le comportement attendu quand la dépendance X est indisponible, comment ce comportement est déclenché, et quand a-t-il été vérifié pour la dernière fois. Cette liste coûte quelques jours d’ingénierie et se maintient. L’actif-actif coûte un budget récurrent et une dette opérationnelle permanente. Les deux sont légitimes — mais commencer par le second sans avoir fait le premier revient à payer deux fois pour une résilience qu’on n’a jamais testée.

Comments (0)

Please log in to leave a comment.

Log In

No comments yet. Be the first to comment!