Puli połączeń i opóźnienia
Puli połączeń i opóźnienia
1) Dlaczego baseny są potrzebne
Połączenia są drogie (uściski dłoni TCP/TLS, uwierzytelnianie, rozgrzewka). Pula umożliwia:- Ponowne użycie gotowych połączeń (utrzymać przy życiu) → poniżej TTFB.
- Kontrolować współistnienie i nadać odwrotne ciśnienie zamiast lawiny rekolekcji.
- Zmniejszyć ogony p95/p99 ze względu na prawidłowy rozmiar i harmonogram.
Kluczowe ryzyko: kolejki oczekujących w basenie, blokowanie głowy linii, zawartość połączeń i burza rekolekcji.
2) Podstawa matematyczna: Jak policzyć rozmiar puli
Używamy prawa Little'a: 'L = α × W'. W przypadku puli oznacza to:- „na” oznacza średni strumień żądań (RPS).
- „W” oznacza średnie połączenie zajęte na żądanie (czas obsługi, w tym opóźnienie sieci i obsługa zdalna).
- Minimalny rozmiar puli to 'N _ min, I × W'.
- Dodaj margines dla zmian i p99: zagłówek 20-50%.
- Przykład: 300 RPS, średni czas wstrzymania 40 ms → 'N _ min = 300 × 0. 04 = 12`. Z marginesem 50%, 18 połączeń są →.
Jeśli ogony są duże: rozważyć 'W _ p95' lub 'W _ p99' dla ścieżek krytycznych - baseny rosną.
3) Ogólne zasady projektowania
1. Krótka ścieżka danych: ponowne użycie (utrzymanie przy życiu, HTTP/2/3 multipleksowanie).
2. Ograniczenie paralelizmu: lepiej szybko odmówić (429/503) niż usmażyć plecy.
3. Timeouts> rekolekcje: Ustaw małe czasowe i rzadkie rekolekcje jitter.
4. Kolejki klientów są krótsze niż kolejki serwerów (szybka awaria).
5. Backpressure: gdy pula jest pełna - natychmiast NACK/błąd/collbeck „później”.
6. Izolacja basenów według celów: DB, pamięć podręczna, zewnętrzny PSP - ich granice.
4) HTTP/1. 1 vs HTTP/2/3, utrzymać przy życiu
HTTP/1. 1: jedno żądanie połączenia na raz (praktycznie); potrzebuje puli z wieloma połączeniami na hosta.
HTTP/2: multipleksowanie strumienia w jednym TCP; mniej połączeń, ale blokowanie HOL na TCP jest możliwe, gdy pakiety są tracone.
HTTP/3 (QUIC): strumieniowanie niezależności od UDP - mniej problemów z HOL, szybsze pierwsze bajty.
- utrzymać żywy czas 30-90 lat (według profilu), limit wniosków o podłączenie (wdzięczny recykling).
- Wstępne ogrzewanie (preconnect) na początku pracy.
- Ograniczyć maksymalne przepływy na HTTP/2 (np. 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 "";
Wysłannik (pula HTTP/2):
yaml http2_protocol_options:
max_concurrent_streams: 200 common_http_protocol_options:
idle_timeout: 60s max_connection_duration: 3600s
5) Baseny DB: PgBouncer, HikariCP, sterowniki
Celem jest ograniczenie konkurencyjnych transakcji i utrzymywanie krótkich łączy.
5. 1 PgBouncer (PostgreSQL)
Tryby: 'session '/' transaction '/' statement'. Dla API - częściej transakcja.
Ważnymi parametrami są '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 (Jawa)
Małe, szybkie połączenia, trudne czasy.
properties dataSourceClassName=org. postgresql. ds. PGSimpleDataSource maximumPoolSize=30 minimumIdle=5 connectionTimeout=250 validationTimeout=200 idleTimeout=30000 maxLifetime=1800000 leakDetectionThreshold=5000
Zasady:
- „maximumPoolSize z RPS × W × zagłówkiem”.
- "łączy Timeout 'hundreds milisekund, nie sekund.
- Włącz wykrywanie przecieków.
5. 3 Go/Node/Python - przykłady
Idź http. Klient (ponowne użycie + 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
}
Węzeł. js utrzymać czynnik żywy:
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) Kolejki oczekujące i opóźnienia ogona
Ogony występują, gdy:- Pula jest mniejsza niż '× W' → Kolejka połączeń rośnie.
- Nierówność obciążenia (wybuchy) bez bufora i ograniczeń.
- Długie żądania podejmują połączenie i tworzą HOL.
- Oddzielne puli według typu żądania (szybki/wolny).
- Wdrożenie harmonogramu po stronie klienta. W przypadku wygaśnięcia - szybki NACK.
- Wykrywanie i łamanie obwodów na trasach (wysłannik, HAProxy).
- Kontyngenty na „ciężkie” trasy, oddzielna pula sprawozdań/wywozu.
yaml circuit_breakers:
thresholds:
- priority: DEFAULT max_connections: 200 max_pending_requests: 100 max_requests: 1000 max_retries: 2
7) Terminy i rekolekcje (prawidłowa kolejność)
1. Podłącz czas (krótki: 50-250 ms wewnątrz DC).
2. TLS handshake timeout (500-1000 ms вна DC).
3. Żądanie/Przeczytaj czas (bliżej trasy SLO).
4. Retry: maksymalnie 1 czas, tylko dla metod idempotent; jitter + backoff.
5. Budżet retrospektywny: globalny limit procentowy RPS (na przykład ≤ 10%).
8) Utrzymaj się przy życiu, Nagle, protokoły
Wyłączyć Nagle (TCP_NODELAY) dla małych komunikatów RPC.
Włączanie HTTP w miarę możliwości.
Uważaj na TIME_WAIT - tune 'reuse '/' recycle' tylko wtedy, gdy rozumiesz konsekwencje; lepsze - ponowne użycie połączeń, a nie dostrajanie jądra.
TLS - Użyj wznowienia sesji i ALPN.
9) OS/Kernel tuning (z ostrożnością)
'net. rdzeń. somaxconn', 'net. ipv4. ip_local_port_range', "net. ipv4. tcp_fin_timeout'.
Deskryptory: 'nofile' ≥ 64 k na proces proxy.
Saldo IRQ, GRO/LRO - według profilu ruchu.
Priorytet - profil; dostrajanie bez metryk jest często szkodliwe.
10) Obserwowalność: co mierzyć
Wykorzystanie puli: zajęty/razem, połączenie p50/p95 w toku.
Żądania podczas lotu i ich czas wstrzymania (przekroje trasy).
Budżet błędu retrospektywnego: odsetek powtórzeń.
Połączenie churn Utwórz/Zamknij na sekundę.
TCP/TLS: SYN RTT, uściski dłoni, ponowne użycie sesji.
МлКА: aktywne połączenia, czekanie, długie transakcje, zamki.
Мрабика: „RPS vs pool wait”, „hold-time distribution”, „reuse ratio”, „circuit trips”.
11) Przepisy przypadku
11. 1 brama API → backend
HTTP/2 do backendów, 'max _ concurrent _ streams = 200'.
Basen 20-40 połączeń na usługę na węzeł bramy.
Timeouts: connect 100ms, per-try 300-500ms, shared 1-2s, 1 retry with jitter.
11. 2 PostgreSQL → usługa za pośrednictwem PgBouncer
'pool _ mode = transaction', 'default _ pool _ size' według wzoru (RPS × W × 1. 3).
W przypadku transakcji krótkoterminowych ≤ 250 ms (<100 ms).
Ciężkie zgłoszenia - oddzielna pula/replika.
11. 3 gRPC wewnętrzne
Jeden kanał (HTTP/2) na hosta docelowego z limitem gwintu 100-200.
Termin na RPC na trasie SLO, przekaźnik tylko idempotent.
Długie próbkowanie RPC i metryki czasowe.
12) Lista kontrolna realizacji (0-30 dni)
0-7 dni
Pomiar „W” (czas wstrzymania) na kluczowych trasach/klientach.
Oblicz 'N _ min = na × W' i dodaj 30-50% zagłówka.
Włącz utrzymać żywe i krótkie timeouts połączenia.
8-20 dni
Oddzielne puli (szybkie/wolne/zewnętrzne).
Wyłączniki typu i budżety przekaźnikowe.
Dodaj deski rozdzielcze: basen czekać p95, stosunek ponownego użycia, w locie.
21-30 dni
Ładunek działa z wybuchami, test chaosu „upadek pleców”.
Optymalizacja ogona: izolacja ciężkich tras, lokalnych buforów.
Wzory dokumentów i limity w książce startowej 'ax.
13) Anty-wzory
Rozmiar basenu „losowo” i bez zagłówka.
Duży czas oczekiwania połączenia → długie ogony zamiast szybkich awarii.
Wiele wycofuje się bez jittera i idempotencji → burza.
Jedna wspólna pula dla wszystkich typów zapytań.
Długie transakcje zachować połączenie (DB) → głód reszty.
Niepełnosprawni utrzymać przy życiu lub zbyt mały bezczynność → ograniczenia churn i wzrost TTFB.
14) Wskaźniki zapadalności
Pool poczekać p95 w prod <10% całkowitej trasy p95.
Współczynnik ponownego użycia (> 90% dla wewnętrznego HTTP;> 80% dla zewnętrznych).
DB txn czas p95 <100-200 ms; odsetek transakcji długich <1%.
Szybkość ponownej próby <5% (i ≤ budżetu), błędy spowodowane terminami są stabilne i przewidywalne.
Udokumentowane rozliczenie puli dla wszystkich klientów krytycznych.
15) Wniosek
Efektywne łączenie połączeń to inżynieria kolejki + dyscyplina timeout. Zmierzyć 'W', obliczyć pulę 'α × W' z marginesem, włączyć keep-alive/HTTP2 +, oddzielne powolne ścieżki, zachować krótkie czasy i minimalne retras z jitter. Dodaj „pool wait vs latency” obserwowalność i wyłączniki - i dostajesz niski TTFB, kontrolowany ogon p99 i opór przepięcia bez przegrzania drzwi.