Resultados experimento 2 - galoryzen/equipo8-pfinal GitHub Wiki
Resultado del Experimento 2
Título del experimento
Validación de latencia en creación de reserva con comunicación síncrona Booking → Catalog bajo carga concurrente
Tabla de Contenidos
- Resultado del Experimento 2
1. Objetivo del experimento
Validar que la táctica de comunicación síncrona HTTP entre Booking Service y Catalog Service, con control de concurrencia pesimista (SELECT FOR UPDATE) en PostgreSQL, cumple el SLA de latencia p95 < 1.5s para la creación de reserva bajo carga pico.
2. Hipótesis
Las tácticas y patrones arquitectónicos seleccionados para el flujo de reserva comunicación síncrona HTTP (estilo Llamado-Retorno) entre Booking y Catalog, control de concurrencia pesimista (SELECT FOR UPDATE) en PostgreSQL, limitación de tiempo de ejecución (timeout 500ms), e introducción de concurrencia (FastAPI async + connection pooling) son suficientes para mantener la latencia p95 por debajo de 1.5 segundos bajo carga pico.
El punto de sensibilidad identificado es la contención de locks a nivel de fila en inventory_calendar: bajo alta concurrencia, múltiples transacciones compiten por lockear las mismas filas, lo que podría degradar la latencia de forma no lineal. El experimento busca determinar si las tácticas elegidas mitigan este riesgo dentro de los escenarios de carga esperados.
3. Metodología
3.1 Infraestructura
El experimento se ejecutó sobre la infraestructura desplegada en AWS:
| Componente | Configuración |
|---|---|
| Booking Service | ECS Fargate |
| Catalog Service | ECS Fargate |
| PostgreSQL | Amazon RDS (t3g.small) |
| Load Balancer | AWS ALB |
| Service Discovery | Cloud Map DNS (VPC interna) |
3.2 Generador de carga
Se utilizó Locust ejecutado desde una máquina local contra el ALB público. Cada usuario simulado:
- Envía un
POST /api/bookings/checkout-startcon datos del catálogo seeded - Espera un think time aleatorio de 1-3 segundos (simula comportamiento real)
- Repite durante toda la duración del escenario
3.3 Estrategia de contención
Para maximizar la contención de locks y poner a prueba el punto de sensibilidad:
- Distribución HOT/COLD: 3 room_types (de 20 totales) reciben el 80% del tráfico. Esto concentra los
SELECT FOR UPDATEen pocas filas deinventory_calendar. - Overlap de fechas: un pool de 4 fechas de check-in con estancias de 2 noches genera solapamiento en las filas lockeadas (ej: check-in 03-01 lockea filas 03-01 y 03-02; check-in 03-02 lockea filas 03-02 y 03-03 la fila 03-02 es compartida).
- Inventario suficiente: 10,000 unidades por room_type/día para evitar agotamiento de inventario durante la prueba y medir contención pura de locks.
3.4 Escenarios de carga
| Escenario | Usuarios concurrentes | Spawn rate | Duración |
|---|---|---|---|
| Normal | 10 | 2/s | 3 min |
| Moderado | 25 | 5/s | 3 min |
| Pico | 50 | 10/s | 3 min |
| Alta contención | 100 | 20/s | 3 min |
Entre cada escenario se realizó un reset completo de la base de datos (drop schemas + init + seed) para garantizar condiciones iniciales idénticas.
3.5 Clasificación de respuestas
| Código | Significado | Clasificación |
|---|---|---|
| 201 | Reserva creada exitosamente | Éxito |
| 409 | Sin inventario disponible | Fallo funcional (esperado) |
| 504 | Timeout de Booking → Catalog (> 500ms) | Fallo de latencia |
| 502 | Error interno de Catalog | Fallo de infraestructura |
4. Resultados
4.1 Tabla resumen
| Escenario | Requests | Fallos | Tasa de error | RPS | p50 | p95 | p99 | p99.9 | Max |
|---|---|---|---|---|---|---|---|---|---|
| 10 usuarios | 856 | 0 | 0.00% | 4.78 | 91ms | 110ms | 200ms | 380ms | 384ms |
| 25 usuarios | 2,114 | 0 | 0.00% | 11.79 | 92ms | 120ms | 240ms | 380ms | 382ms |
| 50 usuarios | 4,253 | 0 | 0.00% | 23.71 | 93ms | 130ms | 320ms | 540ms | 646ms |
| 100 usuarios | 8,420 | 121 | 1.44% | 46.92 | 94ms | 260ms | 730ms | 1,100ms | 1,394ms |
4.2 Desglose de errores (escenario 100 usuarios)
| Tipo de error | Cantidad | Porcentaje |
|---|---|---|
| 504 Timeout (Catalog > 500ms) | 121 | 1.44% |
| 409 No inventory | 0 | 0% |
| 502 Error de Catalog | 0 | 0% |
4.3 Evaluación de las tácticas
Las tácticas arquitectónicas seleccionadas permiten cumplir el SLA p95 < 1.5s en todos los escenarios.
| Escenario | p95 | Cumple SLA | Margen |
|---|---|---|---|
| 10 usuarios | 110ms | SI | 13.6x |
| 25 usuarios | 120ms | SI | 12.5x |
| 50 usuarios | 130ms | SI | 11.5x |
| 100 usuarios | 260ms | SI | 5.8x |
Incluso en el escenario más agresivo (100 usuarios concurrentes, ~47 RPS), el p95 de 260ms está 5.8 veces por debajo del límite de 1.5 segundos. Esto demuestra que la combinación de tácticas elegidas no solo cumple el SLA, sino que proporciona un margen amplio que absorbe la variabilidad operacional.
5. Análisis de los resultados
5.1 Comportamiento de la latencia mediana (p50)
La mediana se mantuvo prácticamente constante entre 91ms y 94ms a través de los 4 escenarios. Esto indica que el request típico no se ve afectado por el nivel de concurrencia: la mayoría de las solicitudes adquieren el lock rápido y completan sin espera significativa.
5.2 Degradación no lineal en la cola de latencia
La degradación de latencia se concentra en los percentiles altos y crece de forma no lineal:
- p95: creció linealmente de 110ms a 260ms (2.4x) al multiplicar los usuarios por 10x
- p99: creció de 200ms a 730ms (3.7x)
- p99.9: creció de 380ms a 1,100ms (2.9x)
- Max: creció de 384ms a 1,394ms (3.6x)
Este patrón es la firma clásica de la contención de locks a nivel de fila: la mayoría de requests pasan rápido, pero los que se encolan detrás de múltiples transacciones experimentan esperas que crecen exponencialmente con la profundidad de la cola.
5.3 Los 504 timeouts confirman el punto de sensibilidad
Las 121 fallas en el escenario de 100 usuarios fueron todas de tipo 504 (timeout). Esto significa que la llamada HTTP de Booking a Catalog excedió los 500ms configurados como timeout (CATALOG_TIMEOUT_SECONDS = 0.5). En estos casos, la espera del lock en PostgreSQL fue la causa directa.
Es importante notar que el timeout actúa como un mecanismo de protección: impide que un request lento mantenga una conexión ocupada indefinidamente y evita que la degradación se propague al rest del sistema. Los requests que superaron 500ms fueron cortados y el cliente recibió una respuesta rápida de error, en lugar de quedar esperando.
6. Contextualización de la carga
Para una cadena hotelera con 5 propiedades (como la del experimento), los escenarios representan:
| Escenario | Usuarios | RPS | Equivalente en reservas/hora | Representa |
|---|---|---|---|---|
| Normal | 10 | ~5 | ~18,000 | Operación diaria típica |
| Moderado | 25 | ~12 | ~43,000 | Horas pico |
| Pico | 50 | ~24 | ~86,000 | Evento de alta demanda (temporada alta) |
| Alta contención | 100 | ~47 | ~170,000 | Stress test / punto de quiebre |
Considerando que una cadena de 5 hoteles podría procesar entre 500 y 2,000 reservas diarias, incluso el escenario de 10 usuarios ya supera la demanda realista por un amplio margen. El escenario de 100 usuarios es un stress test diseñado para identificar los límites del sistema.
7. Conclusiones
7.1 La hipótesis se valida, las tácticas arquitectónicas son adecuadas
Las tácticas y patrones seleccionados demuestran ser suficientes para cumplir el SLA bajo todos los niveles de carga probados:
- Comunicación síncrona HTTP (Llamado-Retorno): el salto de red Booking → Catalog vía Cloud Map DNS (~1ms) es despreciable. La simplicidad del patrón síncrono se justifica para esta escala.
- Concurrencia pesimista (
SELECT FOR UPDATE): garantiza consistencia fuerte del inventario. La contención de locks es medible pero se mantiene dentro del SLA incluso bajo stress test (p95 = 260ms, 5.8x de margen). - Limitar tiempo de ejecución (timeout 500ms): las 121 fallas 504 en el escenario de 100 usuarios demuestran que el timeout funciona como mecanismo de protección, evitando que la degradación se propague.
- Introducir concurrencia (async + connection pooling): el throughput por usuario se mantuvo constante (~0.47 RPS/usuario) sin degradación, confirmando que el modelo async escala linealmente.
7.2 El punto de sensibilidad se confirmó pero no compromete las tácticas
La contención de locks existe: el p99 crece 3.7x (200ms → 730ms) de 10 a 100 usuarios, mientras el p50 apenas se mueve (91ms → 94ms). Sin embargo, este efecto solo se manifiesta más allá del p95 y bajo carga (100 usuarios, ~47 RPS) que excede la demanda realista de 5 hoteles (~500-2,000 reservas/día).
8. Impacto en la arquitectura propuesta
No se requieren cambios en la arquitectura. Las tácticas evaluadas, comunicación síncrona, concurrencia pesimista, timeout, y async con connection pooling, son adecuadas para la escala de operación esperada.
9. Evidencias
9.1 Video de Evidencias
El video de evidencias lo pueden encontrar en el siguiente enlace: Video de Evidencias del Experimento 2
9.2 Reportes de Locust (HTML)
Cada escenario generó un reporte HTML interactivo con gráficas de latencia, throughput y distribución de tiempos de respuesta:
| Escenario | Reporte |
|---|---|
| 10 usuarios | scenario_10.html |
| 25 usuarios | scenario_25.html |
| 50 usuarios | scenario_50.html |
| 100 usuarios | scenario_100.html |
9.3 Datos crudos (CSV)
Los datos completos de cada escenario están disponibles en formato CSV para análisis adicional:
| Archivo | Contenido |
|---|---|
scenario_N_stats.csv |
Percentiles (p50, p95, p99), RPS, tasa de fallos |
scenario_N_stats_history.csv |
Serie temporal segundo a segundo (para gráficas) |
scenario_N_failures.csv |
Detalle de cada tipo de fallo y su frecuencia |
Todos los archivos se encuentran en el directorio experimento2/results/.
9.4 Código fuente del experimento
| Componente | Ruta |
|---|---|
| Booking Service | services/booking/app/ |
| Catalog Service | services/catalog/app/ |
| Esquema de BD | db/init.sql |
| Datos de prueba | db/seed.sql |
| Locustfile | locustfile.py |
| Script de ejecución | scripts/run_experiments.sh |
| Docker Compose (local) | docker-compose.yml |
| Infraestructura AWS | terraform/ |