GH GambleHub

Wyłącznik i rekolekcje

Wyłącznik i Retrai

1) Dlaczego go potrzebujesz

Sieci są niewiarygodne: pulsaty opóźnienia, spadają węzły, osiągają granice. Retrasy są zapisywane przed awariami krótkoterminowymi, a Circuit Breaker chroni system przed awariami kaskadowymi i samodzielnym DDoS. Połączenie z prawidłowymi terminami i limitami zachowuje SLO, stabilizuje opóźnienia ogona i cenę „dziewięciu”.

2) Podstawowe zasady

Najpierw czas, potem rekolekcje, potem wyłącznik.
Retraim tylko operacje idempotent (GET, bezpieczne POST/PUT z kluczem idempotent).
Przeznaczenie budżetu na przekwalifikowanie: ≤ 10-15% pierwotnego RPS na trasę.
Awaria lokalizacji: grodzie (oddzielne puli/kwoty) + limit stawki.
Podczas degradacji - szybka awaria (failil-fast), graceful-degradation/stub.

3) Semantyka retrasy

Kiedy się wycofać

Błędy przejściowe: timeouts, 5xx, niedostępność sieci, 429 (po 'Retry-After').
Nie można wycofać się: oczywiste błędy biznesowe (4xx, 429), skutki uboczne bez idempotencji (płatność bez klucza).

Strategie

Wykładnicze backoff + jitter (pełne lub równomierne): Wygładza roje retras.
Maksymalne próby: 1-2 (rzadko 3) - więcej jest zwykle szkodliwe.
Budżet: global retray counter/sec per service and per-request „retry tokens”.
Zabezpieczenie (rzadko): równoległe podwójne żądanie po t-kwantylu (p95) - tylko dla ściśle idempotent czyta.

Pseudokoda backoff + jitter:
python base = 100 # ms for attempt in range(1, max_attempts+1):
try:
return call()
except Transient as e:
if attempt == max_attempts: raise sleep_ms = min(cap_ms, base 2(attempt-1))
sleep(random(0, sleep_ms)) # full jitter

4) Timeouts i „szybka awaria”

Klient timeout <upstream timeout: aby nie gromadzić żądań „zombie”.
Делита: connect timeout, read timeout, overall deadline.
Timeouts: cel dla p95/p99 + mały margines.
Użyj wspólnego pola terminowego (na przykład „termin” gRPC) i zrzuć go w dół łańcucha.

5) Wyłącznik: Jak to działa

Państwa:
  • Zamknięte: przechodzi ruch, liczy błędy/opóźnienia.
  • Otwórz: natychmiast daje szybką odmowę (lub odpowiedź zapasową).
  • Half-Open: zapytania testowe; Jeśli się uda, zamyka się.
Próg otwarcia:
  • Błędy/timeouts przekraczają X% na okno N żądania/sekundy lub p99 powyżej progu.
  • Statystyki toczenia i minimalna objętość są istotne (na przykład ≥ 50 zapytań).

6) Grodzisko, kwoty oraz podział i podbój

Oddzielne baseny połączeń per-upstream i per-feature.
kontyngenty na wnioski w locie; zbędne - szybka odmowa.
W przypadku niedoboru - degradacja flag funkcyjnych.

7) Integracja obwodowa (wysłannik/Istio/Nginx)

Wysłannik (retry + outlier + CB, idea):
yaml routes:
- match: { prefix: "/api" }
route:
cluster: upstream_api timeout: 2s retry_policy:
retry_on: "connect-failure,reset,retriable-4xx,5xx"
num_retries: 2 per_try_timeout: 600ms retry_back_off: { base_interval: 100ms, max_interval: 800ms }
hedge_policy:
hedge_on_per_try_timeout: true initial_requests: 1 additional_request_chance: { numerator: 5, denominator: HUNDRED } # 5%
clusters:
- name: upstream_api circuit_breakers:
thresholds:
- priority: DEFAULT max_connections: 500 max_requests: 1000 max_retries: 200 outlier_detection:
consecutive_5xx: 5 interval: 5s base_ejection_time: 30s max_ejection_percent: 50
Istio (wirtualny błąd/retry usługi, przykład kompresji):
yaml apiVersion: networking. istio. io/v1beta1 kind: VirtualService spec:
hosts: ["payments"]
http:
- route: [{ destination: { host: payments } }]
timeout: 2s retries:
attempts: 2 perTryTimeout: 600ms retryOn: "5xx,connect-failure,refused-stream,reset"
Nginx Ingress (adnotacje):
yaml nginx. ingress. kubernetes. io/proxy-connect-timeout: "2"
nginx. ingress. kubernetes. io/proxy-read-timeout: "2"
nginx. ingress. kubernetes. io/proxy-next-upstream: "error timeout http_502 http_503 http_504"
nginx. ingress. kubernetes. io/proxy-next-upstream-tries: "2"

8) Biblioteki i kod (stos snippets)

Java (Resilience4j):
java var cb = CircuitBreaker. ofDefaults("psp");
var retry = Retry. of("psp-retry",
RetryConfig. custom()
.maxAttempts(2)
.waitDuration(Duration. ofMillis(200))
.intervalFunction(IntervalFunction. ofExponentialRandomBackoff(100, 2. 0, 0. 5) )//jitter
.retryExceptions(SocketTimeoutException. class, IOException. class)
.build());

Supplier<Response> decorated =
CircuitBreaker. decorateSupplier(cb,
Retry. decorateSupplier(retry, () -> client. call()));

return Try. ofSupplier(decorated)
.recover(BusinessException. class, fallback())
.get();
Go (termin kontekstowy + backoff):
go ctx, cancel:= context. WithTimeout(context. Background(), 2time. Second)
defer cancel()
var lastErr error for i:= 0; i < 2; i++ {
reqCtx, stop:= context. WithTimeout(ctx, 600time. Millisecond)
lastErr = call(reqCtx)
stop()
if lastErr == nil { break }
sleep:= time. Duration(rand. Intn(1<<uint(7+i))) time. Millisecond // full jitter time. Sleep(min(sleep, 800time. Millisecond))
}
if lastErr!= nil { return fastFail() }
Węzeł. js (got + p-retry):
js import pRetry from 'p-retry';
await pRetry(() => got(url, { timeout: { connect: 500, request: 2000 } }), {
retries: 2,
factor: 2,
randomize: true,
minTimeout: 100,
maxTimeout: 800,
onFailedAttempt: e => { if (isBusiness(e)) throw e; }
});

9) Budżet Retray i SLO

Typ żetony powtórne: Każdy retray wydaje token; pula jest ograniczona.
Powiązanie z budżetem błędów: jeśli prędkość spalania jest powyżej progu, wyłącz przekaźniki, otwórz BC częściej, włącz degradację.
Kanaryjskie wydania: Na kanarach, zmniejszyć próby i żetony.

10) Zabezpieczenie (ostrożność)

Uruchom dodatkowe żądanie po terminie p95, anulując przegranego.
Tylko dla odczytów i „bezpiecznych” operacji idempotentnych; ograniczyć udział (≤ 1-5%).
Uważaj na wzrost obciążenia w górnym biegu.

11) Obserwowalność

RED mierniki wzdłuż tras: Szybkość, Błąd, Czas trwania (p50/p95/p99).
Wskaźniki CB: status (otwarte/pół otwarte), szybkość otwarcia, brakujące/odrzucone wnioski.
Przekaźniki: próby/żądanie, powtórne, spalone żetony.
Obwód: wyrzut zewnętrzny, szybkość wyrzutu.
Ślady: adnotat 'retry _ attempt', 'cb _ state', 'hedged = true', cast 'trace _ id'.

12) Integracja architektury

Grodzie + BC dla każdego krytycznego w górnym biegu.
Kolejki/asynchron: dla długich operacji zamiast szalonych terminów.
Cache/stubs: dla funkcji nieistotnych przy otwarciu awaryjnym.
Autoscale: Nie nadrabia złych rekolekcji - najpierw zatrzymaj burzę.

13) Anty-wzory

Przekłady bez czasu → zamrożone połączenia i wyczerpanie basenów.
Powtarzaj transakcje niepodlegające idempotencjom (podwójne odpisy).
Nieskończony wzrost wykładniczy bez czapki i jitter.
Pojedynczy CB do wszystkich upstream → przeciągnij i upuść awarię całego produktu.
Ignorowanie 429/' Retry-After '.
Czas wyjścia klienta jest dłuższy niż w górnym biegu (lub wcale).
„Traktuj” błędy biznesowe z retras.

14) Lista kontrolna wdrażania (0-30 dni)

0-7 dni

Zidentyfikować trasy i ich idempotencję.
Ustawić czasy (podłączyć/odczytać/ogólnie), włączyć minimalne przekaźniki (× 1) i domyślny BC.
Oddzielić baseny/kwoty (grodziowe) dla głównego górnego biegu rzeki.

8-20 dni

Uwzględnij jitter i globalny budżet retray, alerty wsteczne.
Konfiguracja wyrzutni na obwodzie, szybka awaria dla funkcji low-prio.
Tablice rozdzielcze RED + CB/Retry, tagowane szlaki.

21-30 dni

Profile przekaźników kanaryjskich (mniej prób), gra-day „upstream slow/claps”.
Polityka dokumentu: kto/co powtarza, limity, wyjątki.
Sprawdź p95/p99 i terminy zgodnie z danymi, a nie oczami.

15) Wskaźniki zapadalności

100% tras ma harmonogram i udokumentowane zasady retray/NE.
Szybkość ponownej próby mieści się w budżecie (≤ 10-15%), w incydentach nie występują skoki.
CB ogień przed upadkiem całego basenu; żadnych awarii kaskadowych.
Szlaki pokazują próby/zabezpieczenia; p99 jest stabilny w szczytach.
Wydania kanaryjskie używają „ostrożnego” profilu retray.

16) Przykłady krótkiej konfiguracji

Resilience4j YAML (Spring Boot, идей):
yaml resilience4j:
circuitbreaker:
instances:
psp:
slidingWindowType: COUNT_BASED slidingWindowSize: 100 minimumNumberOfCalls: 50 failureRateThreshold: 50 waitDurationInOpenState: 30s permittedNumberOfCallsInHalfOpenState: 5 retry:
instances:
psp:
maxAttempts: 2 waitDuration: 200ms enableExponentialBackoff: true exponentialBackoffMultiplier: 2. 0 retryExceptions:
- java. net. SocketTimeoutException
- java. io. IOException
Limit stopy wysłannika (fragment pomysłu):
yaml rate_limits:
- actions:
- generic_key: { descriptor_value: "api. payments" }

17) Wniosek

Zrównoważony rozwój jest dyscypliną: timeouts → rekolekcje (z jitter i budżetu) → Wyłącznik obwodu + przegroda/kwoty i szybkie odrzucenie. Skonfigurować obwód (outlier-ejection), zawiesić deski rozdzielcze RED/CB/Retry, naprawić politykę idempotencji i nie zapomnij o biznesowym SLI. Wtedy krótkie porażki pozostaną niewidoczne, a prawdziwe incydenty nie zamienią się w upadki kaskadowe.

Contact

Skontaktuj się z nami

Napisz do nas w każdej sprawie — pytania, wsparcie, konsultacje.Zawsze jesteśmy gotowi pomóc!

Telegram
@Gamble_GC
Rozpocznij integrację

Email jest wymagany. Telegram lub WhatsApp są opcjonalne.

Twoje imię opcjonalne
Email opcjonalne
Temat opcjonalne
Wiadomość opcjonalne
Telegram opcjonalne
@
Jeśli podasz Telegram — odpowiemy także tam, oprócz emaila.
WhatsApp opcjonalne
Format: kod kraju i numer (np. +48XXXXXXXXX).

Klikając przycisk, wyrażasz zgodę na przetwarzanie swoich danych.