Devre Kesici ve Retreats
Devre Kesici ve Retrai
1) Neden ihtiyacınız var
Ağlar güvenilmezdir: gecikme titreşimleri, düğümler düşer, sınırlara ulaşılır. Retrays kısa süreli arızalardan kurtarılır ve Devre Kesici sistemi basamaklı arızalardan ve kendi kendine DDoS'den korur. Doğru zaman aşımları ve sınırlar ile kombinasyon SLO'yu korur, kuyruk gecikmelerini ve "dokuzların" fiyatını dengeler.
2) Temel ilkeler
Önce mola, sonra geri çekilme, sonra devre kesici.
Retraim sadece idempotent işlemleri (GET, idempotent anahtar ile güvenli POST/PUT).
Yeniden ödeme bütçesi ayırın: Rota başına orijinal RPS'nin ≤ %10-15'i.
Başarısızlığı yerelleştirin: bölme (ayrı havuzlar/kotalar) + oran sınırı.
Bozunma sırasında - hızlı başarısızlık (fail-fast), zarif bozunma/saplama.
3) Retray semantiği
Ne zaman geri çekilmeli
Geçici hatalar: zaman aşımları, 5xx, ağ kullanılamaması, 429 ('Retry-After'dan sonra).
Geri çekemezsiniz: bariz iş hataları (4xx ≠ 429), idempotans olmadan yan etkiler (anahtarsız ödeme).
Stratejiler
Üstel geri çekilme + jitter (tam veya çift): Retrace sürülerini yumuşatır.
Maksimum girişimler: 1-2 (nadiren 3) - daha fazlası genellikle zararlıdır.
Bütçe: Hizmet başına global geri ödeme sayacı/sn ve istek başına "yeniden deneme belirteçleri".
Hedging (nadir): t-quantile (p95) sonra isteğin paralel çift - sadece kesinlikle idempotent okumalar için.
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) Zaman aşımları ve "hızlı başarısızlık"
İstemci zaman aşımı <upstream timeout: "zombi" isteklerini biriktirmemek için.
Делите: bağlantı zaman aşımı, okuma zaman aşımı, genel son tarih.
Kuyruğa duyarlı zaman aşımları: p95/p99 + küçük marjı hedefleyin.
Ortak bir son tarih alanı kullanın (örneğin, gRPC 'son tarih') ve zincirden aşağı atın.
5) Devre Kesici: Nasıl çalışır
Durumlar:- Kapalı: trafiği geçer, hataları/gecikmeyi sayar.
- Açık: hemen hızlı bir reddetme (veya yedek cevap) verir.
- Yarı Açık: test sorguları; Başarılı olursa kapanır.
- Hatalar/zaman aşımları pencere başına % X'i aşar N istekler/saniye veya eşiğin üzerinde p99.
- Yuvarlanma istatistikleri ve minimum hacim önemlidir (örneğin, ≥ 50 sorguları).
6) Bulkhead, kotalar ve böl ve fethet
Yukarı akış ve özellik bağlantıları için ayrı havuzlar.
Uçuş içi talepler için kotalar; Gereksiz - hızlı reddetme.
Eksiklik durumunda - özellik bayraklarının bozulması.
7) Çevre entegrasyonu (Elçi/Istio/Nginx)
Elçi (retry + outlier + CB, fikir):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 (VirtualService hatası/yeniden deneme, sıkıştırılmış örnek):
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 Giriş (ek açıklamalar):
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) Kütüphaneler ve kod (yığın parçacıkları)
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();
Git (bağlam son tarihi + geri alma):
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() }
Düğüm noktası. 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) Retray ve SLO bütçesi
Tip yeniden deneme belirteçleri: Her retray bir belirteç harcar; Havuz sınırlıdır.
Hata bütçesiyle ilişkilendirme: yanma oranı eşiğin üzerindeyse, geri izlemeleri kapatın, CB'yi daha sık açın, bozulmayı açın.
Kanarya bültenleri: Kanaryalarda, girişimleri ve belirteçleri azaltın.
10) Korunma (dikkat)
P95 son tarihinden sonra ek bir istek çalıştırın ve kaybedeni iptal edin.
Sadece okuma ve "güvenli" idempotent işlemleri için; Payı sınırlayın (≤ %1-5).
Yukarı yöndeki yükün artışına dikkat edin.
11) Gözlemlenebilirlik
Rotalar boyunca RED ölçümleri: Oran, Hata, Süre (p50/p95/p99).
CB metrikleri: durum (açık/yarı açık), açılış oranı, cevapsız/reddedilen istekler.
Retrays: girişimler/istek, yeniden deneme oranı, yanmış belirteçler.
Çevre: aykırı fırlatma, fırlatma hızı.
İzler: 'retry _ entry', 'cb _ state', 'hedged = true', cast 'trace _ id'.
12) Mimari entegrasyon
Her kritik yukarı akış için Bulkhead + CB.
Kuyruklar/asynchron: çılgın zaman aşımları yerine uzun işlemler için.
Önbellek/taslaklar: arıza açıkken kritik olmayan özellikler için.
Autoscale: Kötü geri çekilmeleri telafi etmez - önce fırtınayı durdurun.
13) Anti-desenler
Zaman aşımı olmayan Retrays - donmuş bağlantılar ve havuzların tükenmesi.
Idempotent olmayan işlemleri tekrarlayın (çift yazma-off).
Cap ve jitter olmadan sonsuz üstel büyüme.
Tüm upstream için tek bir CB - tüm ürünün başarısızlığını sürükleyin ve bırakın.
429/' Retry-After 'yoksayılıyor.
İstemci zaman aşımı, yukarı akıştan daha uzundur (veya hiç değildir).
İş hatalarını retras ile "tedavi edin".
14) Uygulama kontrol listesi (0-30 gün)
0-7 gün
Yolları ve idempotensitelerini tanımlayın.
Zaman aşımlarını ayarlayın (bağlayın/okuyun/genel olarak), minimum geri çekilmeleri (× 1) ve varsayılan CB'yi etkinleştirin.
Ana yukarı akış için havuzları/kotaları (bölme) ayırın.
8-20 gün
Jitter ve global retray bütçesini, retry-rate uyarılarını ekleyin.
Çevre üzerinde outlier-ejection, düşük prio özelliği için hızlı başarısızlık yapılandırın.
KIRMIZI + CB/Yeniden deneme panoları, etiketli yollar.
21-30 gün
Kanarya retray profilleri (daha az deneme), oyun günü "upstream slow/flaps".
Belge politikası: kim/ne geri çekilir, sınırlar, istisnalar.
P95/p99 ve zaman aşımlarını verilere göre gözden geçirin, gözle değil.
15) Olgunluk metrikleri
Rotaların %100'ünde zaman aşımları ve belgelenmiş yeniden ödeme/NE politikası vardır.
Yeniden deneme oranı bütçeye uyuyor (≤ %10-15), olaylarda ani bir artış yok.
Tüm havuz düşmeden önce CB'ler ateş eder; basamaklı hata yok.
Yollar girişimleri/hedging gösterir; P99 zirvelerde stabildir.
Kanarya sürümleri "dikkatli'bir yeniden ödeme profili kullanır.
16) Kısa yapılandırma örnekleri
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
Elçi oran sınırı (fikir parçası):
yaml rate_limits:
- actions:
- generic_key: { descriptor_value: "api. payments" }
17) Sonuç
Sürdürülebilirlik bir disiplindir: zaman aşımları - geri çekilmeler (jitter ve bütçe ile) - Devre Kesici + bölme/kotalar ve hızlı reddetme. Bir çevre (outlier-ejection) ayarlayın, RED/CB/Retry panolarını kapatın, idempotency politikasını düzeltin ve iş SLI'sini unutmayın. O zaman kısa başarısızlıklar görünmez kalır ve gerçek olaylar basamaklı düşüşlere dönüşmez.