Timeout, retry, exponential backoff ve circuit breaker nedir? Servisler arası çağrılarda nasıl birlikte kullanılır?
Cevap
Dağıtık sistemlerde bağımlı servisler er geç yavaşlar veya hata verir. Bu dört desen, bir servisin sorununun tüm sisteme yayılmasını (cascading failure) önler.
Timeout
Her ağ çağrısının bir üst süresi olmalıdır. Timeout'suz bir çağrı thread'leri ve bağlantıları sonsuza kadar tutar. Hem connect hem read/request timeout ayarlayın; değer, bağımlılığın normal p99 gecikmesinin biraz üzerinde olmalı. İstek zincirinde deadline aktarımı (kalan süreyi alt çağrılara iletmek) daha da iyidir.
Retry + exponential backoff + jitter
Geçici hatalar (timeout, 503, bağlantı reset) tekrar denenebilir; 400/401/404 gibi kalıcı hatalar denenmez. Yalnızca idempotent işlemler (veya idempotency key taşıyanlar) retry edilmelidir.
import random, time
def call_with_retry(fn, attempts=4, base=0.2, cap=5.0):
for i in range(attempts):
try:
return fn()
except TransientError:
if i == attempts - 1:
raise
sleep = random.uniform(0, min(cap, base * 2 ** i)) # full jitter
time.sleep(sleep)Jitter olmazsa tüm istemciler aynı anlarda tekrar dener ve toparlanmaya çalışan servisi yeniden çökertir. Retry'lar katman katman çarpılır (3 katman x 3 deneme = 27 çağrı), bu yüzden genelde tek katmanda retry yapın veya bir retry budget belirleyin.
Circuit breaker
Bir bağımlılığın hata oranı eşiği aşınca çağrıları bir süre hiç yapmadan hemen başarısız kılar.
| Durum | Davranış |
|---|---|
| Closed | Normal; hatalar sayılır |
| Open | Çağrılar yapılmaz, hemen hata veya fallback döner |
| Half-open | Süre dolunca birkaç deneme isteği geçer; başarılıysa Closed, değilse tekrar Open |
Faydası: sorunlu servise yük bindirmeyi bırakır, onun toparlanmasına izin verir ve çağıranın kaynaklarını (thread, bağlantı) korur.
Birlikte kullanım
Timeout her çağrıyı sınırlar → retry geçici hataları emer → circuit breaker kalıcı arızada retry fırtınasını keser → fallback (cache'teki son değer, varsayılan yanıt) kullanıcı deneyimini korur. Ek olarak bulkhead (bağımlılık başına ayrı thread/connection havuzu) bir bağımlılığın tüm kaynakları tüketmesini engeller.
Araçlar: Java'da Resilience4j, .NET'te Polly (Microsoft.Extensions.Http.Resilience), Node.js'te opossum; service mesh'ler (Istio) bunları altyapı seviyesinde de sunar.
İlgili Sistem Tasarımı soruları
- Mesaj kuyruğu (RabbitMQ, Kafka) ne zaman kullanılır?
- Monolith ile mikroservis mimarisi arasındaki fark nedir? Mikroservislere ne zaman geçilmeli?
- CAP teoremi nedir? Gerçek sistemlerde nasıl yorumlanır?
- Dikey ve yatay ölçekleme arasındaki fark nedir?
- Hangi cache stratejilerini biliyorsunuz?
- REST ile GraphQL arasındaki farklar nelerdir?
Bu konuda başka bir soru biliyor musun?
Mülakatta karşılaştığın soruları ekle, onaylandıktan sonra yayına alınsın.