Grupos de conexiones y latency
Grupos de conexiones y latency
1) Por qué se necesitan grupos
Las conexiones son costosas (TCP/TLS handshakes, autenticación, warm-up). El grupo permite:- Reutilizar los connects terminados (keep-alive) → debajo de TTFB.
- Controlar el paralelismo y dar retroceso en lugar de una avalancha de retraídos.
- Reducir las colas p95/p99 debido al tamaño correcto y los tiempos de espera.
Riesgos clave: colas de espera en el grupo, bloqueo de cabeza de línea, contensado por connects y tormenta de retraídas.
2) Base de las matemáticas: cómo contar el tamaño del grupo
Usamos la ley de Little: 'L = λ × W'. Para una piscina, eso significa:- 'λ' - Flujo medio de consultas (RPS).
- 'W' es la ocupación media de la conexión por solicitud (tiempo de servicio, incluyendo latencia de red y funcionamiento del servicio remoto).
- Tamaño mínimo de la agrupación: 'N _ min ≈ λ × W'.
- Agregue el stock bajo variaciones y p99: headroom 20-50%.
- Ejemplo: 300 RPS, media hold-time 40 ms → 'N _ min = 300 × 0. 04 = 12`. Con un stock del 50% → 18 connects.
Si las colas son grandes: considere 'W _ p95' o'W _ p99 'para rutas críticas - los grupos crecen.
3) Principios generales de diseño
1. Ruta de datos corta: reuse (keep-alive, multiplexación HTTP/2/3).
2. Limitación de la concurrencia: es mejor fallar rápidamente (429/503) que fritar el backend.
3. Taimaouts> Retraos: Exhibe pequeños timeouts y raros retratos con un jitter.
4. El cliente tiene colas más cortas que el servidor (rápido fail-fast).
5. Backpressure: cuando la piscina está llena - inmediatamente NACK/error/collback «más tarde».
6. Aislamiento de grupos por objetivos: DB, caché, PSP externos - sus límites.
4) HTTP/1. 1 vs HTTP/2/3, keep-alive
HTTP/1. 1: una solicitud de connect al mismo tiempo (prácticamente); necesita una piscina con múltiples conexiones por host.
HTTP/2: multiplexación de flujos en un TCP; menos connects, pero HOL-blocking es posible en TCP cuando se pierden paquetes.
HTTP/3 (QUIC): independencia de streaming sobre UDP: menos problemas de HOL, más rápido que los primeros bytes.
- keep-alive timeout 30-90s (por perfil), límite de solicitudes de connect (graceful recycle).
- Pre-calentamiento (preconnect) al inicio del worker.
- Limitar los flujos máximos por HTTP/2 (por ejemplo, 100-200).
nginx upstream backend {
server app-1:8080;
server app-2:8080;
keepalive 512;
keepalive_requests 1000;
keepalive_timeout 60s;
}
proxy_http_version 1. 1;
proxy_set_header Connection "";
Envoy (HTTP/2 pool):
yaml http2_protocol_options:
max_concurrent_streams: 200 common_http_protocol_options:
idle_timeout: 60s max_connection_duration: 3600s
5) Grupos de DB: PgBouncer, HikariCP, controladores
El objetivo es limitar las transacciones competitivas y mantener las retenciones cortas del connect.
5. 1 PgBouncer (PostgreSQL)
Modos: 'session '/' transaction '/' statement'. Para la API, es más común la transacción.
Parámetros importantes: 'pool _ size', 'min _ pool _ size', 'reserve _ pool _ size', 'server _ idle _ timeout', 'query _ wait _ timeout'.
ini
[databases]
appdb = host=pg-primary port=5432 dbname=appdb
[pgbouncer]
pool_mode = transaction max_client_conn = 5000 default_pool_size = 100 min_pool_size = 20 reserve_pool_size = 20 query_wait_timeout = 500ms server_idle_timeout = 60 server_reset_query = DISCARD ALL
5. 2 HikariCP (Java)
Pequeños, rápidos connects, duros timeouts.
properties dataSourceClassName=org. postgresql. ds. PGSimpleDataSource maximumPoolSize=30 minimumIdle=5 connectionTimeout=250 validationTimeout=200 idleTimeout=30000 maxLifetime=1800000 leakDetectionThreshold=5000
Reglas:
- `maximumPoolSize ≈ RPS × W × headroom`.
- 'connectionTimeout' cientos de milisegundos, no segundos.
- Habilite la detección leak.
5. 3 Go/Node/Python - ejemplos
Go http. Client (reuse + timeouts):go tr:= &http. Transport{
MaxIdleConns: 512,
MaxIdleConnsPerHost: 128,
IdleConnTimeout: 60 time. Second,
TLSHandshakeTimeout: 2 time. Second,
}
c:= &http. Client{
Transport: tr,
Timeout: 2 time. Second ,//general
}
Node. js keep-alive agente:
js const http = require('http');
const agent = new http. Agent({ keepAlive: true, maxSockets: 200, maxFreeSockets: 64, timeout: 60000 });
psycopg / SQLAlchemy (Python):
python engine = create_engine(
url, pool_size=30, max_overflow=10, pool_recycle=1800, pool_pre_ping=True, pool_timeout=0. 25
)
6) Colas de espera y tail-latency
Las colas ocurren cuando:- La agrupación es menor que 'λ × W' → crece la cola de espera del connect.
- Irregularidad de la carga (bursts) sin búfer ni límites.
- Las consultas largas ocupan un connect y crean un HOL.
- Divida los grupos por tipo de consulta (rápida/lenta).
- Implemente el temporizador de espera de connect (lado cliente). Si ha caducado, rápido NACK.
- Detección de Outlier y Circuit-breaking en rutas (Envoy, HAProxy).
- Cuotas para rutas «pesadas», grupo separado para informes/exportaciones.
yaml circuit_breakers:
thresholds:
- priority: DEFAULT max_connections: 200 max_pending_requests: 100 max_requests: 1000 max_retries: 2
7) Taimautas y Retraídas (orden correcto)
1. Connect timeout (corto: 50-250 ms dentro de DC).
2. TLS handshake timeout (500–1000 ms вне DC).
3. Request/Read timeout (más cerca de la ruta SLO).
4. Retry: máximo de 1 vez, sólo para técnicas idempotentes; jitter + backoff.
5. Budget sobre retraídas: límite global como porcentaje de RPS (por ejemplo, ≤ 10%).
8) Keep-alive, Nagle, protocolos
Desactive Nagle (TCP_NODELAY) para RPC con mensajes pequeños.
Active HTTP keep-alive siempre que sea posible.
Siga el TIME_WAIT - tune 'reuse '/' recycle' sólo si entiende las consecuencias; mejor - reuse los connects, no la afinación del núcleo.
TLS: utilice la resunción de sesión y ALPN.
9) Afinación OS/Kernel (con precaución)
`net. core. somaxconn`, `net. ipv4. ip_local_port_range`, `net. ipv4. tcp_fin_timeout`.
Descriptores: 'nofile' ≥ 64k por proxy de proceso.
Balance de IRQ, GRO/LRO - por perfil de tráfico.
Prioridad - perfilar; afinación sin métricas a menudo perjudica.
10) Observabilidad: qué medir
Utilidad de la piscina: ocupado/total, p50/p95 espera connect.
Consultas en vuelo y su tiempo de espera (cortes a lo largo de las rutas).
Error budget retrayes: proporción de repeticiones.
Connection churn: crear/cerrar por segundo.
TCP/TLS: SYN RTT, handshakes, session reuse.
Для БД: active connections, waiting, long transactions, locks.
Графики: «RPS vs pool wait», «hold-time distribution», «reuse ratio», «circuit trips».
11) Recetas de caso
11. 1 puerta de enlace API → backend
HTTP/2 a los backends, 'max _ concurrent _ streams = 200'.
Grupo de 20-40 conexiones por servicio por nodo de puerta de enlace.
Timeout: connect 100ms, per-try 300-500ms, general 1-2s, 1 retry con jitter.
11. 2 Servicio → PostgreSQL a través de PgBouncer
'pool _ mode = transaction', 'default _ pool _ size' por fórmula (RPS × W × 1. 3).
En la aplicación 'connectionTimeout≤250ms', transacciones cortas (<100ms).
Solicitudes de informes pesados: una agrupación/réplica independiente.
11. 3 gRPC interno
Un canal (HTTP/2) por host de destino con un límite de flujo de 100-200.
Deadline en RPC a través de la ruta SLO, retrae sólo idempotent.
Sampling Tracks para RPC largos y métricas de tiempo libre.
12) Lista de verificación de implementación (0-30 días)
0-7 días
Medir 'W' (hold-time) en rutas clave/clientes.
Calcula 'N _ min = λ × W' y añade un 30-50% de headroom.
Habilite keep-alive y los temporizadores cortos de espera de connect.
8-20 días
Separe los grupos (rápidos/lentos/externos).
Escriba circuit-breakers y budgets de retrés.
Añadir dashboards: pool wait p95, reuse ratio, in-flight.
21-30 días
Corridos de carga con bursts, la prueba de caos «caída de fondo».
Optimización por cola: aislamiento de rutas pesadas, cachés locales.
Documente las fórmulas y los límites en runbook 'ax.
13) Anti-patrones
El tamaño de la agrupación es «al azar» y no hay sala de cabecera.
Los temporizadores grandes de la espera del connect → colas largas en lugar de fallas rápidas.
Muchos retraídos sin jitter e idempotencia → una tormenta.
Un grupo compartido para todos los tipos de solicitudes.
Las transacciones largas mantienen el connect (DB) → la starvation del resto.
Keep-alive desactivado o límites de idle → churn demasiado pequeños y crecimiento TTFB.
14) Métricas de madurez
Pool wait p95 en venta <10% del total de la ruta p95.
Reuse ratio (> 90% para HTTP internos;> 80% para externos).
DB txn time p95 < 100–200 ms; proporción de transacciones largas <1%.
Retry rate <5% (y ≤ budget), los errores debidos a timeouts son estables y predecibles.
Cálculo documentado del grupo para todos los clientes críticos.
15) Conclusión
El pooling de conexión eficiente es la ingeniería de colas + disciplina de timeout. Mida 'W', calcule la piscina 'λ × W' con el stock, encienda keep-alive/HTTP2 +, separe las rutas lentas, mantenga los temporizadores cortos y los retratos mínimos con el jitter. Agregue la observabilidad de «pool wait vs latency» y circuit-breakers - y obtendrá un TTFB bajo, una cola p99 controlada y resistencia a ráfagas sin sobrecalentamiento de backends.