Diseno experimento HA 01 - martin-hendricks/MISO-PROYECTO-FINAL-SOLVENTA GitHub Wiki
Módulo 5 — EDA Maestría en Ingeniería de Software — MISW4501 Arquitectura de Software Caso de estudio: Solventa — plataforma insurtech Versión: 1.0
Documento complementario: la implementación detallada (Docker, contrato del proveedor, código fuente, scripts de carga y protocolo de ejecución) se encuentra en
Guia_Tecnica_HA-01.md.
| Campo | Detalle |
|---|---|
| Título del experimento | Caché con actualización oportunista y valor de respaldo para proteger el presupuesto de latencia de la cotización embebida ante un proveedor de Open Finance degradado |
| Propósito del experimento | Evaluar si la distribución de componentes propuesta —:MsCotización → :CacheOF → :AdaptadorOF → proveedor externo, con la llamada al adaptador fuera del camino bloqueante— permite cumplir EC-LAT-01 (p95 ≤ 250 ms) y EC-LAT-02 (p99 ≤ 500 ms) tanto con el proveedor sano como degradado (EC-LAT-09), y determinar cuál es el nivel mínimo de desacople que lo satisface. El montaje no incluye el :ApiGateway, de modo que los umbrales se trasladan al servicio descontando el presupuesto de borde (Anexo G). |
| Resultados esperados | Se espera que la llamada síncrona bloqueante al proveedor no alcance el umbral cuando este se degrada, que la caché con lectura bloqueante en fallo lo alcance solo si la tasa de acierto es muy alta, y que la caché con actualización oportunista lo alcance de forma estable e independiente del estado del proveedor. El experimento debe cuantificar el costo de esa independencia en dos dimensiones: la frescura del dato con que se tarifica y la proporción de cotizaciones resueltas con valor de respaldo. Se espera además confirmar el resultado contraintuitivo previsto por el equipo: el camino degradado resulta más rápido que el camino frío con proveedor sano. |
| Elementos de arquitectura involucrados |
ASR asociados: EC-LAT-01 y EC-LAT-02 — Latencia, prioridad (A,A); EC-LAT-09 — Latencia con dependencia degradada, prioridad (A,A). Restricciones de presupuesto: EC-LAT-07 (≤ 120 ms por dependencia externa) y EC-LAT-08 (timeout duro de 700 ms).Historia de arquitectura: HA-01. Vistas y modelos: Vista funcional ( :MsCotización, :MotorRaiting, :CacheOF, :AdaptadorOF); Vista de despliegue (ElastiCache Redis y grupo de escalado de cotización); Vista de información (§1.4.4 valor de respaldo, §1.4.3 estrategia de replicación de la Hoja de trabajo semana 5).Correspondencia con el diagrama de componentes: el montaje no introduce componentes nuevos. Cada pieza corresponde a un «component» o «datastore» ya publicado en §1.2, salvo el inyector de fallas y el doble del proveedor, que son instrumentación y se declaran como tales.Puntos de sensibilidad que se desean probar: grado de bloqueo de la dependencia externa, tasa de acierto de la caché, estado del proveedor, política del interruptor y tasa de llegada. |
| Esfuerzo estimado | Tiempo: 1 semana — 40 horas Horas hombre: 10 horas/hombre (4 integrantes) Menor que HA-08 porque se reutiliza el montaje de contenedores, el stack de observabilidad y el protocolo de corridas ya construidos. |
- Lenguaje y framework: Python 3.12, FastAPI, Uvicorn (uvloop, httptools)
-
Contenerización: Docker y Docker Compose V2 (extiende el
docker-compose.ymlde HA-08) -
Almacenamiento: Redis 7 (
:CacheOF), PostgreSQL 16 (catálogo de producto y reglas de tarifa) -
Cliente HTTP asíncrono:
httpxcon límites de conexión explícitos por proveedor - Doble del proveedor de Open Finance: servicio FastAPI que devuelve el contrato real de Open Finance con una distribución de latencia de aplicación configurable (no un valor fijo)
-
Inyección de fallas de red: Toxiproxy, interpuesto entre
:AdaptadorOFy el doble, para degradación a nivel de conexión TCP -
Librerías:
httpx,redis-py(asyncio),asyncpg,orjson,pydantic,prometheus-client - Generación de carga: k6 con ejecutor de tasa de llegada
- Observabilidad: Prometheus, Grafana
- Hardware: estación de desarrollo con mínimo 16 GB de RAM, 4 núcleos y 10 GB de disco libre. El dataset es mucho menor que el de HA-08: no hay millón de registros, sino un conjunto de perfiles de Open Finance del tamaño del universo de clientes simulado.
Si
:MsCotizaciónresuelve el perfil de Open Finance leyendo:CacheOFy trata la invocación de:AdaptadorOFcomo una actualización oportunista —abandonando la espera al agotar el presupuesto por dependencia de 120 ms (EC-LAT-07) y resolviendo con el último valor conocido o con un valor por defecto—, mientras:AdaptadorOFconserva su timeout duro de 700 ms (EC-LAT-08) con circuit breaker y aislamiento de recursos por proveedor,entonces la cotización embebida alcanzará un p95 ≤ 225 ms y un p99 ≤ 475 ms medidos en el servicio —equivalentes a 250 ms y 500 ms extremo a extremo una vez sumado el presupuesto de borde del Anexo G— con el proveedor sano y también con el proveedor degradado o caído,
aceptando como contrapartida que una fracción acotada de las cotizaciones se tarifique con señales menos frescas o con valores por defecto, que esa fracción quede trazada para actuaría, y que un conjunto reducido de peticiones se sacrifique durante la apertura del interruptor.
| Campo | Detalle |
|---|---|
| Historia de arquitectura asociada | HA-01 — Protección del presupuesto de latencia de la cotización embebida |
| Escenarios de calidad |
EC-LAT-01 y EC-LAT-02 (operación normal y horario pico), EC-LAT-09 (dependencia degradada). Restricciones: EC-LAT-07, EC-LAT-08
|
| Nivel de incertidumbre |
Alto. La separación de los dos timeouts en componentes distintos es una lectura del equipo, no una prescripción del enunciado: el caso da ambos números sin decir a quién pertenecen. Se desconoce (a) cuántas peticiones se sacrifican antes de que el interruptor abra y si ese conjunto rompe el p99, (b) si el umbral por conteo abre a tiempo con tráfico bajo, (c) si las llamadas abandonadas por :MsCotización agotan el pool de :AdaptadorOF bajo carga, y (d) qué tasa de acierto de caché es necesaria para sostener el escenario. El costo de equivocarse es alto: si el diseño no se sostiene, la cotización embebida —el journey que define la propuesta de valor de Solventa— incumple su ASR frente a un proveedor que Solventa no controla. |
| # | Punto de sensibilidad | ¿Qué probar? |
|---|---|---|
| 1 | Grado de bloqueo de la dependencia externa. Es la decisión arquitectónica central: cuánto puede el camino crítico depender de un tercero impredecible. | Variar la estrategia de resolución del perfil en tres niveles: A invocación síncrona bloqueante al adaptador en cada cotización, sin caché; B caché con lectura bloqueante en fallo (cache-aside clásico: el fallo espera al proveedor); C caché con actualización oportunista y valor de respaldo (el diseño propuesto: la respuesta nunca espera al proveedor). |
| 2 |
Estado del proveedor externo. EC-LAT-09 exige cumplir el umbral con la dependencia degradada, no solo en condiciones ideales. |
Cinco estados, más la transición de recuperación. Ver el modelo de fallas del Anexo A: sano, lento, degradado, sin respuesta (acepta la conexión y nunca contesta) y caído (conexión rechazada). El estado sin respuesta es el más hostil y el que realmente pone a prueba el pool del adaptador. |
| 3 | Tasa de acierto de la caché. Es la variable que decide si el camino frío define o no el percentil. El diseño se sostiene solo por encima de cierto umbral, y ese umbral hoy no está cuantificado. | Preparar el conjunto de claves consultadas para producir tasas de acierto de 99 %, 96 %, 90 % y 50 %, midiendo el p95 y el p99 en cada nivel para localizar el punto de quiebre. |
| 4 | Política del circuit breaker. Un umbral por conteo abre rápido con tráfico alto y tarde con tráfico bajo; en el segundo caso las peticiones sacrificadas pueden superar el 1 % de la ventana y romper el p99. | Comparar umbral por conteo (N fallos consecutivos) contra umbral por tasa sobre ventana deslizante, en dos niveles de tráfico: alto (200 sol/s) y bajo (10 sol/s). |
| 5 | Concurrencia sobre la misma clave (estampida). Varias peticiones concurrentes con fallo sobre el mismo perfil dispararían N invocaciones idénticas al proveedor justo cuando más duele. | Brazo adicional C' = C más coalescencia de peticiones (single-flight), midiendo invocaciones al proveedor por fallo de caché y saturación del pool del adaptador. |
| ID | Enunciado | Punto de sensibilidad | Brazos |
|---|---|---|---|
| HD-01.1 | Con el proveedor sano, los tres brazos cumplen p95 ≤ 225 ms | 1, 2 | A, B, C |
| HD-01.2 | Con el proveedor degradado, solo el brazo C cumple p95 ≤ 225 ms y p99 ≤ 475 ms | 1, 2 | A, B, C |
| HD-01.3 | En el brazo C, el camino degradado es más rápido que el camino frío con proveedor sano | 1, 2 | C |
| HD-01.4 | El brazo C sostiene el umbral con tasa de acierto ≥ 96 %; por debajo de ese valor el p99 se degrada | 3 | B, C |
| HD-01.5 | Las peticiones sacrificadas hasta la apertura del interruptor son < 1 % de la ventana con tráfico alto | 4 | C |
| HD-01.6 | Con tráfico bajo, el umbral por conteo no mantiene las sacrificadas bajo el 1 %, y el umbral por tasa sí | 4 | C |
| HD-01.7 | Sin coalescencia, un fallo concurrente sobre la misma clave produce más de una invocación al proveedor y satura el pool del adaptador antes que con coalescencia | 5 | C, C' |
| HD-01.8 | Al recuperarse el proveedor, el interruptor cierra y la proporción con respaldo vuelve por debajo del 5 % en ≤ 60 s, sin producir una estampida de invocaciones | 2, 5 | C, C' |
Nota metodológica. HD-01.6 es deliberadamente refutable en su forma afirmativa. Si el umbral por conteo resulta suficiente también con tráfico bajo, el equipo se ahorra una complejidad; si no, tiene evidencia para justificarla. En ambos casos el experimento decide algo.
| Estilo de arquitectura asociado al experimento | Análisis (atributos de calidad que favorece y desfavorece) |
|---|---|
| Llamada-retorno sincrónico (N-niveles) |
Favorece: • Baja latencia interna y consistencia inmediata en el journey de venta • Simplicidad de razonamiento y de depuración Desfavorece: • Acoplamiento temporal con el colaborador • Propagación de la latencia y de la falla del tercero al camino crítico |
| Capas + adaptadores (anticorrupción) |
Favorece: • Modificabilidad e integrabilidad ante el cambio de proveedor • Punto único donde alojar timeout, interruptor y aislamiento de recursos Desfavorece: • Una indirección más por llamada • Riesgo de que el adaptador se vuelva cuello de botella si no se le acota el pool |
| Microservicios (contexto general de Solventa) |
Favorece: • Escalamiento selectivo de :MsCotización según la curva de campaña de un socio• Modificabilidad Desfavorece: • Latencia extremo a extremo por los saltos de borde • Consistencia distribuida |
Precisión sobre el origen del costo de latencia. A diferencia de HA-08 —donde el costo provenía de componer el estado sobre cinco entidades normalizadas—, aquí el costo es externo y ajeno al control de Solventa: proviene de la latencia y la variabilidad del proveedor de Open Finance. Ningún estilo interno lo elimina; lo único que la arquitectura puede hacer es sacarlo del camino bloqueante. Ese es el objeto exacto del experimento, y la razón por la que el brazo A no es un hombre de paja sino la implementación que cualquier equipo escribiría primero.
| Táctica de arquitectura asociada al experimento | Descripción |
|---|---|
| Múltiples copias de datos |
:CacheOF conserva una copia local del perfil de Open Finance con su marca de tiempo. Es la táctica que la wiki ya declara para EC-LAT-09, y la que este experimento pone a prueba. La copia acorta el camino de acceso a costa de introducir una ventana de desactualización que debe medirse, no suponerse. |
| Incrementar la latencia de los recursos | El presupuesto por dependencia de 120 ms es un límite explícito sobre cuánto puede esperar el camino crítico. Al agotarse, :MsCotización abandona la espera en lugar de propagar el retraso del tercero. |
| Limitar la respuesta a los eventos | La actualización del perfil se ejecuta fuera de la respuesta al socio: la invocación al adaptador continúa en segundo plano y su resultado sirve para repoblar la caché, no para responder. |
| Detección de fallas: temporizador | El timeout duro de 700 ms en :AdaptadorOF (EC-LAT-08) es el detector que alimenta al circuit breaker. |
| Recuperación: degradación elegante | Ante la ausencia de perfil fresco, :MsCotización tarifica con el último valor conocido o con el valor por defecto del ramo, y marca la cotización como resuelta con respaldo para trazabilidad actuarial. |
| Aislamiento de recursos (bulkhead) | Pool de conexiones y de trabajo dedicado por proveedor en :AdaptadorOF, de modo que las llamadas abandonadas no agoten los recursos del resto del servicio. Es la táctica que hace viable abandonar a los 120 ms sin efectos colaterales. |
| Componente | Propósito y comportamiento esperado | Tecnología asociada |
|---|---|---|
API de Cotización (:MsCotización) |
Expone el recurso de cotización embebida. Implementa los cuatro brazos sobre el mismo binario, seleccionables por configuración, de modo que la estrategia de resolución del perfil sea la única variable que cambie entre corridas. Aplica el presupuesto por dependencia, decide entre perfil fresco, último valor conocido y valor por defecto, y marca la respuesta con el origen y la edad del dato usado. | Python, FastAPI, Uvicorn, httpx, redis-py, orjson
|
Motor de Tarifa (:MotorRaiting) |
Calcula la prima a partir del perfil recibido y del conjunto de reglas vigente. Se implementa con un costo de cómputo fijo y calibrado (~60 ms) para que sea una constante entre brazos y no una fuente de variación. Debe aceptar perfiles incompletos y reflejar la incertidumbre en el resultado. | Python, reglas versionadas en memoria, asyncpg para cargar el conjunto de reglas al arranque |
Caché de Perfil de Open Finance (:CacheOF) |
Almacena el perfil por cliente con su marca de tiempo de obtención, bajo política de expiración por fuente. Sirve el último valor conocido incluso vencido cuando el proveedor no responde: la expiración marca cuándo conviene refrescar, no cuándo dejar de servir. Esta distinción es una decisión de diseño y una de las cosas que el experimento debe validar. | Redis 7, política allkeys-lru
|
Adaptador de Open Finance (:AdaptadorOF) |
Traduce del esquema del proveedor al modelo canónico de señales. Aloja el timeout duro de 700 ms, el circuit breaker con sus tres estados y el pool dedicado por proveedor. Expone como métricas el estado del interruptor, las conexiones en vuelo y el tiempo hasta la apertura. | Python, httpx con límites de conexión, interruptor implementado en el propio adaptador para poder instrumentar sus transiciones |
| Doble del Proveedor de Open Finance (instrumentación, no arquitectura) | Sustituye al «External» :OpenFinance del modelo de componentes. Devuelve la forma real del contrato de Open Finance para que el costo de deserialización en el adaptador sea representativo, y aplica una latencia de aplicación muestreada de una distribución log-normal con cola larga, no un valor constante. Es sin estado y determinista bajo semilla fija, de modo que dos repeticiones sean comparables. Corre con límites de recursos propios y su saturación se verifica antes de cada corrida. |
Python, FastAPI, numpy para el muestreo |
| Inyector de Fallas de Red (instrumentación, no arquitectura) | Se interpone entre el adaptador y el doble para degradar la conexión, no la aplicación: latencia de red, corte de conexión, rechazo y agujero negro. Se modifica en caliente por su API de administración, sin reiniciar el montaje, condición necesaria para recorrer los cinco estados dentro de una misma corrida. | Toxiproxy |
Los dos últimos componentes no existen en el modelo de arquitectura y no deben aparecer en él. Son el banco de pruebas. Se declaran aquí para que la trazabilidad entre el experimento y el diagrama de componentes sea explícita y no quede a interpretación del lector.
| Conector | Comportamiento deseado en el experimento | Tecnología asociada |
|---|---|---|
| Conector HTTP de cotización | El generador de carga emite solicitudes contra el recurso de cotización a una tasa de llegada fija, de modo que la degradación del servicio no reduzca automáticamente la carga y enmascare el percentil. Registra la latencia extremo a extremo por solicitud y etiqueta cada una con el brazo, el estado del proveedor y el nivel de acierto configurado. | Cliente: k6 con ejecutor de tasa de llegada. Servidor: Uvicorn sobre ASGI. |
| Conector de acceso a la caché | Lectura por clave del perfil, devolviendo valor y marca de tiempo. En el brazo C la escritura ocurre fuera del camino de respuesta, alimentada por el resultado de la actualización oportunista. |
redis-py en modo asíncrono sobre Redis 7. |
| Conector de invocación al proveedor (brazo A) | Invocación bloqueante en cada cotización, sin caché y sin presupuesto de abandono: el camino crítico espera lo que el proveedor tarde, hasta el timeout duro. Es la línea base y representa la implementación que se escribiría sin la táctica bajo estudio. |
httpx asíncrono con timeout de 700 ms. |
| Conector de invocación bloqueante en fallo (brazo B) | Cache-aside clásico: ante un acierto responde de inmediato; ante un fallo invoca al proveedor y espera el resultado antes de responder. Aísla el efecto de la caché del efecto del desacople, que es la distinción que el experimento debe demostrar. |
httpx asíncrono, misma configuración de timeout. |
| Conector de actualización oportunista (brazos C y C') | La invocación al proveedor se lanza con un presupuesto de 120 ms; al agotarse, la respuesta se resuelve con el último valor conocido o con el valor por defecto y la invocación continúa en segundo plano hasta su timeout duro, repoblando la caché si llega a completarse. El circuit breaker corta las invocaciones mientras esté abierto. En C' se añade coalescencia por clave. |
httpx con pool dedicado, asyncio.timeout para el presupuesto, tarea en segundo plano para el refresco, coalescencia por clave con asyncio.Future compartido. |
| Conector de inyección de fallas | Permite alterar la latencia y la disponibilidad del proveedor sin reiniciar el montaje, condición necesaria para que los cuatro estados del proveedor se recorran dentro de una misma corrida y sean comparables sin efecto de calentamiento. | Toxiproxy con API de administración. |
| Conector de telemetría | La API y el adaptador exponen métricas que Prometheus recolecta periódicamente; el generador de carga las envía por escritura remota al mismo Prometheus, de modo que latencia de cliente, latencia interna, estado del interruptor y saturación del pool queden en la misma línea de tiempo. |
prometheus-client, Prometheus, Grafana. |
| Tecnología asociada con el experimento | Selección | Justificación |
|---|---|---|
| Lenguajes de programación | Python 3.12 | Alineado con el stack del equipo, con el resto de Solventa y con el experimento HA-08, lo que permite reutilizar montaje y protocolo. Su modelo asíncrono es indispensable para representar la actualización oportunista: la tarea de refresco debe seguir viva después de que la respuesta ya salió. |
| Frameworks de desarrollo | FastAPI + Uvicorn (uvloop, httptools) | Framework ASGI nativo asíncrono. Es requisito para el brazo C: un servidor síncrono no puede continuar una invocación en segundo plano después de responder sin bloquear un hilo del pool, lo que falsearía la comparación. |
| Cliente HTTP |
httpx en modo asíncrono, con limits explícitos por proveedor |
Permite fijar el tamaño del pool por destino, que es la implementación concreta del bulkhead, y separar el presupuesto de la petición del timeout de la conexión. Un cliente sin límites por destino haría imposible medir HD-01.7. |
| circuit breaker | Implementación propia dentro de :AdaptadorOF
|
Se descarta una librería genérica porque el punto 4 de sensibilidad exige comparar dos políticas de apertura (conteo contra tasa sobre ventana deslizante) e instrumentar las transiciones de estado. Una librería obligaría a adaptar la instrumentación a su modelo interno y añadiría una variable ajena al estudio. |
| Inyección de fallas | Toxiproxy | Es el estándar de facto para inyectar latencia y cortes a nivel de conexión TCP de forma reproducible y modificable en caliente por API. Inyectar la latencia dentro del doble del proveedor sería más simple, pero simularía un servidor lento y no una red degradada, que es el modo de falla que EC-LAT-09 describe. |
| Doble del proveedor | Servicio FastAPI propio | Se prefiere sobre una herramienta de mocking general porque debe devolver la forma real del contrato de Open Finance para que el costo de deserialización en :AdaptadorOF sea representativo. |
| Plataforma de despliegue | Docker + Docker Compose V2 | Permite fijar límites explícitos de CPU y memoria por componente, condición indispensable para que las corridas sean reproducibles y comparables entre brazos. Se reutiliza el archivo del experimento HA-08. |
| Almacenamiento | Redis 7 (:CacheOF), PostgreSQL 16 (reglas de tarifa) |
Redis corresponde a ElastiCache Redis de la vista de despliegue. PostgreSQL solo sirve el conjunto de reglas al arranque y no participa del camino crítico, para que la variable bajo estudio sea únicamente la resolución del perfil. |
| Herramientas de análisis | k6, Prometheus, Grafana | k6 ofrece el ejecutor de tasa de llegada, imprescindible para medir latencia correctamente, y umbrales declarativos que codifican el criterio de aceptación en el propio script. Grafana permite superponer el estado del interruptor sobre la curva de latencia, que es la visualización que hace evidente el hallazgo de HD-01.3. |
| Librerías |
httpx, redis-py (asyncio), asyncpg, orjson, pydantic, prometheus-client
|
Drivers asíncronos en toda la ruta: un driver síncrono dentro de una corrutina bloquea el event loop y produciría una refutación falsa. orjson minimiza el costo de serialización para que no contamine la comparación entre brazos. |
| Integrante | Tareas a realizar | Esfuerzo estimado |
|---|---|---|
| Alex Mauricio Rodriguez Sanchez |
Desarrollar la API de Cotización: • Crear la aplicación FastAPI y el ciclo de vida de los clientes y pools. • Implementar los cuatro brazos sobre el mismo binario. • Implementar el presupuesto de abandono a 120 ms y la tarea de refresco en segundo plano. • Instrumentar el origen y la edad del dato en cada respuesta. |
10 horas |
| Martin Ricardo Romero Ortiz |
Preparar el entorno de ejecución: • Extender el docker-compose.yml de HA-08 con Toxiproxy y el doble del proveedor.• Configurar los cuatro estados del proveedor y el script que los conmuta en caliente. • Configurar los tableros de Grafana con el estado del interruptor superpuesto a la latencia. • Apoyar la ejecución de las corridas. |
10 horas |
| John Edwin Guerrero Ayala |
Desarrollar el Adaptador y el Motor de Tarifa: • Implementar :AdaptadorOF con timeout duro, pool dedicado y las dos políticas de interruptor.• Instrumentar transiciones de estado, conexiones en vuelo y peticiones sacrificadas. • Implementar el motor de tarifa con costo calibrado y tolerancia a perfiles incompletos. • Implementar la coalescencia por clave del brazo C'. |
10 horas |
| Juan Camilo Acevedo Ospina |
Planificar y dirigir el experimento: • Definir el contrato del perfil canónico y la política de expiración por fuente. • Construir el conjunto de claves que produce cada tasa de acierto objetivo. • Construir el script de carga y el protocolo de corridas contrabalanceadas. • Consolidar el presupuesto del Anexo G y redactar el informe final. |
10 horas |
Total: 40 horas — 1 semana
El esfuerzo asume que el montaje de contenedores y el stack de observabilidad de HA-08 están operativos y se reutilizan. Si el experimento se ejecuta de forma independiente, deben sumarse unas 12 horas de preparación de entorno.
El punto de sensibilidad 2 exige recorrer cinco estados del proveedor de Open Finance, más su transición de recuperación. Cada estado se implementa como una combinación de configuración del doble del proveedor (latencia de aplicación) y del inyector de fallas (comportamiento de la conexión TCP):
| Estado | Latencia de aplicación (doble) | Comportamiento de conexión (Toxiproxy) | Qué representa |
|---|---|---|---|
| Sano | Log-normal, mediana 80 ms, cola hasta 200 ms | Sin alteración | Operación normal declarada por EC-LAT-01/EC-LAT-02
|
| Lento | Log-normal, mediana 400 ms, cola hasta 900 ms | Sin alteración | Proveedor respondiendo pero por encima del presupuesto de 120 ms |
| Degradado | Log-normal, mediana 800 ms, cola hasta 2 s | +150 ms de latencia de red inyectada | Combinación de aplicación lenta y red congestionada — el escenario que describe EC-LAT-09
|
| Sin respuesta | N/A (la petición nunca llega a resolverse) |
timeout: acepta la conexión TCP y no envía datos |
El caso más hostil: el pool del adaptador retiene el socket hasta su propio timeout duro de 700 ms |
| Caído | N/A |
reset_peer: rechaza la conexión inmediatamente |
Fallo rápido, el circuit breaker debe abrir con el menor costo posible |
| Recuperación | Vuelve a Sano tras una ventana configurable (30 s por defecto) | Se retira la alteración de Toxiproxy | Verifica HD-01.8: el cierre del interruptor y el retorno del hit-rate de datos frescos |
Transición entre estados dentro de una misma corrida. El inyector se reconfigura por su API de administración sin reiniciar los contenedores, de modo que una corrida puede recorrer Sano → Degradado → Sin respuesta → Recuperación sin perder el estado de la caché ni reiniciar el circuit breaker — condición necesaria para que HD-01.8 sea observable.
| Tipo | Variable | Valores / control |
|---|---|---|
| Independiente | Estrategia de resolución del perfil | A (bloqueante sin caché) / B (cache-aside bloqueante en fallo) / C (actualización oportunista) / C' (C + coalescencia) |
| Independiente | Estado del proveedor | Sano / Lento / Degradado / Sin respuesta / Caído / Recuperación |
| Independiente | Tasa de acierto de caché objetivo | 99 % / 96 % / 90 % / 50 % |
| Independiente | Política del circuit breaker | Por conteo (N fallos consecutivos) / por tasa sobre ventana deslizante |
| Independiente | Tasa de llegada | 10 sol/s (tráfico bajo) / 200 sol/s (tráfico alto) |
| Dependiente | Latencia extremo a extremo | p50, p95, p99 medidos en el generador de carga |
| Dependiente | Latencia interna del servicio | Histograma expuesto por la API |
| Dependiente | Tasa de error | Porcentaje de respuestas no exitosas |
| Dependiente | Proporción resuelta con valor de respaldo | Porcentaje de respuestas marcadas como "último valor conocido" o "valor por defecto" |
| Dependiente | Peticiones sacrificadas hasta apertura del interruptor | Conteo absoluto y como porcentaje de la ventana |
| Dependiente | Invocaciones al proveedor por fallo de caché | Solo brazos C y C', para medir el efecto de la coalescencia |
| Controlada | Costo de cómputo del motor de tarifa | Fijo y calibrado (~60 ms), idéntico entre brazos |
| Controlada | Tamaño del pool de conexiones del adaptador | Fijo e idéntico entre brazos |
| Controlada | Timeout duro del adaptador | 700 ms, idéntico entre brazos (EC-LAT-08) |
| Controlada | Presupuesto por dependencia | 120 ms, aplica solo en brazos C y C' (EC-LAT-07) |
| Controlada | Representación de la respuesta | Contrato de respuesta idéntico entre los cuatro brazos |
| Controlada | Semilla del muestreo de latencia del doble | Fija, para que las corridas sean comparables |
Control crítico. Al igual que en HA-08, si los cuatro brazos no devuelven exactamente el mismo contrato de respuesta, parte de la diferencia medida provendría del tamaño del payload y no de la estrategia de resolución del perfil. El protocolo incluye una verificación automática de equivalencia antes de cada corrida.
Tres corridas independientes por brazo, con el orden contrabalanceado mediante un cuadrado latino, igual que en HA-08 y por la misma razón (neutralizar el sesgo del caché de páginas del sistema operativo y del calentamiento de conexiones):
| Corrida | Orden de ejecución |
|---|---|
| R1 | A → B → C |
| R2 | B → C → A |
| R3 | C → A → B |
Cada corrida recorre los seis estados del modelo de fallas en secuencia (Sano → Lento → Degradado → Sin respuesta → Caído → Recuperación), midiendo el escalón de operación regular en cada uno antes de avanzar al siguiente. El brazo C' se corre por separado, una vez confirmado el comportamiento de C, para aislar el efecto de la coalescencia (punto de sensibilidad 5).
Se acepta la hipótesis HD-01 si, en el escalón de operación regular y en las tres corridas:
- El p95 del brazo C medido en el servicio es ≤ 225 ms y el p99 ≤ 475 ms, tanto con el proveedor sano como con el proveedor degradado o sin respuesta.
- Las peticiones sacrificadas hasta la apertura del interruptor son < 1 % de la ventana con tráfico alto (HD-01.5).
- El hit-rate mínimo que sostiene el umbral queda cuantificado (HD-01.4), aunque no alcance el 96 % propuesto — el resultado en sí es la evidencia buscada.
- Ninguna corrida queda invalidada por las verificaciones de sanidad definidas en la guía técnica.
Se refuta la hipótesis HD-01 si:
- El brazo C no alcanza el umbral con el proveedor degradado o sin respuesta, o
- El brazo C alcanza el umbral solo degradando la proporción de valor de respaldo a un nivel que actuaría considere inaceptable para la calidad de la tarifa, lo cual contradice el propósito declarado de HA-01, o
- La recuperación del proveedor (HD-01.8) produce una estampida de invocaciones que satura el pool del adaptador.
Resultado intermedio relevante. Si el brazo B ya cumple el umbral con el proveedor degradado (es decir, si la tasa de acierto de caché es suficientemente alta para que el camino bloqueante en fallo casi nunca se ejercite), la actualización oportunista del brazo C constituye complejidad no justificada y la recomendación arquitectónica debe ser la alternativa más simple que satisface el ASR — igual que el criterio ya aplicado en HA-08 para el brazo B frente al C.
| Brazo | Corrida | Estado proveedor | p50 (ms) | p95 (ms) | p99 (ms) | Error (%) | % con respaldo | ¿Cumple? |
|---|---|---|---|---|---|---|---|---|
| A | R1 | Sano | n/a | |||||
| A | R1 | Degradado | n/a | |||||
| B | R1 | Sano | ||||||
| B | R1 | Degradado | ||||||
| C | R1 | Sano | ||||||
| C | R1 | Degradado | ||||||
| C | R1 | Sin respuesta | ||||||
| C | R1 | Caído | ||||||
| C' | R1 | Degradado |
(Repetir el bloque completo para R2 y R3.)
| Brazo | Estado | p95 medio (ms) | Desviación estándar | ¿Cumple los 3? | Veredicto |
|---|---|---|---|---|---|
| A | Sano | ||||
| A | Degradado | ||||
| B | Sano | ||||
| B | Degradado | ||||
| C | Sano | ||||
| C | Degradado | ||||
| C | Sin respuesta | ||||
| C' | Degradado |
Reportar la desviación estándar entre corridas es obligatorio, por la misma razón que en HA-08: un p95 medio dentro del umbral con desviación amplia es evidencia de inestabilidad, no de cumplimiento.
| Hit-rate objetivo | p95 brazo B (ms) | p95 brazo C (ms) | ¿Brazo B ya cumple? |
|---|---|---|---|
| 99 % | |||
| 96 % | |||
| 90 % | |||
| 50 % |
| Tráfico | Política | % peticiones sacrificadas | ¿< 1 %? |
|---|---|---|---|
| Alto (200 sol/s) | Por conteo | ||
| Alto (200 sol/s) | Por tasa | ||
| Bajo (10 sol/s) | Por conteo | ||
| Bajo (10 sol/s) | Por tasa |
| Brazo | Invocaciones al proveedor por fallo concurrente | Saturación del pool observada |
|---|---|---|
| C (sin coalescencia) | ||
| C' (con coalescencia) |
Los umbrales absolutos (225 ms / 475 ms en servicio) no son transferibles. El hardware de desarrollo no es producción ni incluye el salto del :ApiGateway. Se reporta la mejora relativa entre brazos como resultado principal y el valor absoluto como indicativo.
Todo se ejecuta en un solo host. Subestima la latencia real entre :MsCotización, :CacheOF y :AdaptadorOF, que en producción residen en nodos distintos.
Contención de recursos. El generador de carga, Toxiproxy, el doble del proveedor y la plataforma de observabilidad compiten por la misma CPU. Mitigado con límites explícitos por componente.
Caché de páginas del sistema operativo no controlable. Mitigado mediante el contrabalanceo del orden de brazos (Anexo A).
Variabilidad en la cola de la distribución. Afecta sobre todo al p99. Mitigado con tres corridas independientes y reporte de la desviación estándar.
El muestreo de latencia del doble del proveedor es una aproximación. La distribución log-normal es una elección razonada de forma de cola, no una medición del proveedor real de Open Finance (que aún no existe como integración productiva).
El valor de respaldo se modela como constante por ramo. En producción, el valor por defecto podría requerir calibración actuarial más fina que no es objeto de este experimento.
Un solo perfil de carga. Se miden tráfico alto (200 sol/s) y bajo (10 sol/s) como dos puntos discretos, no una curva continua; el punto de quiebre exacto entre ambos regímenes queda para una iteración posterior.
Toxiproxy inyecta la falla en la conexión, no en la aplicación del proveedor real. Es una aproximación deliberada (Sec. 7, tabla de tecnología), pero implica que comportamientos específicos del proveedor real de Open Finance (p. ej. rate limiting con código 429) no están cubiertos por este montaje.
En orden de menor a mayor costo arquitectónico:
- Precarga proactiva de la caché para los clientes con mayor probabilidad de cotizar (por ejemplo, tras el primer contacto en el canal del socio), reduciendo la dependencia del camino frío.
- Ajustar el presupuesto por dependencia (hoy 120 ms) si la telemetría muestra que el proveedor sano rara vez lo agota, ganando margen sin tocar el diseño.
- Separar el valor de respaldo por segmento de riesgo, en vez de un único valor por ramo, si actuaría determina que la pérdida de precisión no es aceptable de forma uniforme.
-
Réplicas de
:CacheOFcon lectura local por zona, si la latencia de red hacia Redis resulta ser una fracción no despreciable del presupuesto. - Revisión del contrato con el proveedor de Open Finance (SLA de latencia, rate limits) si el experimento muestra que ninguna táctica interna alcanza el umbral con el proveedor consistentemente degradado. Esto excede el control arquitectónico del equipo y debe negociarse con el área comercial.
| Artefacto | Identificador |
|---|---|
| Historia de arquitectura | HA-01 |
| Escenarios de calidad |
EC-LAT-01, EC-LAT-02, EC-LAT-09
|
| Atributo de calidad | Latencia |
| Prioridad | (A,A) — ASR |
| Hipótesis de diseño | HD-01 (sub-hipótesis HD-01.1 a HD-01.8) |
| Tácticas | Múltiples copias de datos; incrementar la latencia de los recursos; limitar la respuesta a los eventos; detección de fallas (temporizador); degradación elegante; aislamiento de recursos (bulkhead) |
| Estilos | Llamada-retorno sincrónico, capas + adaptadores, microservicios |
| Vistas de arquitectura | Funcional (componentes), Información (datos), Despliegue (contenedores) |
| Reutiliza montaje de | HA-08 (Docker Compose, stack de observabilidad, protocolo de corridas contrabalanceadas) |
| Proyecto Jira | SOLV |
| Documento técnico complementario | Guia_Tecnica_HA-01.md |