Una solicitud de pago puede consumir 40 ms en el API Gateway, 60 ms en validaciones, 180 ms en la orquestación, 220 ms actualizando estado, 250 ms en una dependencia externa y otros 50 ms atravesando redes y serializando datos. Ningún componente parece catastrófico de forma aislada. El cliente, sin embargo, espera 800 ms.
Ese es el caso sencillo.
En la cola de la distribución, la espera por una conexión, un desafío de autenticación, una ruta lenta hacia el emisor o un reintento pueden convertir la misma operación en varios segundos. La interfaz puede mostrar un timeout aunque la autorización original continúe ejecutándose. El cliente vuelve a enviar el pago. El sistema ya no tiene solo un problema de latencia: también tiene un problema de estado y, potencialmente, de pagos duplicados.
La idea central es esta:
La latencia de un pago no es el tiempo de respuesta de una pasarela. Es la demora y la incertidumbre acumuladas a lo largo de toda la ruta del pago.
Este artículo explica cómo definir esa ruta, medir su distribución, asignar un presupuesto de latencia, controlar los reintentos, preservar la corrección después de un timeout y comprobar que una optimización mejoró el resultado visible para el cliente en lugar de trasladar la demora a otro componente.
Qué mide realmente la latencia de un pago
La latencia es el tiempo transcurrido entre dos eventos definidos. La definición queda incompleta mientras esos eventos no sean explícitos.
En un sistema de pagos importan, como mínimo, cuatro intervalos:
| Medición | Inicio | Fin | Pregunta operativa |
|---|---|---|---|
| Latencia de envío | El cliente confirma el pago | El backend del comercio acepta la solicitud | ¿Cuánto tarda la operación en entrar al sistema controlado? |
| Latencia de autorización | El comercio envía la autorización | Se recibe un resultado autoritativo | ¿Cuánto tarda la decisión síncrona? |
| Latencia de confirmación | Existe un resultado autoritativo | El cliente ve el resultado | ¿El sistema es lento después de tomar la decisión? |
| Latencia de finalización | Se inicia el pago | El negocio considera el estado definitivo para ese método | ¿Cuánto tiempo permanece la incertidumbre? |
Estos intervalos están relacionados, pero no son intercambiables. La API del comercio puede responder rápido mientras el cliente sigue esperando una redirección o un desafío de autenticación. El proveedor puede aceptar la solicitud de inmediato mientras el pago permanece en estado processing. El cliente puede abandonar la página después de la autorización mientras el cumplimiento continúa de forma asíncrona.
Para ingeniería de checkout, el SLI principal suele ser visible para el usuario, por ejemplo:
checkout_payment_outcome_latency
= instante_en_que_el_cliente_ve_un_estado_terminal_o_accionable
- instante_en_que_el_cliente_confirma_el_pago
El inicio y el final exactos dependen del método de pago y del contrato del producto. Una autorización con tarjeta, una transferencia bancaria y un método con notificación diferida no comparten el mismo modelo de finalización. El error no está en elegir una definición u otra. Está en mezclar varias en un mismo panel y llamarlas a todas "latencia del pago".
Latencia no es disponibilidad, éxito ni throughput
Una plataforma de pagos puede estar disponible y ser operacionalmente inutilizable porque el resultado llega demasiado tarde. También puede devolver un timeout mientras el sistema externo termina aprobando la operación.
| Concepto | Pregunta | Ejemplo de fallo |
|---|---|---|
| Disponibilidad | ¿La operación puede intentarse? | El endpoint no responde o rechaza todo el tráfico. |
| Tasa de éxito | ¿El pago alcanzó el estado de negocio esperado? | La autorización fue rechazada o el proceso falló. |
| Latencia | ¿Cuánto tardó la transición de estado? | El P99 sube de 1 a 8 segundos. |
| Throughput | ¿Cuántos intentos se procesan por unidad de tiempo? | El sistema procesa 500 intentos por segundo. |
| Saturación | ¿Qué tan cerca está un recurso restringido de su límite? | Se agotó el pool de conexiones, la cola, los workers o la cuota del proveedor. |
Pueden ocurrir varias combinaciones:
- Throughput alto con una mediana aceptable y una cola inutilizable.
- CPU baja con latencia alta porque las solicitudes esperan I/O, locks, colas o conexiones.
- Sin incremento de HTTP 5xx, pero con aumento de timeouts visibles para el cliente.
- Éxito estable en autorizaciones, pero retraso de webhooks que bloquea estados posteriores.
Google SRE trata latencia, tráfico, errores y saturación como señales diferentes porque ninguna sustituye a las demás. El crecimiento de la cola también puede ser una señal temprana de saturación antes de que el servicio falle de forma visible.
Por qué el promedio oculta riesgo operativo
Las distribuciones de latencia en pagos suelen ser asimétricas. La mayoría de las solicitudes puede completar rápido mientras un grupo pequeño espera mucho más por variación de red, rutas externas, autenticación, contención del pool, garbage collection, reintentos o colas.
Considera 100 intentos:
99 intentos: 100 ms cada uno
1 intento: 10,000 ms
El promedio es:
((99 × 100) + 10,000) / 100 = 199 ms
Un promedio de 199 ms parece saludable. Un cliente esperó diez segundos.
El promedio responde a una pregunta útil para capacidad: cuánto tiempo consumieron los intentos en promedio. No describe la experiencia de la población lenta. Para eso se necesita la distribución.
Otro error es promediar percentiles de varias instancias. Un P99 no es una medición aditiva y los cuantiles precalculados no pueden agregarse de forma correcta entre réplicas. Los histogramas conservan conteos por bucket que sí pueden combinarse antes de calcular el percentil; los summaries que exportan cuantiles ya calculados no.
Para profundizar en cálculo, ventanas, buckets e interpretación, revisa cómo funcionan los percentiles de latencia.
P50, P95, P99 y P99.9
Un percentil indica la latencia por debajo o igual a la cual completó un porcentaje de las operaciones observadas durante una ventana definida.
| Percentil | Interpretación práctica |
|---|---|
| P50 | El intento mediano. La mitad completó en este valor o menos. |
| P95 | Una vista de la experiencia lenta pero todavía frecuente. |
| P99 | El 1 % más lento empieza después de este límite. |
| P99.9 | Una cola más profunda que adquiere importancia operativa a gran volumen. |
Un P99 de 1.8 segundos significa que el 99 % de los intentos observados completó en 1.8 segundos o menos durante la ventana. No significa que todos los intentos del 1 % restante tardaran exactamente 1.8 segundos.
El volumen cambia el significado de la cola:
100,000 intentos de pago por día
1 % más allá del P99 = 1,000 intentos por día
0.1 % más allá del P99.9 = 100 intentos por día
El valor también depende de:
- La ventana de observación.
- Las rutas y métodos incluidos.
- La resolución de los buckets.
- Si los reintentos se cuentan como solicitudes separadas o como un solo intento de negocio.
- Si las solicitudes canceladas por el cliente siguen dentro de la población del servidor.
Por eso un P99 global puede mejorar mientras se degrada una ruta de emisor, una región, una versión de aplicación o un método concreto. Conserva dimensiones que expliquen la población sin crear cardinalidad ilimitada.
Por qué la tail latency empeora entre dependencias
Una operación de pago suele esperar varios resultados obligatorios: validaciones del comercio, evaluación antifraude, tokenización, autorización externa, persistencia y, en algunos casos, autenticación del cliente.
Cuando las llamadas son seriales, sus tiempos se acumulan.
Cuando las llamadas obligatorias se ejecutan en paralelo, la respuesta obligatoria más lenta domina el tiempo total.
Supón cuatro validaciones independientes, cada una con 1 % de probabilidad de ser lenta. La probabilidad de que al menos una sea lenta es:
P(al menos una lenta)
= 1 - P(las cuatro rápidas)
= 1 - 0.99⁴
≈ 3.94 %
El cálculo es ilustrativo. En producción las dependencias rara vez son independientes. Redes compartidas, incidentes regionales, garbage collection, rutas sobrecargadas y reintentos sincronizados introducen correlación. Esa correlación puede volver la cola observada mucho peor que la fórmula simple.
La conclusión operativa se mantiene: cada dependencia requerida aumenta la exposición a eventos de cola. Dean y Barroso describen este comportamiento en servicios a gran escala: episodios raros de alta latencia en componentes individuales pueden dominar la respuesta global cuando existe fan-out.
No "corrijas" este problema paralelizando operaciones cuyo orden tenga semántica de corrección. El paralelismo reduce tiempo solo cuando las operaciones son independientes, acotadas y seguras para ejecutarse de forma concurrente.
Mapear la ruta end-to-end del pago
El span del proveedor es solo un segmento. La latencia completa puede incluir:
- Renderizado y manejo de eventos en navegador o móvil.
- Resolución DNS.
- Adquisición de una conexión.
- Establecimiento de TCP y TLS en conexiones frías.
- Enrutamiento edge y procesamiento del API Gateway.
- Autenticación y validación del comercio.
- Espera en cola antes de obtener un worker.
- Decisiones de riesgo y fraude.
- Tokenización o acceso a vault.
- Procesamiento del proveedor.
- Adquirente, red y emisor.
- Transiciones en la base de datos del comercio.
- Serialización y transferencia de respuesta.
- Renderizado de la confirmación.
- Propagación de webhooks para cambios asíncronos.
La primera pregunta de diagnóstico no es "¿qué servicio está lento?". Es:
¿La demora ocurre antes del envío, dentro de la plataforma del comercio, en la autorización externa, al persistir estado o después de que ya existe un resultado autoritativo?
La mecánica general de la latencia en sistemas distribuidos explica por qué importa la ruta completa. Esta pieza limita el alcance a corrección en pagos, reintentos y resultados inciertos.
Construir un presupuesto de latencia
Un presupuesto de latencia convierte un objetivo end-to-end en restricciones de diseño para la ruta.
Supón el siguiente objetivo ilustrativo:
Objetivo de autorización bajo una carga y mezcla de rutas definidas:
latencia end-to-end P95 <= 800 ms
No es un valor universal. El objetivo correcto depende del método, geografía, flujo del usuario, autenticación, comportamiento del proveedor, política de riesgo y expectativas contractuales.
Una primera asignación podría ser:
| Componente | Presupuesto |
|---|---|
| Cliente y red | 80 ms |
| Edge y API Gateway | 40 ms |
| Autenticación y validación del comercio | 60 ms |
| Orquestación del pago | 120 ms |
| Riesgo y tokenización | 100 ms |
| Ruta de autorización externa | 250 ms |
| Persistencia, serialización y respuesta | 50 ms |
| Margen reservado | 100 ms |
| Total | 800 ms |
Un presupuesto no es la suma de percentiles por componente
Sumar el P95 de todos los componentes no produce el P95 end-to-end. Los percentiles son propiedades de distribuciones, no costes escalares ordinarios. Las dependencias pueden superponerse, compartir causas o existir solo en algunas rutas.
Usa presupuestos locales para restringir el diseño y asignar propiedad. Valida el percentil end-to-end directamente sobre la distribución completa de transacciones.
Reservar margen
Un diseño que consume el 100 % del objetivo en condiciones nominales no tiene espacio para:
- Jitter de red.
- Variación de rutas del proveedor.
- Garbage collection.
- Contención de locks.
- Tráfico en ráfaga.
- Cache misses.
- Creación de conexiones.
- Desafíos de autenticación.
- Overhead de observabilidad.
El margen no debe convertirse en una bolsa sin propietario que absorba regresiones permanentes. Trátalo como una reserva de diseño y revisa la distribución cuando cambie la mezcla de rutas.
Definir la población
El presupuesto debe especificar:
- Qué métodos de pago cubre.
- Qué regiones.
- Qué versiones de cliente.
- Si los flujos con desafío se separan.
- Si incluye reintentos del proveedor.
- Si el inicio es una acción de UI o la recepción en servidor.
- Si el final es autorización, aceptación en proceso o liquidación.
Sin población, el objetivo no puede reproducirse ni exigirse.
Caso práctico: descomponer un pago de 800 ms
Considera un intento observado:
| Segmento | Tiempo observado |
|---|---|
| API Gateway | 40 ms |
| Autenticación y validaciones del comercio | 60 ms |
| Orquestación del pago | 180 ms |
| Base de datos y transición de estado | 220 ms |
| Dependencia externa de pagos | 250 ms |
| Serialización y red | 50 ms |
| Total | 800 ms |
40 + 60 + 180 + 220 + 250 + 50 = 800 ms
La siguiente decisión no debe ser "optimizar el número más grande" sin contexto. Pregunta:
- ¿Qué segmento tiene mayor variabilidad? Una llamada externa estable en 250 ms puede ser menos dañina que una base de datos que oscila entre 30 ms y 2 segundos.
- ¿Qué segmento está en todas las rutas? Una validación opcional puede afectar solo a una población específica.
- ¿Qué trabajo puede ejecutarse en paralelo? Solo operaciones independientes y seguras frente a efectos laterales.
- ¿Qué trabajo puede salir de la ruta síncrona? Notificaciones, analítica y enriquecimiento no decisorio no deberían extender la autorización si pueden registrarse de forma durable y procesarse después.
- ¿Qué datos pueden cachearse con seguridad? La configuración estática puede ser cacheable. El estado del pago y los resultados de autorización requieren reglas de consistencia más estrictas.
- ¿Dónde hace falta un timeout? Toda dependencia remota necesita una espera acotada derivada del deadline restante.
- ¿Qué significa un fallo en ese punto? Un timeout local después del envío produce un resultado desconocido, no evidencia de fallo externo.
Un timeout debe preservar la diferencia entre fallido y desconocido
Un timeout limita cuánto tiempo espera un componente. No determina qué ocurrió en el sistema remoto.
Hay tres casos materialmente diferentes:
- La solicitud nunca fue enviada. El llamador puede fallar localmente sin efectos remotos.
- La solicitud fue enviada y llegó una respuesta definitiva. El sistema puede transicionar al estado correspondiente.
- La solicitud fue enviada, pero la respuesta no llegó antes del deadline. El resultado es desconocido para el llamador. El sistema remoto puede haber rechazado, aceptado o seguir procesando el pago.
Tratar el tercer caso como un fallo definitivo es un defecto de corrección específico de pagos.
Usar un único deadline end-to-end
Los timeouts por salto deben caber dentro de un deadline común, no configurarse de forma aislada.
Deadline end-to-end: 800 ms
Tiempo ya consumido: 430 ms
Reserva para respuesta y persistencia: 90 ms
Máxima espera externa restante: 280 ms
Pseudocódigo conceptual:
// Pseudocódigo ilustrativo. No está listo para producción.
deadline = request_start + 800ms
validate_request()
load_payment_state()
remaining = deadline - now()
response_reserve = 90ms
configured_provider_cap = 300ms
provider_timeout = min(
configured_provider_cap,
remaining - response_reserve
)
if provider_timeout <= 0:
return fail_before_dispatch("deadline exhausted")
result = provider.authorize(
payment_attempt,
timeout = provider_timeout,
idempotency_key = payment_attempt.id
)
if result.timed_out_after_dispatch:
transition_to(PENDING_RECONCILIATION)
schedule_status_reconciliation()
El timeout se selecciona a partir de distribuciones observadas, contrato de la dependencia, espera aceptable para el cliente y deadline restante. Copiar el valor de otro servicio no es una decisión de ingeniería.
Para la interacción general entre timeouts correctamente configurados y reintentos, revisa la pieza especializada sobre su orden y configuración.
Los reintentos pueden reducir fallos o multiplicarlos
Los reintentos ayudan ante fallos transitorios. También generan carga adicional, tiempo adicional y otra oportunidad de repetir un efecto lateral.
Define el vocabulario con precisión:
Intento inicial: 1
Reintentos adicionales: 2
Máximo de intentos totales: 3
Supón ahora tres capas, cada una con dos reintentos adicionales. En el peor caso, una operación de negocio puede producir:
3 × 3 × 3 = 27 llamadas a la dependencia más profunda
Google SRE identifica los reintentos como un amplificador común de sobrecarga en fallos en cascada. El backoff exponencial y el jitter reducen sincronización, pero no vuelven correcta una política insegura o ilimitada.
Decidir según la clase de fallo
| Señal de fallo | Decisión predeterminada | Razonamiento requerido |
|---|---|---|
| Error de validación o solicitud mal formada | No reintentar sin cambios | La solicitud debe modificarse. |
| Fallo de autenticación o autorización | No reintentar sin cambios | Deben cambiar credenciales, permisos o la acción del cliente. |
| Rechazo definitivo del pago | No tratar como retry de infraestructura | Es un resultado de negocio salvo que el proveedor lo clasifique como transitorio. |
| Rate limit | Reintentar condicionalmente | Respetar indicaciones del proveedor, deadline restante, backoff y presupuesto de reintentos. |
| 5xx transitorio | Reintentar condicionalmente | Solo si la operación es idempotente y no se amplifica la sobrecarga. |
| Fallo de conexión antes del envío | Con frecuencia reintentable | Confirmar que no pudo existir un efecto remoto. |
| Timeout o reset después del envío | Resultado desconocido | Reintentar solo con idempotencia y conciliación. |
Asignar un único propietario de reintentos
Los reintentos deberían pertenecer normalmente a una capa con visibilidad sobre:
- La operación de negocio.
- La idempotencia.
- El deadline restante.
- La clasificación de la respuesta.
- El total de intentos.
- La salud actual del sistema.
Reintentos ocultos en clientes, service meshes, SDK, gateways y código de aplicación pueden multiplicarse aunque cada política local parezca conservadora.
Usar un presupuesto de reintentos
Un retry budget limita los intentos adicionales en relación con el tráfico original. Evita que una dependencia degradada reciba carga sintética ilimitada.
Mide, como mínimo:
retry_ratio = solicitudes_de_reintento_adicionales / solicitudes_originales
Alerta sobre la proporción, no solo sobre el conteo absoluto, porque el volumen cambia durante el día.
Para un análisis específico de tormentas de reintentos, y de cómo un exceso de retries se convierte en fallos en cascada, revisa las piezas de resiliencia.
La idempotencia es un requisito de corrección
Una operación idempotente permite repetir el mismo intento lógico sin crear un segundo pago independiente.
La clave debe identificar el intento de negocio, no la instancia de la solicitud HTTP.
Un diseño sólido suele requerir:
- Una clave generada antes del primer envío.
- Reutilización de la misma clave para reintentos del mismo intento lógico.
- Rechazo de la misma clave cuando cambian parámetros materiales.
- Persistencia durable de clave, huella de solicitud y resultado.
- Control de concurrencia cuando llegan duplicados simultáneos.
- Retención alineada con la ventana de reintentos y conciliación.
- Una clave nueva cuando el usuario inicia deliberadamente otro intento.
La documentación de las principales pasarelas de pago describe las claves de idempotencia como mecanismo para repetir solicitudes después de fallos de conexión sin crear otro objeto ni repetir la operación. AWS formula el mismo principio de diseño: los reintentos automatizados solo son seguros cuando el contrato de la API soporta comportamiento idempotente.
La idempotencia no elimina la conciliación. Evita efectos duplicados. El sistema todavía debe determinar si la primera solicitud tuvo éxito, falló o continúa pendiente.
Finalización síncrona frente a asíncrona
El procesamiento asíncrono no elimina la latencia. Cambia dónde ocurre la espera, qué necesita saber el usuario de inmediato y cómo se recuperan los fallos.
La pregunta de diseño es:
¿El cliente necesita el resultado final ahora o solo una confirmación durable de que la solicitud fue aceptada?
| Decisión | Ruta síncrona | Ruta asíncrona |
|---|---|---|
| Resultado inmediato | Disponible cuando completa la dependencia | Puede mostrar aceptado o procesando primero |
| Acoplamiento temporal | Alto | Menor después de la aceptación durable |
| Espera del usuario | Incluye trabajo downstream | Puede terminar tras la aceptación durable |
| Manejo de fallos | El llamador suele gestionar la respuesta inmediata | Workers, eventos y máquina de estados gestionan la recuperación |
| Consistencia | Inmediata o cercana | Frecuentemente eventual |
| Complejidad operativa | Menor al inicio | Mayor por eventos, deduplicación, orden, replay y conciliación |
Mantener síncrono solo el trabajo decisorio
Según el producto y método, la ruta síncrona puede necesitar:
- Validación de la solicitud.
- Autenticación.
- Registro de idempotencia.
- Controles de riesgo necesarios para autorizar.
- Envío de autorización.
- Transición durable de estado.
- Una respuesta accionable para el cliente.
Suelen ser candidatos a procesamiento asíncrono:
- Envío de recibos.
- Analítica.
- Enriquecimiento no bloqueante.
- Indexación de búsqueda.
- Notificaciones downstream.
- Conciliación.
- Cumplimiento tras un evento autoritativo, cuando el producto lo permite.
No retires la persistencia crítica de la ruta síncrona salvo que la aceptación sea durable. Responder éxito antes de registrar el intento o su evento produce una respuesta rápida con corrección débil.
Tratar los webhooks como una ruta durable
Los proveedores usan webhooks para cambios posteriores a la solicitud inicial. Las pasarelas de pago recomiendan observar el estado mediante webhooks y realizar el fulfillment en servidor, sin depender de que el cliente permanezca en la página: confirmar la recepción, almacenar el mensaje y procesarlo después de la aceptación.
Un receptor de producción debe:
- Autenticar el evento mediante el mecanismo del proveedor.
- Validar el envelope mínimo.
- Persistir o encolar de forma durable.
- Devolver rápido el código de éxito esperado.
- Procesar idempotentemente.
- Deduplicar por identificador del evento e identificador de negocio.
- Aplicar transiciones según la máquina de estados, no solo por orden de llegada.
- Vigilar lag, antigüedad de reintentos, dead letters y brechas de conciliación.
Dónde se oculta la latencia antes del código de aplicación
Una llamada externa lenta no siempre significa que el proveedor procesó lentamente. Parte del tiempo puede consumirse antes de que la solicitud lo alcance.
DNS, TCP y TLS
Una conexión fría puede incluir:
- Consulta DNS.
- Creación de socket.
- Establecimiento TCP.
- Negociación TLS.
- Paso por proxies.
- Validación de conexión.
Reutilizar conexiones evita repetir gran parte del trabajo. También hace depender el sistema de un keep-alive saludable, detección de conexiones obsoletas y administración correcta del pool.
Separa fases cuando la librería lo permita:
pool_wait
connection_setup
TLS_handshake
request_write
provider_wait
response_read
Sin esa separación, una "llamada al proveedor" de 900 ms puede contener 600 ms esperando una conexión local disponible.
Pools de conexiones
Un pool puede fallar en ambas direcciones.
Demasiado pequeño:
- Las solicitudes esperan una conexión.
- El P99 sube mientras el procesamiento del proveedor permanece estable.
- Los timeouts ocurren antes del envío.
Demasiado grande:
- El comercio puede superar límites de conexión o tasa.
- Más trabajo concurrente alcanza una dependencia degradada.
- Aumentan sockets, memoria y trabajo TLS.
- El pool oculta backpressure ausente.
Mide:
- Conexiones activas.
- Conexiones ociosas.
- Límite del pool.
- Duración de adquisición.
- Timeouts de adquisición.
- Tasa de creación.
- Vida útil y fallos por conexiones obsoletas.
- Solicitudes por conexión.
OpenTelemetry define métricas de duración HTTP y de conexiones que permiten separar estas fases, como duración de solicitudes, conexiones abiertas y duración de conexión.
Cold starts y efectos de calentamiento
"Cold start" puede referirse a mecanismos distintos:
- Inicialización de una instancia serverless.
- Arranque de un contenedor.
- Carga de clases o compilación JIT en JVM.
- Pools vacíos.
- Estado DNS o TLS frío.
- Calentamiento de caché.
- Inicialización lazy.
- Primera consulta que compila o carga planes.
Diagnostica la fase real. Aumentar instancias mínimas no corrige una primera consulta lenta. Calentar caché no corrige la adquisición de conexiones. Llamar cold start a cualquier demora inicial impide tomar una decisión precisa.
Colas, backpressure e incidentes con CPU baja
Una cola transforma el exceso de llegadas en tiempo de espera. Puede conservar throughput temporalmente mientras la latencia crece.
Un sistema con CPU baja puede estar saturado en:
- Un pool de conexiones.
- Permisos de workers.
- Conexiones de base de datos.
- Concurrencia del proveedor.
- Un lock.
- I/O de disco.
- Sockets de red.
- Una partición de mensajería.
Mide la antigüedad de la cola además de su tamaño. Mil elementos pueden ser aceptables con alto throughput y peligrosos con bajo throughput. La antigüedad refleja demora ya acumulada para el usuario.
Backpressure significa que los componentes upstream reducen, difieren o rechazan trabajo cuando downstream está restringido. En pagos, importa la frontera de aceptación:
- Antes de la aceptación durable, rechaza explícitamente y evita estado ambiguo.
- Después de la aceptación durable, preserva el intento y procésalo o concílialo según la máquina de estados.
- Nunca descartes silenciosamente trabajo de pago ya aceptado.
El load shedding debe diseñarse alrededor de corrección y comunicación al cliente, no copiarse de una API de lectura sin estado.
Instrumentación mínima para producción
La telemetría mínima debe conectar el intento de pago de negocio con cada espera técnica sin exponer datos sensibles.
Métricas
Registra distribuciones, conteos y señales de saturación.
| Métrica | Tipo | Propósito |
|---|---|---|
payment.outcome.duration | Histograma | Tiempo end-to-end desde el inicio definido hasta un resultado terminal o accionable |
payment.authorization.duration | Histograma | Duración de la ruta de autorización |
payment.dependency.duration | Histograma | Duración por dependencia |
payment.queue.duration | Histograma | Tiempo de espera antes del procesamiento |
payment.pool.wait.duration | Histograma | Tiempo para adquirir conexión o permiso |
payment.webhook.lag | Histograma | Tiempo desde el evento del proveedor hasta aplicar la transición |
payment.attempts | Contador | Intentos originales de negocio |
payment.retry.requests | Contador | Solicitudes de reintento adicionales |
payment.timeouts | Contador | Timeouts por fase y dependencia |
payment.unknown_outcomes | Contador | Intentos que requieren conciliación |
payment.duplicate_suppressed | Contador | Duplicados resueltos mediante idempotencia |
payment.state.transition_failures | Contador | Transiciones inválidas o fallidas |
Para instrumentación HTTP, OpenTelemetry estandariza nombres como http.server.request.duration y http.client.request.duration. Los histogramas son apropiados porque interesan la distribución y los percentiles; el modelo de métricas de OpenTelemetry representa histogramas mediante conteos, sumas y buckets agregables.
Dimensiones acotadas útiles:
- Operación.
- Proveedor.
- Clase de ruta.
- Región.
- Familia del método de pago.
- Plataforma y versión mayor del cliente.
- Clase de resultado.
- Intento original frente a retry.
- Flujo con desafío frente a flujo frictionless.
No uses identificadores de pago, clientes, claves de idempotencia, números de tarjeta ni mensajes de error ilimitados como labels.
Trazas
Una traza debe hacer visibles las esperas. Spans sugeridos:
checkout.submit
payment.validate
payment.idempotency.reserve
risk.evaluate
provider.authorize
payment.state.persist
customer.confirmation
webhook.ingest
webhook.apply
payment.reconcile
Cada span de dependencia debe capturar:
- Inicio y duración.
- Estado.
- Fase del timeout.
- Número de intento.
- Ruta o clasificación acotada del proveedor.
- Si la solicitud fue enviada.
- Si el resultado es definitivo o desconocido.
Propaga contexto entre servicios controlados. El proveedor puede devolver su propio request ID; almacénalo como atributo de traza o log cuando esté permitido para correlacionar el intento interno con registros externos. Para una implementación más profunda, revisa la observabilidad con trazas distribuidas.
Logs
Los logs deben responder preguntas de estado y causalidad que una métrica no puede resolver:
trace_id
payment_attempt_id
operation
state_before
state_after
dependency
provider_request_id
elapsed_ms
queue_wait_ms
pool_wait_ms
retry_attempt
outcome_class
error_code
dispatch_status
Nunca registres PAN, CVV, tokens completos, secretos o payloads crudos sin un diseño explícito de seguridad. Hashear un identificador no lo vuelve seguro automáticamente si puede reconstruirse por un espacio pequeño o continuar vinculándose a una persona.
Cómo investigar una API de pagos lenta
Una investigación disciplinada avanza desde el impacto hacia la segmentación y desde la segmentación hacia una hipótesis causal comprobable.
Paso 1: confirmar el impacto
Revisa en conjunto:
- P50, P95, P99 y P99.9 end-to-end.
- Éxito de autorización y clases de fallo.
- Tasa de timeouts visibles.
- Tráfico original y tráfico de retry.
- Antigüedad de cola.
- Resultados desconocidos.
- Señales de abandono o finalización del checkout.
- SLI y SLO aplicables.
Un aumento del P99 del servidor sin impacto en el cliente puede tener una prioridad distinta a una confirmación lenta con métricas de backend estables.
Paso 2: definir la población exacta
Especifica:
- Inicio y fin del incidente.
- Ventana de medición.
- Operación incluida.
- Métodos incluidos.
- Regiones y versiones.
- Si los retries son solicitudes separadas o se agrupan por intento de negocio.
- Si los flujos con desafío se separan.
Cambiar el denominador durante la investigación puede fabricar una recuperación aparente.
Paso 3: segmentar antes de culpar al proveedor
Segmenta por:
- Proveedor y ruta.
- Método.
- País del emisor o región acotada, cuando esté permitido.
- Operación del comercio.
- Versión de aplicación.
- Región o zona de infraestructura.
- Solicitud original frente a retry.
- Flujo de autenticación.
Un P99 global puede ocultar una única ruta degradada. Un P99 del proveedor puede ocultar contención local en el pool.
Paso 4: separar procesamiento de espera
Clasifica el tiempo de cada traza lenta:
procesamiento CPU
espera en cola
espera del pool
espera por lock
DNS o establecimiento de conexión
transferencia de solicitud
espera de dependencia externa
I/O de base de datos
serialización
confirmación en cliente
Si la CPU está baja y la espera de cola o pool está alta, añadir cómputo difícilmente resolverá la espera dominante.
Paso 5: comparar trazas sanas y lentas
Compara la misma operación, ruta, método y periodo cuando sea posible.
Pregunta:
- ¿Qué span se expande?
- ¿Aparece un span nuevo?
- ¿Los retries existen solo en trazas lentas?
- ¿El request ID del proveedor muestra una o varias solicitudes?
- ¿El tiempo se acumula antes o después del envío?
- ¿La persistencia es lenta antes o después del resultado externo?
- ¿La demora ocurre en renderizado o redirección del cliente después de completar el backend?
Un span lento está correlacionado con la solicitud lenta. Solo es causal cuando su expansión explica el tiempo adicional y se han probado hipótesis competidoras.
Paso 6: inspeccionar retries y resultados desconocidos
Calcula:
additional_retry_ratio
= solicitudes_de_retry_adicionales / intentos_originales_de_negocio
Compara:
- Proporción antes y durante el incidente.
- Intentos totales por
payment_attempt_id. - Backlog de conciliación.
- Conteo de duplicados suprimidos.
- Solicitudes al proveedor por operación de negocio.
El aumento de retries puede comenzar como consecuencia de la latencia y luego convertirse en causa de más latencia.
Paso 7: formular una hipótesis comprobable
Una buena hipótesis nombra el mecanismo y predice señales.
Débil:
El proveedor está lento.
Comprobable:
El pool local de conexiones hacia el proveedor está saturado.
Si es correcto, la espera de adquisición explicará la mayor parte del P99 añadido,
el tiempo del proveedor después del envío permanecerá estable
y aumentar concurrencia segura reducirá la cola
sin incrementar errores ni rate limiting.
Paso 8: mitigar la espera dominante
La acción depende del mecanismo:
- Restaurar o redimensionar el pool después de validar límites downstream.
- Retirar trabajo no crítico de la ruta síncrona.
- Acotar colas y rechazar antes de una aceptación ambigua.
- Reducir amplificación de retries.
- Añadir backoff y jitter.
- Corregir índices o contención de locks.
- Reutilizar conexiones.
- Separar flujos con desafío.
- Enrutar alrededor de una ruta degradada si el modelo de negocio y corrección lo permite.
- Extender un timeout solo si el presupuesto end-to-end y el contrato con el usuario aceptan la espera adicional.
Aumentar un timeout puede reducir errores de timeout mientras hace esperar más al cliente y retiene más recursos. No es automáticamente una mejora.
Paso 9: verificar latencia, corrección y carga
Una recuperación válida debe mostrar:
- Recuperación de percentiles end-to-end.
- Menor espera de cola o pool.
- Tasa de éxito estable o mejor.
- Sin aumento de intentos duplicados.
- Menor backlog de resultados desconocidos.
- Retry ratio de regreso a su línea base.
- Sin nueva saturación o rate limiting downstream.
- Conciliación consistente entre comercio y proveedor.
Ejemplo hipotético de dimensionamiento de pool
Supón que la ruta externa recibe 200 solicitudes por segundo en hora pico y mantiene cada conexión ocupada 350 ms en promedio.
Bajo supuestos de estado estable, la Ley de Little da una estimación de concurrencia media:
L = λ × W
L = 200 solicitudes/s × 0.35 s
L = 70 solicitudes concurrentes
Un pool limitado a 40 conexiones tendrá que encolar trabajo con esa carga incluso antes de considerar ráfagas y variación de cola.
La decisión no es "configurar 70". También debes revisar:
- Límites de concurrencia y tasa del proveedor.
- Límites locales de sockets y memoria.
- Distribución de ráfagas.
- Ocupación P95 y P99.
- Tráfico de retry.
- Si una mayor concurrencia sobrecarga la dependencia.
Después puedes validar un límite candidato con carga similar a producción e inyección de fallos. Solo se acepta si mejora la latencia end-to-end sin trasladar el fallo a throttling, agotamiento local o una tormenta de reintentos mayor.
Para un flujo completo más allá de la latencia, revisa la investigación estructurada de incidentes.
Traducir la latencia a impacto de negocio sin inventar causalidad
La idea central de la versión anterior sigue siendo válida: la latencia de pagos termina convirtiéndose en una variable de negocio. La responsabilidad de ingeniería consiste en medir esa relación sin transformar una correlación en una cifra de ingresos fabricada.
Empieza por cantidades observables:
intentos_lentos
= intentos_originales_totales × fracción_sobre_el_umbral
Ejemplo:
100,000 intentos originales por día
1 % por encima del umbral seleccionado
= 1,000 intentos lentos por día
Después mide, por cohortes comparables:
- Abandono del checkout.
- Reenvíos del cliente.
- Duplicados suprimidos.
- Resultados desconocidos.
- Contactos a soporte.
- Retraso de cumplimiento.
- Brechas de conciliación.
- Exposición contractual a SLO o SLA, cuando corresponda.
Un modelo posible de exposición es:
exposición_estimada
= intentos_lentos
× abandono_incremental_observado
× valor_promedio_de_orden
No llames "ingresos perdidos" a este resultado mientras el abandono incremental no tenga respaldo causal. Las sesiones lentas pueden diferir por geografía, emisor, método, dispositivo, red o desafío de autenticación. Usa despliegues controlados, cohortes equivalentes o experimentos cuando sea viable.
La misma regla aplica a los retries. Una subida de reintentos puede correlacionarse con menor conversión porque ambas señales nacen de una ruta externa degradada. El retry no es automáticamente la causa original. Se necesitan trazas, secuencia temporal y una mitigación controlada para establecer el mecanismo.
Errores comunes de implementación
Tratar un timeout como pago fallido
Un timeout después del envío significa que el llamador desconoce el resultado. Marcarlo como fallido puede permitir un segundo intento independiente mientras el primero termina exitosamente.
Reintentar en todas las capas
Políticas locales se multiplican en una tormenta. Asigna un propietario y haz visibles los retries de SDK, proxies, service mesh y aplicación.
Reintentar operaciones no idempotentes
El backoff no evita efectos duplicados. El intento lógico necesita un contrato de idempotencia.
Usar el mismo timeout para todo
Adquisición de conexión, establecimiento, procesamiento externo y deadline end-to-end resuelven problemas distintos. Un valor copiado oculta la fase que está fallando.
Sumar P99 por componente
Los percentiles por componente no producen el percentil end-to-end. Usa trazas para descomponer solicitudes y distribuciones completas para SLO.
Promediar P99 entre instancias
Los cuantiles precalculados no se agregan correctamente. Agrega poblaciones de histogramas y luego calcula el percentil.
Optimizar P50 e ignorar la cola
La mediana puede mejorar mientras el P99 empeora. Los incidentes de pago suelen vivir en colas específicas por ruta o amplificadas por retry.
Aumentar el pool sin analizar downstream
Un pool mayor puede trasladar la cola al proveedor, exceder cuotas o acelerar la sobrecarga.
Mantener trabajo no crítico en la autorización
Recibos, analítica y enriquecimiento no deberían retrasar al cliente cuando pueden registrarse de forma durable y procesarse después.
Hacer polling agresivo de resultados asíncronos
El polling frecuente añade carga y puede provocar rate limiting. Prefiere eventos del proveedor y conciliación acotada.
Registrar datos sensibles o labels de alta cardinalidad
La telemetría debe permitir diagnóstico sin filtrar información de pago ni volver inutilizable el sistema de métricas.
Asumir que CPU baja significa capacidad libre
El recurso restringido puede ser una cola, pool, lock, conexión de base de datos, cuota del proveedor o ruta de red.
Checklist operativo
Definir
- Los eventos inicial y final de cada SLI están explícitos.
- La latencia de autorización no se mezcla con la latencia de finalización.
- La población del SLO identifica ruta, método, región y flujo de autenticación.
- Los intentos originales y los retries adicionales se cuentan por separado.
Instrumentar
- La duración end-to-end se registra como histograma.
- P50, P95, P99 y una cola más profunda apropiada están disponibles.
- La espera de cola y pool se miden por separado.
- Puede distinguirse establecimiento de conexión de procesamiento externo.
- Son visibles la proporción de retries, la fase del timeout y los resultados desconocidos.
- Se vigilan lag de webhooks y backlog de conciliación.
- Las dimensiones de métricas son acotadas.
- Trazas y logs no contienen datos prohibidos.
Controlar
- Se propaga un deadline end-to-end común.
- Los timeouts por dependencia caben en el deadline restante.
- Un timeout posterior al envío lleva a conciliación pendiente, no a fallo automático.
- Una sola capa controla los retries.
- Los reintentos se limitan a fallos transitorios clasificados.
- Se aplican backoff y jitter cuando corresponde.
- Un retry budget limita la carga sintética.
- La idempotencia es durable y segura frente a concurrencia.
- Las colas están acotadas y tienen una política explícita de overflow.
- El procesamiento de webhooks es durable e idempotente.
Validar
- Los percentiles end-to-end mejoran bajo carga similar a producción.
- La tasa de éxito no retrocede.
- No aumentan resultados desconocidos ni antigüedad de conciliación.
- La supresión de duplicados funciona como se esperaba.
- El retry ratio vuelve a la línea base.
- Throttling y saturación downstream permanecen dentro de lo aceptable.
- La inyección de fallos cubre demora, reset, timeout posterior al envío, webhook duplicado y eventos fuera de orden.
- Los registros del comercio y proveedor concilian después de la prueba.
Preguntas frecuentes
¿Cuál es una buena latencia para una pasarela de pagos?
No existe un valor universal. Depende del método, geografía, autenticación, flujo, proveedor y estado que el cliente necesita recibir. Define un SLI visible para una población concreta, establece un SLO y distribuye un presupuesto por la ruta.
¿Cuál es la diferencia entre P95 y P99 en pagos?
P95 es la latencia en la que completó el 95 % de los intentos observados o menos. P99 cubre el 99 %. El 1 % restante puede representar muchos clientes a escala, pero el significado depende de la ventana y mezcla de rutas.
¿Por qué puede subir la latencia si la CPU sigue baja?
Las solicitudes pueden esperar conexiones, colas, locks, I/O de base de datos, proveedores externos, autenticación o red. CPU mide uso de cómputo, no todos los recursos restringidos.
¿Debe reintentarse un pago que alcanzó timeout?
Solo después de determinar si la solicitud pudo enviarse. Si el resultado es desconocido, el retry requiere idempotencia, deadline restante, una clase de fallo elegible y conciliación. El timeout por sí solo no demuestra que el pago falló.
¿Los pagos asíncronos eliminan la latencia?
No. Acortan o cambian la espera síncrona al exponer un estado aceptado o procesando y completar después. Añaden requisitos de eventos durables, consumidores idempotentes, transiciones de estado, comunicación y conciliación.
¿Pueden sumarse los P99 de los componentes para obtener el P99 del pago?
No. Los percentiles son propiedades de distribuciones y no son directamente aditivos. Usa presupuestos locales para diseño, trazas para solicitudes individuales y un histograma end-to-end para el percentil del pago.
Conclusión
La latencia de pagos se vuelve costosa cuando amplía el periodo en que ni el cliente ni el comercio conocen el resultado autoritativo.
La respuesta de ingeniería no consiste en optimizar una llamada aislada. Consiste en controlar el sistema completo:
- Definir los intervalos visibles y relevantes para negocio.
- Medir distribuciones en lugar de depender de promedios.
- Asignar un presupuesto end-to-end con margen explícito.
- Separar cola, adquisición de conexión, procesamiento y espera externa.
- Propagar un deadline único por la ruta.
- Preservar los resultados desconocidos después de timeouts.
- Hacer que los retries sean acotados, observables e idempotentes.
- Sacar trabajo no crítico de la ruta síncrona solo después de una aceptación durable.
- Validar latencia, corrección, reintentos y conciliación en conjunto.
Un sistema de pagos no es rápido porque una API reporta un promedio bajo. Es rápido cuando la ruta completa produce un resultado predecible y autoritativo sin crear carga adicional ni comprometer la corrección en la cola.
Fuentes técnicas
- Google SRE — Monitoring Distributed Systems: sre.google/sre-book/monitoring-distributed-systems
- Google SRE — Service Level Objectives: sre.google/sre-book/service-level-objectives
- Google SRE — Addressing Cascading Failures: sre.google/sre-book/addressing-cascading-failures
- Jeff Dean y Luiz André Barroso — The Tail at Scale: research.google/pubs/the-tail-at-scale
- OpenTelemetry — Semantic conventions for HTTP metrics: opentelemetry.io/docs/specs/semconv/http/http-metrics
- OpenTelemetry — Metrics Data Model: opentelemetry.io/docs/specs/otel/metrics/data-model
- Prometheus — Histograms and summaries: prometheus.io/docs/practices/histograms
- AWS — Timeouts, retries, and backoff with jitter: builder.aws.com/content/timeouts-retries-and-backoff-with-jitter
- AWS — Making retries safe with idempotent APIs: aws.amazon.com/builders-library/making-retries-safe-with-idempotent-APIs
- Stripe — Idempotent requests: docs.stripe.com/api/idempotent_requests
- Stripe — Payment status updates: docs.stripe.com/payments/payment-intents/verifying-status
- Adyen — Webhooks: docs.adyen.com/development-resources/webhooks
- John D. C. Little — A Proof for the Queuing Formula L = λW: pubsonline.informs.org/doi/10.1287/opre.9.3.383