Caso de descubrimiento de una condición de carrera en Aurora RDS
(hightouch.com)- Caso en el que se confirmó experimentalmente un bug de condición de carrera ocurrido en AWS Aurora RDS y AWS verificó oficialmente la causa
- Hightouch detectó, mientras escalaba su sistema de procesamiento de eventos, un fenómeno en el que fallaba el cambio de instancia de escritura durante el proceso de failover de Aurora
- El análisis de logs mostró que dos instancias realizaban operaciones de escritura al mismo tiempo, lo que provocó conflictos en la capa de almacenamiento y la finalización de procesos
- AWS confirmó oficialmente que la causa fue que, debido a un problema en el procesamiento de señales internas, el nuevo writer fue promovido antes de que terminara la degradación del writer anterior
- Este caso resalta la importancia del control de concurrencia en sistemas distribuidos a gran escala y la necesidad de un procedimiento de pausa de escrituras durante un failover
Contexto
- El 20 de octubre de 2025 ocurrió una interrupción en la región
us-east-1de AWS causada por un bug de condición de carrera en el sistema de gestión de DNS - Debido a esto, Hightouch vio un fuerte aumento en el backlog de procesamiento de eventos, hasta llegar al límite del sistema
- Para asegurar el rendimiento, el 23 de octubre realizó una actualización de instancias de Aurora RDS, y durante ese proceso descubrió un nuevo bug de condición de carrera
Estructura del sistema de eventos de Hightouch
- El sistema encargado de recopilar y enviar eventos está compuesto por Kubernetes, Kafka y Postgres(Aurora)
- Postgres se usa como una cola de metadatos por lotes y procesa 500 mil eventos por segundo en menos de 1 segundo
- Aurora PostgreSQL está compuesto por una instancia solo escritura (primary), una instancia solo lectura (replica) y una capa de almacenamiento compartida
Plan de actualización
- Agregar una instancia de lectura → actualizar el reader existente y asignarle prioridad de failover → ejecutar el failover → actualizar el writer existente → eliminar el reader temporal
- Este procedimiento está indicado en la documentación de AWS y había sido validado mediante pruebas de carga en un entorno de staging
Intento de actualización y aparición del problema
- El 23 de octubre a las 16:39 EDT, después de ejecutar el failover, ocurrió el fenómeno en el que el writer anterior volvía a quedar como primary
- En ambos intentos ocurrió el mismo resultado, y en algunos servicios aparecieron errores de imposibilidad de escritura: DatabaseError: cannot execute UPDATE in a read-only transaction
- El análisis de logs confirmó registros donde dos instancias realizaban escrituras al mismo tiempo y terminaban por un conflicto de almacenamiento
Causa de la condición de carrera
- Durante el proceso de failover de Aurora ocurrió una condición de carrera entre el paso 3 (degradación del writer anterior) y el paso 4 (promoción del nuevo writer)
- Como resultado, ambas instancias obtuvieron permiso de escritura al mismo tiempo y entraron en conflicto
- Al reintentar con el tráfico de escritura eliminado, el failover se completó con normalidad, lo que demostró la hipótesis de la condición de carrera
Confirmación y respuesta de AWS
- Tras una revisión interna, AWS confirmó que la causa fue un error en el procesamiento de la señal de degradación del writer, y que no estaba relacionado con la configuración de Hightouch ni con su patrón de tráfico
- La corrección está incluida en la hoja de ruta, y como medida temporal AWS recomendó detener las escrituras durante el failover
Medidas finales
- Hightouch completó la actualización del clúster y además:
- agregó un procedimiento para detener escrituras antes de un failover intencional
- reforzó el monitoreo de cambios en el rol de writer
- actualizó el manual operativo (playbook)
Principales lecciones
- Es necesario prepararse para la recuperación ante transiciones de estado inesperadas durante una migración
- Contar con observabilidad es clave para detectar el problema
- Es importante diseñar para minimizar el impacto entre componentes de un sistema distribuido
- Hay que reconocer las diferencias entre el entorno de pruebas y el entorno real de producción
No hay información adicional en el texto original
1 comentarios
Opiniones en Hacker News
Al leer esto, parece que durante un failover manual la aplicación siempre falla si intenta mantener el tráfico de escritura como si nada hubiera pasado.
Pero deja varias dudas. ¿Por qué otros usuarios de Aurora no se topan siempre con este problema?, ¿cómo podría AWS no saberlo?, y si sí lo sabe, ¿por qué no lo trata como un incidente crítico de nivel P0?
También da la impresión de que podrían influir condiciones sutiles, como el estado de las transacciones en curso o los timeouts
SELECT ... FOR UPDATEfallaba en silencio y la transacción pasaba a modo autocommit. A nadie le importó y me quedé hablando solo, pero unos meses después otra persona me contactó diciendo que había sufrido exactamente el mismo problema. Al final sí se corrigió, pero para entonces yo ya había perdido el interésEnlace relacionado: pregunta en Stack Overflow
En Aurora PostgreSQL he visto varias veces comportamientos inesperados.
En particular, durante Zero Downtime Patching (ZDP), el estado de la sesión se conservó mal y hasta consultas simples terminaban cancelándose mucho antes de
statement_timeout.Mi sospecha es que, cuando el cliente se reconecta, Aurora hereda el estado de temporizadores viejo de la sesión anterior y por eso la consulta se cancela casi de inmediato
Nosotros también hacemos failover de forma regular en un entorno con tráfico de escritura muy alto, pero lo operamos de manera estable con un proceso automatizado usando el AWS JDBC wrapper.
Uno paga esperando que Aurora mantenga este tipo de invariantes básicos, así que sorprende que ocurra algo así.
Por los logs y la explicación de AWS, parece que la hipótesis del autor original es incorrecta.
Todo indica que, tras fallar la promoción, un proceso externo de monitoreo detectó una inconsistencia en el estado del clúster y forzó un cierre con
kill -9. Los mensajes relacionados con el subsistema de almacenamiento aparecieron después de esoMe gustaría preguntar sobre la comparación de rendimiento entre Aurora y RDS Postgres.
Si no se necesita Multi-AZ ni failover rápido, ¿RDS con una configuración de gp3 64k IOPS podría dar mejor rendimiento? Aurora da la impresión de tener insert más lento y mayor costo. Además, cuesta confiar en los benchmarks porque muchos ni siquiera aclaran bien la configuración de RDS
Además, no hace falta aprovisionar IOPS manualmente y entrega alrededor de 80k IOPS.
También hay dos modelos de cobro de IO: pay-per-IO conviene para cargas ligeras, mientras que el modo de tarifa fija favorece workloads con mucho IO.
Como referencia, Serverless casi siempre fue antieconómico. Solo sirve cuando hay picos cortos de demanda
Aquí se ve muy bien el “modelo de bloques Lego” del que hablan los ingenieros de AWS.
Diseñaron la capa de almacenamiento de forma totalmente independiente, así que aunque falle el servicio de arriba, la consistencia de los datos se mantiene. Me parece un buen ejemplo de ingeniería de AWS
Dicen que AWS recomendó “detener las escrituras durante el failover”, así que me gustaría saber si podrían compartir el número de caso correspondiente.
Me da alivio saber que no fui el único que pasó por algo así.
Me parece interesante la arquitectura separada de cómputo y almacenamiento de Aurora.
Hyperscale de MSSQL tiene una estructura parecida, y es casi el único producto de Azure que personalmente considero realmente utilizable