Découverte d’un cas de race condition dans Aurora RDS
(hightouch.com)- Cas où un bug de race condition survenu dans AWS Aurora RDS a été reproduit expérimentalement, et dont AWS a confirmé la cause
- En faisant évoluer son système de traitement d’événements, Hightouch a découvert, pendant le processus de failover (basculement) d’Aurora, un phénomène où le basculement de l’instance d’écriture échouait
- L’analyse des logs a montré que deux instances effectuaient des écritures simultanément, provoquant des conflits dans la couche de stockage et l’arrêt des processus
- AWS a officiellement confirmé que la cause était la promotion d’un nouveau writer alors que la rétrogradation de l’ancien writer n’était pas terminée, en raison d’un problème de traitement des signaux internes
- Ce cas souligne l’importance du contrôle de concurrence dans les systèmes distribués à grande échelle ainsi que la nécessité d’une procédure d’arrêt des écritures lors d’un basculement
Contexte
- Le 20 octobre 2025, une panne s’est produite dans la région AWS
us-east-1en raison d’un bug de race condition dans le système de gestion DNS - À cause de cela, Hightouch a vu son backlog de traitement d’événements fortement augmenter jusqu’à atteindre les limites du système
- Pour garantir le débit nécessaire, l’entreprise a procédé le 23 octobre à une mise à niveau des instances Aurora RDS, découvrant au passage un nouveau bug de race condition
Architecture du système d’événements de Hightouch
- Le système chargé de la collecte et de l’envoi des événements repose sur Kubernetes, Kafka et Postgres (Aurora)
- Postgres est utilisé comme file de métadonnées de batch, avec un traitement de 500 000 événements par seconde en moins d’une seconde
- Aurora PostgreSQL se compose d’une instance d’écriture uniquement (primary), d’instances en lecture seule (replica), ainsi que d’une couche de stockage partagée
Plan de mise à niveau
- Ajout d’une instance de lecture → mise à niveau du reader existant et attribution d’une priorité de failover → exécution du failover → mise à niveau du writer existant → suppression du reader temporaire
- Cette procédure correspond à celle décrite dans la documentation AWS et avait été validée en environnement de staging via des tests de charge
Tentative de mise à niveau et apparition du problème
- Le 23 octobre à 16:39 EDT, après l’exécution du failover, l’ancien writer est redevenu primary
- Lors des deux tentatives, le même résultat s’est produit, avec des erreurs d’écriture dans certains services :
DatabaseError: cannot execute UPDATE in a read-only transaction - L’analyse des logs a confirmé que deux instances effectuaient des écritures en même temps avant de s’arrêter à cause d’un conflit de stockage
Cause de la race condition
- Pendant le processus de failover d’Aurora, une race condition est survenue entre l’étape 3 (rétrogradation de l’ancien writer) et l’étape 4 (promotion du nouveau writer)
- Deux instances ont ainsi détenu simultanément les droits d’écriture, provoquant le conflit
- En réessayant après avoir supprimé le trafic d’écriture, le failover s’est déroulé normalement, ce qui a confirmé l’hypothèse de la race condition
Confirmation et réponse d’AWS
- Après examen interne, AWS a confirmé que la cause était une erreur dans le traitement du signal de rétrogradation du writer, sans lien avec la configuration de Hightouch ni avec son profil de trafic
- Le correctif est inscrit à la roadmap, et AWS recommande à titre provisoire d’interrompre les écritures pendant le failover
Mesures finales
- Hightouch a finalisé la mise à niveau du cluster et a mis en place :
- une procédure d’arrêt des écritures avant tout failover volontaire
- un renforcement de la supervision des changements de rôle du writer
- une mise à jour du manuel opérationnel (playbook)
Principaux enseignements
- Il faut préparer des mécanismes de reprise face aux transitions d’état inattendues pendant une migration
- La visibilité opérationnelle (observability) est essentielle pour détecter les problèmes
- Il est important de concevoir pour minimiser l’impact entre les composants d’un système distribué
- Il faut garder à l’esprit la différence entre environnement de test et environnement de production
Aucune information supplémentaire dans l’article original
1 commentaires
Avis Hacker News
À la lecture de ce billet, on a l'impression que pendant un failover manuel, si l'application continue à envoyer du trafic d'écriture comme d'habitude, cela échoue systématiquement
Mais cela soulève plusieurs questions. Pourquoi les autres utilisateurs d'Aurora ne rencontrent-ils pas toujours ce problème, comment AWS pourrait-il ne pas être au courant, et s'ils le savent, pourquoi cela n'est-il pas traité comme un incident critique de niveau P0 ?
Je me dis qu'il y a peut-être des conditions subtiles en jeu, comme l'état des transactions en cours ou les timeouts
SELECT ... FOR UPDATEéchouait silencieusement et la transaction passait en mode autocommit. Personne n'y prêtait attention, donc j'étais seul à en parler, puis quelques mois plus tard quelqu'un m'a contacté en disant avoir eu le même problème. Cela a fini par être corrigé, mais j'avais déjà cessé de m'y intéresserLien connexe : question Stack Overflow
J'ai vu plusieurs fois des comportements inattendus sur Aurora PostgreSQL
En particulier, pendant le Zero Downtime Patching (ZDP), l'état de session a été mal conservé, au point que même des requêtes simples étaient annulées bien plus vite que
statement_timeoutMon hypothèse est que lorsque le client se reconnecte, Aurora réutilise tel quel l'ancien état du timer de la session précédente, ce qui provoque l'annulation immédiate des requêtes
Nous effectuons nous aussi régulièrement des failovers dans un environnement avec un trafic d'écriture très élevé, mais nous opérons cela de manière fiable via un processus automatisé en utilisant l'AWS JDBC wrapper
On paie justement pour qu'Aurora maintienne ce genre d'invariants fondamentaux, donc voir ce type de problème est surprenant
D'après les logs et l'explication d'AWS, l'hypothèse de l'auteur du billet original semble erronée
Après l'échec de la promotion, un processus de supervision externe semble avoir détecté l'incohérence de l'état du cluster et l'avoir forcé à s'arrêter avec kill -9. Les messages liés au sous-système de stockage sont apparus après cela
J'aimerais avoir un retour sur la comparaison de performances entre Aurora et RDS Postgres.
Si l'on n'a pas besoin du multi-AZ ni d'un failover rapide, est-ce qu'une configuration gp3 64k IOPS sur RDS peut offrir de meilleures performances ? Aurora semble notamment lent sur les insertions et plus coûteux. Les benchmarks indiquent rarement clairement la configuration RDS, donc il est difficile de leur faire confiance
Il n'est pas non plus nécessaire de provisionner directement les IOPS, et le service fournit environ 80k IOPS.
Il existe aussi deux modes de facturation des IO : pay-per-IO pour les charges faibles, et un mode à tarif fixe plus intéressant pour les workloads très consommateurs d'IO.
À noter que le Serverless a presque toujours été peu économique. Il n'est utile que lorsqu'il y a de courts pics de charge
Cela illustre bien le « modèle en briques Lego » dont parlent les ingénieurs AWS
La couche de stockage a été conçue de manière totalement indépendante, si bien que même lorsque le service de niveau supérieur a échoué, la cohérence des données a été garantie. Je trouve que c'est un bon exemple d'ingénierie AWS
AWS aurait recommandé de « stopper les écritures pendant le failover », mais je me demande s'il serait possible de partager le numéro de dossier correspondant
Cela me rassure de savoir que je ne suis pas le seul à avoir rencontré ce problème
L'architecture séparant calcul et stockage d'Aurora est intéressante
Le Hyperscale de MSSQL repose sur une structure similaire, et c'est presque le seul produit Azure que je considère réellement utilisable