Bazine de conectare și latență
Piscine de conexiune și latență
1) De ce sunt necesare piscine
Conexiunile sunt scumpe (strângeri de mână TCP/TLS, autentificare, încălzire). Piscina permite:- Reutilizați conexiunile gata preparate (păstrați în viață) → sub TTFB.
- Controlați concurența și dați backpressure în loc de o avalanșă de retrageri.
- Reduceți cozile p95/p99 datorită dimensiunii și timpilor corecți.
Riscuri cheie: cozi de așteptare în piscină, blocarea capului de linie, conținut pentru conexiuni și o furtună de retrageri.
2) Baza de matematică: Cum să numărați dimensiunea piscinei
Folosim legea Little: 'L = λ × W'. Pentru o piscină, aceasta înseamnă:- „λ” este fluxul mediu de cereri (SPR).
- „W” este conexiunea medie ocupată pe cerere (timpul de serviciu, inclusiv latența rețelei și funcționarea serviciului la distanță).
- Dimensiunea minimă a piscinei este 'N _ min ≈ λ × W'.
- Adăugați o marjă pentru variații și p99: înălțime 20-50%.
- Exemplu: 300 RPS, durata medie de așteptare 40 ms → 'N _ min = 300 × 0. 04 = 12`. Cu o marjă de 50%, sunt → 18 conexiuni.
Dacă cozile sunt mari: luați în considerare „W _ p95” sau „W _ p99” pentru căile critice - piscinele cresc.
3) Principii generale de proiectare
1. Cale de date scurtă: reutilizare (menținere în viață, multiplexare HTTP/2/3).
2. Limitarea paralelismului: este mai bine să refuzați rapid (429/503) decât să prăjiți backend-ul.
3. Timeouts> se retrage: Setați temporizări mici și retrageri rare jitter.
4. Cozile de client sunt mai scurte decât cozile de server (rapid fail-fast).
5. Rucsac: când piscina este plină - imediat NACK/eroare/collbeck „mai târziu”.
6. Izolarea bazinelor după ținte: DB, cache, PSP extern - limitele lor.
4) HTTP/1. 1 vs HTTP/2/3, păstrați-în viață
HTTP/1. 1: o singură cerere de conectare la un moment dat (practic); au nevoie de o piscină cu mai multe conexiuni pe gazdă.
HTTP/2: multiplexarea fluxului într-un singur TCP; mai puține conexiuni, dar blocarea HOL pe TCP este posibilă atunci când pachetele sunt pierdute.
HTTP/3 (QUIC): streaming independența față de UDP - mai puține probleme HOL, mai repede primii octeți.
- timp de viață 30-90 (după profil), limita cererilor de conectare (reciclare grațioasă).
- Preîncălzire (preconnect) la începutul lucrătorului.
- Limitarea fluxurilor maxime pe HTTP/2 (ex. 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 "";
Trimis (HTTP/2 pool):
yaml http2_protocol_options:
max_concurrent_streams: 200 common_http_protocol_options:
idle_timeout: 60s max_connection_duration: 3600s
5) Piscine DB: PgBouncer, HikariCP, drivere
Scopul este de a limita tranzacțiile competitive și de a păstra o conexiune scurtă deține.
5. 1 PgBouncer (PostgreSQL)
Moduri: „sesiune ”/„ tranzacție ”/„ declarație”. Pentru API - mai des tranzacție.
Parametrii importanți sunt '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)
Conexiuni mici, rapide, termene grele.
properties dataSourceClassName=org. postgresql. ds. PGSimpleDataSource maximumPoolSize=30 minimumIdle=5 connectionTimeout=250 validationTimeout=200 idleTimeout=30000 maxLifetime=1800000 leakDetectionThreshold=5000
Reguli:
- 'maximumPoolSize ≈ RPS × W × headroom'.
- 'conexiuneTimeout' hundreds de milisecunde, nu secunde.
- Activați detectarea scurgerilor.
5. 3 Go/Node/Python - exemple
Du-te http. Client (reutilizare + timeout):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
}
Nod. js agent de menţinere în viaţă:
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) Cozi de așteptare și coadă-latență
Cozile apar atunci când:- Piscina este mai mică decât „λ × W” → coada de conectare este în creștere.
- Încărcați denivelări (explozii) fără tampon și limite.
- Solicitările lungi preiau conexiunea și creează un HOL.
- Piscine separate după tipul de cerere (rapid/lent).
- Implementarea unui timeout client-side. Dacă expirat - rapid NACK.
- Detectarea și întreruperea circuitelor pe rute (Envoy, HAProxy).
- Cote pentru rutele „grele”, o rezervă separată pentru rapoarte/exporturi.
yaml circuit_breakers:
thresholds:
- priority: DEFAULT max_connections: 200 max_pending_requests: 100 max_requests: 1000 max_retries: 2
7) Timeout-uri și retrageri (ordinea corectă)
1. Conectați timpul de ieșire (scurt: 50-250 ms în interiorul DC).
2. TLS strângere de mână timeout (500-1000 ms вне DC).
3. Cerere/Citiți timeout (mai aproape de traseul SLO).
4. Retry: timp maxim 1, numai pentru metode idempotente; jitter + backoff.
5. Buget retras: limita globală ca procent din SPR (de exemplu, ≤ 10%).
8) Păstrați-în viață, Nagle, protocoale
Dezactivați Nagle (TCP_NODELAY) pentru RPC-uri cu mesaje mici.
Activați HTTP în viață ori de câte ori este posibil.
Urmăriți TIME_WAIT - reglați „reutilizarea ”/„ reciclarea” numai dacă înțelegeți consecințele; mai bine - reutilizați conexiunile, nu tuning kernel.
TLS - Utilizați reluarea sesiunii și ALPN.
9) OS/Kernel tuning (cu precauție)
"net. nucleu. somaxconn', "net. ipv4. ip_local_port_range', "net. ipv4. tcp_fin_timeout'.
Descriptori: „nofile” ≥ 64k pe proces proxy.
Echilibru IRQ, GRO/LRO - pe profil de trafic.
Prioritate - profil; reglarea fără valori este adesea dăunătoare.
10) Observabilitate: ce se măsoară
Utilizarea piscinei: ocupat/total, p50/p95 conexiune în așteptare.
Cereri în timpul zborului și timpul de așteptare al acestora (felii de rută).
Bugetul de eroare Retray: proporția de repetări.
Conectare Chorn Creare/Închidere pe secundă.
TCP/TLS: SYN RTT, strângeri de mână, reutilizarea sesiunii.
Для БД: conexiuni active, așteptare, tranzacții lungi, încuietori.
Графики: "RPS vs pool wait", "hold-time distribution", "reutilizare ratio", "circuit trips'.
11) Retete de caz
11. 1 gateway API → backend
HTTP/2 la backends, 'max _ concurent _ streams = 200'.
Un bazin de 20-40 conexiuni per serviciu pe nod gateway.
Timeout: conectați 100ms, pe încercare 300-500ms, partajate 1-2s, 1 încercați din nou cu jitter.
11. 2 Serviciu de → PostgreSQL prin PgBouncer
'pool _ mode = transaction', 'default _ pool _ size' by formula (RPS × W × 1. 3).
În „connectionTimeout≤250ms”, tranzacții scurte (<100ms).
Solicitări mari de raportare - piscină separată/replică.
11. 3 gRPC intern
Un canal (HTTP/2) pe gazdă țintă cu o limită de fir de 100-200.
Termen limită pe RPC pe ruta SLO, retraiți numai idempotent.
Prelevare lungă de urme RPC și măsurători de timp.
12) Lista de verificare a implementării (0-30 zile)
0-7 zile
Măsura „W” (timp de așteptare) pe rutele/clienții cheie.
Calculați 'N _ min = λ × W' și adăugați 30-50% înălțime.
Activați timpii de menținere în viață și scurte de conectare.
8-20 zile
Piscine separate (rapid/lent/extern).
Întreruptoare de tip și bugete de retractare.
Adăugați tablouri de bord: așteptați p95, reutilizați raportul, în zbor.
21-30 zile
Sarcina se execută cu explozii, test de haos „căderea backend-ului”.
Optimizarea cozii: izolarea rutelor grele, a cache-urilor locale.
Formulele și limitele documentului în runbook 'ax.
13) Anti-modele
Dimensiunea piscinei „la întâmplare” și nici o cameră de picioare.
Timp mare de așteptare a conexiunii → cozi lungi în loc de eșecuri rapide.
Mulți se retrag fără jitter și idempotență → o furtună.
O piscină comună pentru toate tipurile de cereri.
Tranzacțiile lungi păstrează conexiunea (DB) → înfometarea restului.
Cu handicap păstrează-în viață sau limite prea mici inactiv → Churn și creșterea TTFB.
14) Valorile maturității
Pool așteptați p95 în prod <10% din traseul total p95.
Rata de reutilizare (> 90% pentru HTTP intern;> 80% pentru extern).
DB txn timp p95 <100-200 ms; procentul tranzacțiilor lungi <1%.
Rata de reîncercare <5% (și bugetul ≤), erorile cauzate de timeout sunt stabile și previzibile.
Soluționare documentată a piscinei pentru toți clienții critici.
15) Concluzie
Punerea efectivă în comun a conexiunii este ingineria de coadă + disciplina timeout. Măsurați "W", calculați piscina "λ × W 'cu o marjă, activați keep-alive/HTTP2 +, trasee lente separate, păstrați timpii scurți și retras minim cu jitter. Adăugați observabilitatea și întrerupătoarele de circuit „pool wait vs latency” - și obțineți TTFB scăzut, coada controlată p99 și rezistența la supratensiune fără supraîncălzire.