Sterowanie układem Timeout
1) Dlaczego go potrzebujesz
Systemy spadają nie z jednej „śmiertelnej” awarii, ale z nagromadzenia opóźnień i „fali” powtórzeń. Terminy ograniczają czas oczekiwania i wolne zasoby, a kontrola obwodów (wyłącznik + przelanie + konkurencja adaptacyjna) zapobiega rozprzestrzenianiu się degradacji wzdłuż łańcucha zależności. Celem jest utrzymanie p95/p99 w granicach docelowych i utrzymanie dostępności dla częściowych awarii.
2) Podstawowe definicje
2. 1 Rodzaje terminów (L7/L4)
Connect timeout - Nawiązanie połączenia TCP/TLS.
TLS/Shake timeout - uściski dłoni TLS/HTTP2 preface.
Zapisz czas - wyślij prośbę (w tym ciało).
Przeczytaj czas - poczekaj na pierwszy bajt odpowiedzi i/lub całego ciała.
Idle/Keep-Alive timeout - nieaktywne połączenie.
Ogólny termin - „trudny” termin dla całego wniosku (end-to-end).
2. 2 Budżet terminowy
Wybierz cel „deadline _ total” i podziel przez etapy:- 'ingress (gateway) + authZ + app + DB/cache + outbound PSP'.
- brama: 30 ms,
- zastosowanie: 120 ms,
- DB: 120 ms,
- PSP: 100 ms,
- margines: 30 ms.
2. 3 Rozmnażanie i unieważnianie
„deadline ”/„ timeout” należy przekazywać w łańcuchu (kontekst, nagłówki, gRPC Deadline). W momencie wygaśnięcia - anuluj operacje w tle (abort/ctx anuluj), wyczyść zamki/semafory.
3) Wyznaczanie terminów
1. Odgórnie: w oparciu o SLO i p95 - ustawić ostateczny termin, a następnie podzielić na podczasy.
2. Identyfikuj „drogie” ścieżki (pliki do pobrania, raporty, zewnętrzne PSP) - indywidualne dłuższe, ale ograniczone.
- idempotent (GET/powtórzenia stanu) - krótszy, bardziej agresywny;
- napisz/monetarne - nieco dłuższe, ale z pojedynczym powtórzeniem i idempotencją.
4. Stopniowanie przez plany/najemców (przedsiębiorstwo może mieć dłuższy czas, ale mniej równoległości).
4) Wyłącznik: modele i parametry
4. 1 Polityka uruchamiająca
Wskaźnik awarii - wskaźnik błędu ≥ X% w oknie zapytania/czasu N.
Awarie następcze: M kolejne awarie.
Tempo powolnego wywoływania - odsetek połączeń dłuższy niż próg T.
Klasy błędów: timeouts/5xx/connection-reset → „fatal”, 4xx - nie uwzględniaj.
4. 2 Warunki
Zamknięte - pomija wszystko, gromadzi statystyki.
Open - błyskawiczna awaria (oszczędza zasoby, nie niszczy zależności).
Półotwarte - małe „próbki” (żądania N) do „badania wody”.
4. 3 Przydatne dodatki
Grodzisko: pula wątków/połączeń na zależność, aby nie „wyssać” wszystkiego.
Jednoczesność adaptacyjna: automatyczne ograniczenie jednoczesności (algorytmy podobne do AIMD/Vegas) przez obserwowaną opóźnienie.
Load Shedding: wczesna awaria/degradacja w przypadku braku zasobów lokalnych (kolejki, procesor, pauzy GC).
5) Interakcja: czas, rekolekcje, limity
Pierwszy termin, następnie przekwalifikować: każde powtórzenie powinno pasować do wspólnego terminu.
Backoff + jitter na powtórki; szacunek dla „Retry-After” i retry-budget.
Ograniczenie prędkości: Z otwartym wyłącznikiem - niższe limity, aby nie nasilać burzy.
Idempotencja: obowiązkowe w operacjach pisania (aby uniknąć bierze z „głupich” timeouts).
Gdzie schować: najlepiej na krawędzi (klient/brama), a nie głęboko w środku.
6) Praktyczne wartości docelowe (wartości odniesienia)
Publiczne czytanie API: end-to-end '200-500 ms', czytaj timeout '100-300 ms'.
Pismo krytyczne (płatności): „300-800 ms” e2e; zewnętrzny PSP ≤ '250-400 ms'.
Connect/TLS: '50-150 ms' (więcej - problem z siecią/lutowaniem).
Bezczynność: '30-90 s' (klienci mobilni - krótszy, aby zapisać baterię).
Dostosować wartości dla p95/p99 i regionów.
7) Konfiguracje i przykłady
7. 1 Wysłannik (gromada + trasa, pseudo)
yaml clusters:
- name: payments_psp connect_timeout: 100ms type: STRICT_DNS lb_policy: ROUND_ROBIN circuit_breakers:
thresholds:
- priority: DEFAULT max_connections: 2000 max_requests: 2000 max_retries: 50 outlier_detection:
consecutive_5xx: 5 interval: 5s base_ejection_time: 30s max_ejection_percent: 50
routes:
- match: { prefix: "/api/v1/payments" }
route:
cluster: payments_psp timeout: 350ms # per-request deadline idle_timeout: 30s retry_policy:
retry_on: "reset,connect-failure,refused-stream,5xx,gateways"
num_retries: 1 per_try_timeout: 200ms
7. 2 NGINX (obwód)
nginx proxy_connect_timeout 100ms;
proxy_send_timeout 200ms; # write proxy_read_timeout 300ms; # read (первый байт/все тело)
keepalive_timeout 30s;
send_timeout 15s;
Быстрый отказ при перегрузке limit_conn_zone $binary_remote_addr zone=addr:10m;
limit_conn addr 50;
7. 3 gRPC (klient, Go-pseudo)
go ctx, cancel:= context.WithTimeout(context.Background(), 350time.Millisecond)
defer cancel()
resp, err:= client.Pay(ctx, req) // Deadline передается вниз
7. 4 klient HTTP (Go)
go client:= &http.Client{
Timeout: 350 time.Millisecond, // общий дедлайн на запрос
Transport: &http.Transport{
TLSHandshakeTimeout: 100 time.Millisecond,
ResponseHeaderTimeout: 250 time.Millisecond,
IdleConnTimeout: 30 time.Second,
MaxIdleConnsPerHost: 100,
},
}
7. 5 Resilience4j (Jawa, pseudo)
yaml resilience4j.circuitbreaker.instances.psp:
slidingWindowType: TIME_BASED slidingWindowSize: 60 failureRateThreshold: 50 slowCallDurationThreshold: 200ms slowCallRateThreshold: 30 permittedNumberOfCallsInHalfOpenState: 5 waitDurationInOpenState: 30s
resilience4j.timelimiter.instances.psp:
timeoutDuration: 350ms
8) Obserwowalność i ostrzeganie
8. 1 Metryka
'http _ client _ requests {endpoint, status}', 'client _ latency _ bucket'
8. 2 Szlaki
Przęsła: ingress → handler → DB/Redis → zewnętrzne.
Atrybuty: 'timeout _ ms _ target', 'circuit _ state', 'queue _ time _ ms'.
Przykłady: piki Tie p99 do określonego śladu-id.
8. 3 Wpisy
'p99 _ latency {critical}'> cele X minut z rzędu.
'timeout _ rate {dependence}' skakany> Y%.
Częste przejścia do wyłącznika „open ”/„ flapping”.
Wzrost 'completed _ requests _ total' z wysokim procesorem/GC.
9) Adaptacyjne równoległości i rozrzucanie obciążenia
9. 1 Pomysł
Automatyzacja zmniejsza paralelizm, gdy rosną ogony opóźnienia:- AIMD: powoli wzrasta, gwałtownie się zmniejsza.
- Vegas-jak: zachować czas kolejki.
- Token-based: każde żądanie „spala” token; żetony są wydawane na podstawie zmierzonej prędkości.
9. 2 Realizacja
lokalne semafory na jedną trasę; celem jest utrzymanie „queue _ time” poniżej progu.
Globalny „bezpiecznik” (marginalny RPS/konkurencyjny) na bramie.
Jeśli wystąpi niedobór procesora/połączeń, wczesna awaria przed wykonaniem logiki (429/503 z 'Retry-After').
10) Testowanie i scenariusze chaosu
Zastrzyk opóźnienia: sztucznie dodać 50-300 ms na zależność.
Utrata pakietu/kropla/kropla (tc/tbf, toksyproksy).
Obracanie pokrętła: zmniejszyć pulę połączeń, zwiększyć obciążenie do nasycenia.
Zabić/zdegradować jedną strefę/odłamek (częściowa niedostępność).
Kontrole: nie „zawodzi” burza retray; wyłącznik otwiera się przewidywalnie; czy kolejka rośnie.
11) Antypattery
Jeden globalny „read timeout” bez szczegółów connect/TLS/per-stage.
Brak wspólnego terminu → przekaźniki wykracza poza SLO.
Retrai bez jitter i bez retry-budget.
„Wieczne” połączenia bez bezczynnych czasów → wyciek deskryptorów.
Breaker liczy 4xx jako śmiertelne błędy.
Nie cofnij/przerwij → praca w tle trwa po upływie czasu klienta.
Terminy są zbyt długie dla sieci mobilnych/niestabilnych.
12) Szczegóły dotyczące iGaming/Finance
Krytyczny zapis (depozyty/wyjścia): jedno krótkie powtórzenie z Idempotence-Key, a następnie '202 Accepted' + sondaż zamiast nieskończonych oczekiwań.
PSP/bankowość: odrębne zasady według dostawcy/regionu (niektóre wolniej).
Odpowiedzialne płatności i limity: dla zamków/recenzji - szybkie '423/409', nie rozciągać „wiszące” transakcje.
Raportowanie/agregacja - uruchom asynchronicznie (zasób partii + stanu).
13) Lista kontrolna gotowości Prod
- Ostateczny krytyczny termin trasy (GET/POST) określony.
- Zapisane w budżecie według etapów; możliwe jest propagowanie terminów.
- Connect/TLS/read/write/idle configs on gateway and clients.
- Wyłącznik z szybkością awarii i progami powolnego wywoływania; Poprawna logika w połowie otwarta.
- Grodzie od zależności; granice jednoczesności na trasie.
- Przeładowanie przed wykonaniem logiki biznesowej podczas przeciążenia.
- Integracja z rekolekcjami: backoff + jitter, retry-budget, respect „Retry-After”.
- Idempotence write, „Idempotency-Key” i outbox for events.
- Metryki: timeout/slow-call/breaker/queue time/competitive.
- Testy chaosu: wtrysk opóźnień/strat/awarii, degradacja stref.
- Dokumentacja klienta: przykładowe terminy, kody odpowiedzi, wskazówki dotyczące powtórzenia.
14) TL; DR
Daj każdemu żądaniu twardy termin, ułożyć go etapami i rozłożyć w dół łańcucha. Zarządzanie usterkami za pomocą wyłącznika + grodzi + adaptacyjne równoległości + przesuwanie obciążenia. Powtórki - tylko w terminie, z jitter i budżetu; pisać - idempotent tylko. Zmierzyć czas/powolne wywołanie, stan wyłącznika i 'kolejka _ czas', regularnie prowadzić testy chaosu.