Poulas de conexões e latency
Pool de conexões e latency
1) Para quê são as balas
As conexões são caras (TCP/TLS handshakes, autenticação, warm-up). O pool permite:- Reutilizar os conectórios prontos (keep-alive) → abaixo do TTFB.
- Controlar o paralelismo e dar backpressure em vez de uma avalanche de retrações.
- Reduzir as caudas p95/p99 através do tamanho correto e dos temporizadores.
Riscos essenciais: filas de espera na bala, head-of-line blocking, contêineres por conectórios e tempestade de retrações.
2) Base de matemática: como contar o tamanho do pool
Usamos a Lei Little: 'L = £ x W'. Para um pulo, significa:- '£' é o fluxo médio de solicitações (RPS).
- 'W' é a média de emprego da conexão por solicitação (serviço time, incluindo latência de rede e serviço remoto).
- Tamanho mínimo do pool: 'N _ min ≈ £ x W'.
- Adicione o estoque para variações e p99: headroom 20-50%.
- Exemplo: 300 RPS, média hold-time 40 ms → 'N _ min = 300 x 0. 04 = 12`. Com 50% → 18 conectórios.
Se as caudas forem grandes, se considerarem «W _ p95» ou «W _ p99» para os caminhos críticos, as balas crescerão.
3) Princípios gerais de design
1. Atalho de dados: reuse (keep-alive, HTTP/2/3 multiplexagem).
2. Limite de paralelismo: é melhor falhar rapidamente (429/503) do que curar backand.
3. Timeouts> retrai: exibe pequenos times e raras retrações com jitter.
4. As filas do cliente são mais curtas do que as do servidor (rápido fail-fast).
5. Backpressure: Quando o pool está cheio, imediatamente NACK/erro/colleback «mais tarde».
6. Isolar os grupos de metas: DB, kesh, PSP externo - seus limites.
4) HTTP/1. 1 vs HTTP/2/3, keep-alive
HTTP/1. 1: um pedido de conectório simultâneo (praticamente); Preciso de um pool com vários conectórios por anfitrião.
HTTP/2: multiplexe os fluxos em um único TCP; menos conectórios, mas é possível TER-blocking em TCP quando perder pacotes.
HTTP/3 (QUIC): O streaming é independente do UDP - menos problemas HOL, mais rápido que os primeiros bytes.
- keep-alive timeout 30-90s (por perfil), limite de solicitação de conectório (graceful recyple).
- Preconnect (preconnect) ao iniciar o worker.
- Limite o fluxo máximo para HTTP/2 (por exemplo, 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) Pula BD: PgBouncer, HikariCP, drivers
O objetivo é limitar as transações competitivas e manter o conectório curto.
5. 1 PgBouncer (PostgreSQL)
Modos: 'sessions '/' direction '/' statement'. Para API, é mais frequente.
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)
Conectórios pequenos, rápidos, times duros.
properties dataSourceClassName=org. postgresql. ds. PGSimpleDataSource maximumPoolSize=30 minimumIdle=5 connectionTimeout=250 validationTimeout=200 idleTimeout=30000 maxLifetime=1800000 leakDetectionThreshold=5000
Regras:
- `maximumPoolSize ≈ RPS × W × headroom`.
- Centenas de milissegundos, não segundos.
- Ative o leak detation.
5. 3 Go/Node/Python - exemplos
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) Filas de espera e tail-latency
As caudas surgem quando:- O pool é menor do que '£ x W' → cresce a fila de espera do conector.
- Irregularidade de carga (bursts) sem tampão ou limite.
- Longas solicitações ocupam o conector e criam o HOL.
- Divida os grupos por tipo de consulta (rápido/lento).
- Implemente o tempo de espera do conector (cliente-side). Se expirou, NACK rápido.
- Outlier detation e circuito-breaking em rotas (Envoy, HAProxy).
- Quotas de rotas «pesadas», pool separado para relatórios/exportações.
yaml circuit_breakers:
thresholds:
- priority: DEFAULT max_connections: 200 max_pending_requests: 100 max_requests: 1000 max_retries: 2
7) Timeouts e retais (ordem correta)
1. Connect timeout (curto: 50-250 ms dentro do DC).
2. TLS handshake timeout (500–1000 ms вне DC).
3. Request/Read timeout (próximo da rota SLO).
4. Retry: no máximo 1 vez, apenas para métodos idumpotentes; jitter + backoff.
5. Budet em retraí: limite global de porcentagem de RPS (por exemplo, ≤ 10%).
8) Keep-alive, Nagle, protocolos
Desabilite o Nagle (TCP _ NODELAY) para RPC com mensagens pequenas.
Inclua HTTP keep-alive sempre que possível.
Só siga TIME _ WAIT - tune 'reuse '/' recyple' se entender as consequências; melhor: Reuse os conectórios, em vez de sintonizar o núcleo.
TLS: Use a sessão de resposta e ALPN.
9) OS/Kernel sintonizar (com cautela)
`net. core. somaxconn`, `net. ipv4. ip_local_port_range`, `net. ipv4. tcp_fin_timeout`.
Descriptor: 'nofile' ≥ 64k para processo proxy.
Balanço IRQ, GRO/LRO - por perfil de tráfego.
A prioridade é perfilar; sintonizar sem métricas muitas vezes faz mal.
10) Observabilidade: o que medir
Pool utilization: ocupado/total, p50/p95 espera conector.
In-flight solicitações e seus hold-time (cortes sobre rotas).
Error budget retrações: proporção de repetições.
Connect churn: criar/fechar 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) Receitas de mala
11. 1 gateway API → backend
HTTP/2 para backends, 'max _ concurrent _ streams = 200'.
Um pool de 20 a 40 conectórios para o nó da entrada.
Temporizações: connect 100ms, per-try 300-500ms, total 1-2s, 1 retry com jitter.
11. 2 Serviço → PostgreSQL através de PgBouncer
'pool _ modo = transformation', 'default _ pool _ size' com a fórmula (RPS x W x 1. 3).
No aplicativo «connectionTimeout≤250ms», transações curtas (<100ms).
As consultas de relatório pesadas são um pool/réplica separado.
11. 3 gRPC interior
Um canal (HTTP/2) por anfitrião de destino com limite de fluxo 100-200.
Deadline em RPC rota SLO, retraí apenas idempotent.
Sampling trailers para RPC longo e métricas hold-time.
12) Folha de cheque de implementação (0-30 dias)
0-7 dias
Mede 'W' (hold-time) nas principais rotas/clientes.
Calcule 'N _ min = £ x W' e adicione 30% a 50% headroom.
Ative o keep-alive e os curtos tempos de espera do conector.
8 a 20 dias
Divida as balas (rápidas/lentas/externas).
Digite os circuitos-breakers e budgets retraes.
Adicione dashboards: pool wait p95, reuse ratio, in-flight.
21-30 dias
A carga de trabalho dos buracos, o teste de caos da queda do Backand.
Otimização por cauda: isolamento de trajetos pesados, cachês locais.
Documente fórmulas e limites no runbook 'ax.
13) Anti-pattern
Tamanho do pool «ao acaso» e falta de headroom.
Grandes tempos de espera do conector → longas caudas em vez de falhas rápidas.
Muitas retrações sem jitter e idempotação → tempestade.
Um pool compartilhado para todos os tipos de solicitação.
Transações longas mantêm o conector (DB) → o starvation dos outros.
Keep-alive desativado ou limites de idle-churn muito pequenos e crescimento TTFB.
14) Métricas de maturidade
Pool wait p95 em venda <10% do p95 total.
Reuse ratio (> 90% para HTTP interno;> 80% para HTTP externo).
DB txn time p95 < 100–200 ms; proporção de transações longas <1%.
Retry rate <5% (e ≤ budet), erros devido a timeouts são estáveis e previsíveis.
Cálculo documentado do pool para todos os clientes críticos.
15) Conclusão
Uma conexão de pooling eficiente é a engenharia de filas + disciplina de temporizações. Mede 'W', calcule o pool '£ x W' com a reserva, inclua keep-alive/HTTP2 +, separe caminhos lentos, mantenha o tempo curto e retais mínimos com jitter. Adicione a observabilidade de «pool wait vs latency» e circuito-breakers - e você terá um TTFB baixo, cauda de p99 controlada e resistência a picos sem superaquecimento de backends.