Wzorce odporności systemów
Circuit Breaker, Retry z Exponential Backoff, Bulkhead isolation, Backpressure — jak zapobiec cascade failure w mikrousługach.
6 kluczowych wzorców odporności
Każdy wzorzec rozwiązuje inny rodzaj awarii — od cascade failure przez wyczerpanie zasobów po przeciążenie consumer.
| Wzorzec | Problem | Mechanizm | Narzędzia | Overhead |
|---|---|---|---|---|
| Circuit Breaker | Cascade failure | Przerywanie żądań do awarii | Resilience4j, Polly, Istio | Niski |
| Retry + Backoff | Przejściowe awarie | Ponowne próby z delay | Resilience4j, Polly, tenacity | Niski-Średni |
| Timeout | Slow dependencies | Max czas oczekiwania | Wbudowany w HTTP clients | Minimalny |
| Bulkhead | Wyczerpanie zasobów | Izolacja thread pool/semaphore | Resilience4j, Hystrix, K8s Quotas | Średni |
| Fallback | Całkowita niedostępność | Alternatywna odpowiedź | Resilience4j, custom code | Zależy od fallback |
| Backpressure | Przeciążenie consumer | Sygnalizacja do producer | Reactor, RxJava, Kafka | Niski (reactive) |
Często zadawane pytania
Co to są wzorce odporności (Resilience Patterns) i dlaczego są kluczowe?
Resilience Patterns: wzorce projektowe zapewniające odporność systemów na awarie. W mikrousługach — cascade failure: jeden serwis pada, wywołuje chain reakcję i cały system pada. Cel wzorców odporności: izolacja awarii (failure isolation). Degradacja graceful (partial functionality zamiast full outage). Szybkie przywracanie. Kluczowe wzorce: Circuit Breaker: przerywa łańcuch wywołań do niedostępnego serwisu. Retry: ponów żądanie przy przejściowej awarii. Timeout: nie czekaj w nieskończoność. Bulkhead: izoluj zasoby per zależność. Fallback: alternatywna odpowiedź przy awarii. Rate Limiting/Throttling: chroń serwis przed przeciążeniem. Hedging: wyślij równoległe żądania, użyj pierwszej odpowiedzi. Backpressure: sygnalizuj upstream że nie możesz przetworzyć więcej. Gdzie stosować: między każdą parą serwisów w komunikacji synchronicznej. HTTP klient -> HTTP serwis. Message consumer -> external service call. Batch job -> external dependency. Narzędzia: Resilience4j (Java), Polly (.NET), go-resiliency (Go), Hystrix (Java, Netflix, deprecated), pybreaker (Python), tenacity (Python retry).
Circuit Breaker Pattern — jak działa i jak skonfigurować?
Circuit Breaker: naśladuje fizyczny bezpiecznik elektryczny. Stany: CLOSED (normalny) — żądania przechodzą. Liczy błędy. OPEN (awaria) — żądania blokowane natychmiastowo (nie czekają). Periodycznie próbuje half-open. HALF-OPEN (próba) — przepuszcza ograniczoną liczbę żądań. Jeśli sukces -> CLOSED. Jeśli błąd -> OPEN. Przejście CLOSED -> OPEN: sliding window (count lub time based). Count-based: 100 żądań, 50% failure rate. Time-based: ostatnie 10 sekund, 50% failure rate. Wait duration in open state: 30-60s standardowo. Slow calls: żądania które trwają za długo (np. > 2s) również liczone jako failures. Resilience4j konfiguracja: slidingWindowType COUNT_BASED. slidingWindowSize 10. failureRateThreshold 50. slowCallDurationThreshold 2000ms. slowCallRateThreshold 100. waitDurationInOpenState 30s. permittedNumberOfCallsInHalfOpenState 3. Fallback przy OPEN: return cached data. return default/empty response. redirect to backup service. throw degraded exception (graceful degradation). Metrics: resilience4j.circuitbreaker.{name}.state. transition events. call.failure.rate. Integracja: Spring Boot Actuator automatycznie eksponuje metryki. Prometheus + Grafana dashboard.
Retry Pattern — kiedy ponawiać i kiedy nie?
Retry: ponów żądanie przy przejściowej awarii. Nie wszystkie błędy są przejściowe. Retryable errors: 500 Internal Server Error (może być przejściowy). 503 Service Unavailable. Network timeout (connection reset). 429 Too Many Requests (z Retry-After). Non-retryable errors: 400 Bad Request (błąd klienta, retry nie pomoże). 401 Unauthorized (brak autentykacji, retry nie pomoże). 404 Not Found (zasób nie istnieje). 422 Unprocessable Entity. Retry strategies: Fixed Delay: czekaj 1s między próbami. Prosto ale retry storm. Exponential Backoff: 1s, 2s, 4s, 8s, 16s. Redukuje load na serwis. Exponential + Jitter: dodaj losowość. Bez jitter: wszystkie klienty czekają synchronicznie. Full Jitter: sleep = random(0, 2^attempt). Decorrelated Jitter (AWS): sleep = random(base, prev_sleep * 3). Max Retry attempts: 3-5 standardowo. Z Circuit Breaker: Circuit Breaker liczy failed retries. Retry budgets: globalny limit retry per czas (Google SRE). Idempotency wymagana: jeśli retry może powodować duplikaty -> endpoint musi być idempotentny. Resilience4j Retry: maxAttempts 3. waitDuration 500ms. exponentialBackoff multiplier 2. randomizedWaitFactor 0.5. retryExceptions [IOException, TimeoutException]. ignoreExceptions [BusinessException].
Bulkhead Pattern — izolacja zasobów?
Bulkhead: grodziowy system statku — każda komora izolowana. Awaria jednej komory nie topi całego statku. W systemach IT: izoluj thread pool / connection pool / semaphore per zależność. Bez Bulkhead: jeden slow external service zajmuje wszystkie wątki thread pool. Cały serwis niedostępny dla innych requestów. Z Bulkhead: każda zależność ma własny thread pool lub semaphore. Awaria jednej zależności nie wpływa na inne. Thread Pool Isolation: każda zewnętrzna zależność ma osobny thread pool. Hystrx thread pool isolation. Wada: overhead thread switching. Semaphore Isolation: limita liczby równoległych żądań do zależności. Lżejszy niż thread pool. Bez timeout per execution. Connection Pool Isolation: baza danych A — pool 10 połączeń. Baza danych B — pool 5 połączeń. Crash BD A nie wyczerpuje połączeń BD B. Resilience4j Bulkhead: maxConcurrentCalls 10 per dependency. maxWaitDuration 0ms (natychmiastowy błąd gdy pełny). Thread Pool Bulkhead: coreThreadPoolSize 2. maxThreadPoolSize 4. queueCapacity 2. keepAliveDuration 20ms. Kubernetes: Resource Quotas per namespace. Limit CPU/RAM per pod. PodDisruptionBudget. Service Mesh (Istio): connection pool per upstream service. maxConnections, pendingRequests, requests, retries.
Backpressure — jak sygnalizować przeciążenie w systemach reaktywnych?
Backpressure: mechanizm gdzie consumer informuje producer że nie może przetworzyć więcej danych. Przeciwieństwo push model (producer decyduje kiedy wysyłać). Pull model: consumer pobiera dane kiedy gotowy. Problem bez backpressure: producer produkuje szybciej niż consumer przetwarza. Bufory rosną -> OutOfMemoryError. Crash aplikacji. Backpressure strategie: DROP: odrzuć nowe dane gdy bufor pełny. ERROR: wyślij błąd do producera. LATEST: zachowaj tylko najnowsze dane. BUFFER: buforuj z limitem. BLOCK: blokuj producera. Reactive Streams (standard): Publisher -> Subscriber. request(N) — subscriber mówi ile może przetworzyć. onNext(), onError(), onComplete(). Project Reactor (Spring WebFlux): Flux/Mono z backpressure support. limitRate(), onBackpressureBuffer(), onBackpressureDrop(). RxJava: Flowable (backpressure-aware) vs Observable (bez). Backpressure operators: onBackpressureBuffer, onBackpressureDrop, onBackpressureLatest. Kafka Consumer: max.poll.records — ile rekordów per poll. pause()/resume() — dynamiczne wstrzymanie. Wstaw throttle gdy downstream wolny. gRPC streaming: flow control wbudowane (HTTP/2 flow control). Monitoring: queue depth metrics. Alerting gdy queue rośnie. Auto-scaling gdy persistently full queue.
Powiązane artykuły
Skontaktuj się z nami
Porozmawiajmy o Twoim projekcie. Bezpłatna wycena w ciągu 24 godzin.
Wyślij zapytanie
Telefon
+48 790 814 814
Pon-Pt: 9:00 - 18:00
adam@fotz.pl
Odpowiadamy w ciągu 24h
Adres
Plac Wolności 16
61-739 Poznań
Godziny pracy
Wolisz porozmawiać?
Zadzwoń teraz i porozmawiaj z naszym specjalistą o Twoim projekcie.
Zadzwoń teraz