Arquitectura (IT)Arquitecto de Sistemas

¿Cómo diseñarías un patrón de orquestación de saga a prueba de fallos para un sistema de reservas distribuido que compense transacciones de larga duración a través de subdominios independientes mientras asegura la idempotencia durante escenarios de solicitudes duplicadas?

Supere entrevistas con el asistente de IA Hintsage

Respuesta a la pregunta.

Implementar un Orquestador de Saga centralizado utilizando Temporal o Netflix Conductor que mantenga un estado de flujo de trabajo duradero en PostgreSQL con comunicación gRPC a los servicios de dominio. El patrón requiere claves de idempotencia almacenadas en Redis Cluster con ventanas de TTL que coincidan con las restricciones comerciales, mientras que Apache Kafka sirve como la columna vertebral de eventos para auditorías y desencadenadores de compensación. Cada paso de la saga debe incluir transacciones compensatorias que ejecuten operaciones inversas utilizando el patrón de Máquina de Estado de Saga, con estados explícitos (PENDIENTE, EXITOSO, COMPENSANDO, COMPENSADO) rastreados en etcd o ZooKeeper para la coordinación del clúster.

┌─────────────────┐     ┌──────────────┐     ┌─────────────────┐
│   API Gateway   │────▶│   Temporal   │────▶│   Inventario    │
└─────────────────┘     │  Orquestador │     │   Servicio      │
                        └──────────────┘     └─────────────────┘
                               │                        │
                               ▼                        ▼
                        ┌──────────────┐          ┌─────────────────┐
                        │  PostgreSQL  │          │   PostgreSQL    │
                        │  Almacenamiento│          │   (Lógica de   │
                        │     de Estado │          │    Compensación)│
                        └──────────────┘          └─────────────────┘

Situación de la vida real

Una plataforma global de reservas de hoteles luchaba con fallas en cascada al coordinar reservas de habitaciones, procesamiento de pagos y actualizaciones de puntos de lealtad a través de tres distintos clústeres de Kubernetes en diferentes regiones. Su implementación heredada usaba Compromiso en Dos Fases (2PC) a través de APIs REST, lo que causaba bloqueos generalizados durante el tráfico pico cuando la puerta de enlace de pago experimentaba picos de latencia que excedían los 10 segundos.

El equipo evaluó la Saga Basada en Coreografía utilizando Amazon EventBridge, donde cada servicio publicaba eventos de dominio en un bus compartido. Este enfoque eliminó el único punto de falla y redujo los costos de infraestructura en un 40%. Sin embargo, introdujo graves desafíos de observabilidad, ya que determinar si una compleja reserva de múltiples habitaciones había tenido éxito requería consultar registros a través de diecisiete microservicios. Las dependencias implícitas hacían imposible imponer políticas de tiempo de espera consistentes, y la depuración de problemas de producción se convirtió en un ejercicio forense que abarcaba múltiples paneles de AWS CloudWatch.

Prototiparon una Saga Orquestada utilizando un coordinador personalizado de Node.js desplegado en AWS ECS. Esto centralizó la lógica del negocio y simplificó el monitoreo a través de un panel unificado de Grafana. Desafortunadamente, la implementación inicial solo almacenaba el estado del flujo de trabajo en la memoria, resultando en una pérdida catastrófica de datos cuando el coordinador se reiniciaba durante los despliegues. Treinta transacciones entraron en estados desconocidos, requiriendo reconciliación manual de bases de datos que tomó tres días y resultó en pérdidas significativas de ingresos debido a clientes cobrados en doble.

La solución elegida desplegó Temporal como el motor de flujo de trabajo con persistencia en Cassandra, asegurando durabilidad del estado a través de reinicios de pods y fallas en zonas de disponibilidad. La arquitectura utilizó esquemas Protobuf para la comunicación tipo-segura entre el orquestador y los servicios de dominio, con Redis Sentinel gestionando las claves de idempotencia. Cuando el servicio de pago experimentó una falla regional en us-east-1, la saga activó automáticamente flujos de trabajo de compensación que liberaron retenciones de habitaciones en 200ms y revocaron puntos de lealtad de manera atómica.

El sistema ahora procesa 50,000 reservas complejas diarias con garantías de consistencia del 99.99% y sin intervenciones manuales durante particiones de red. El tiempo medio de detección (MTTD) de fallas se redujo de 45 minutos a 8 segundos, mientras la latencia de compensación se mantiene por debajo de 500ms en p99.

Lo que a menudo los candidatos pasan por alto

¿Cómo manejas el fallo en la compensación parcial cuando una transacción compensatoria falla, lo que podría dejar el sistema en un estado inconsistente?

Implementar un Registro de Auditoría de Compensación utilizando Event Sourcing donde cada intento de compensación se registra como un evento inmutable en Apache Kafka con retención infinita. El sistema debe distinguir entre fallas transitorias de infraestructura que requieren un reintento automático con retroceso exponencial y violaciones de lógica de negocio que requieren intervención humana. Para problemas transitorios, usar Colas de Mensajes Muertas (DLQ) en RabbitMQ o Amazon SQS que reprocesen las compensaciones después de la recuperación del servicio con jitter para evitar reacciones en cadena. Para violaciones de reglas comerciales, como intentar reembolsar una transacción ya liquidada, la saga entra en un estado de 'COMPENSACIÓN_FALLIDA' que activa alertas de PagerDuty mientras se aplica el patrón CQRS para congelar la raíz agregada a través del modelo de comando. Siempre diseñar las compensaciones para ser idempotentes utilizando restricciones únicas en la base de datos o operaciones SETNX de Redis, asegurando que los reintentos no creen efectos secundarios.

¿Cuál es la diferencia arquitectónica fundamental entre coreografía y orquestación en relación con el acoplamiento temporal y la capacidad de responder a consultas del estado de la transacción actual?

La Coreografía sigue el Manifiesto Reactivo, creando desacoplamiento temporal donde los servicios reaccionan a eventos sin conocimiento de los participantes ascendentes o descendentes, pero sacrificando la posibilidad de consultar el estado de la saga sin construir un Rastreo Distribuido complejo con Jaeger o AWS X-Ray. El estado se convierte en emergente de los registros de eventos, requiriendo proyecciones de modelos de lectura CQRS para responder preguntas de '¿se completó la reserva?'. La Orquestación introduce un acoplamiento temporal explícito entre el coordinador y los trabajadores, ya que el orquestador debe estar disponible para activar los siguientes pasos, pero proporciona una única fuente de verdad en su almacén de estado (PostgreSQL/CockroachDB). Esto permite consultas de estado inmediatas pero crea una dependencia de red. La idea crítica es que la coreografía requiere implementar máquinas de estados en cada consumidor, mientras que la orquestación centraliza esta complejidad; para sistemas que requieren una fuerte auditabilidad y cumplimiento (PCI-DSS), la orquestación es preferible a pesar del costo de acoplamiento.

¿Cómo previenes la ejecución duplicada de saga cuando usas semánticas de entrega al menos una vez en corredores de mensajes durante el reequilibrio de consumidores de Kafka o reinicios de pods de Kubernetes?

Implementar patrones de Consumidor Idempotente utilizando Redis o Memcached para almacenar IDs de mensajes procesados con ventanas de deduplicación que coinciden con su Objetivo de Punto de Recuperación (RPO), típicamente 24-48 horas para sistemas financieros. Cuando un orquestador de saga recibe un comando, genera una clave de idempotencia determinista al hash de la ID de correlación con una clave comercial (ID de cliente + referencia de reserva) antes de realizar cualquier efecto secundario. Cada servicio de dominio debe validar esta clave contra su Almacenamiento de Idempotencia, implementado como una tabla PostgreSQL con restricciones únicas en claves compuestas o Bloom Filters en Redis para búsquedas negativas eficientes en memoria. Para sagas de larga duración, utilizar Máquinas de Estado de Saga con bloqueo optimista a través de vectores de versión de etcd para manejar semánticas de procesamiento exactamente una vez a través de nodos distribuidos. Esto previene escenarios de doble reserva cuando los grupos de consumidores se reequilibran durante los despliegues o durante particiones de red que disparan reinicios de livenessProbe de Kubernetes.