İçeriğe geç
Muhammet Şafak
en
Güncelleme 3 dk okuma

Dış Servis Entegrasyonlarında Circuit Breaker

Kritik bir sistemi dış API'lere bağlarken: timeout, retry ve circuit breaker ile bir servisin çöküşünün tüm sistemi düşürmesini engellemek.

Kısaca

Yavaş bir dış servis, çökmüş birinden daha hızlı düşürür: çağrı process'i tutar, havuz dolar ve o servisle ilgisi olmayan endpoint'ler zaman aşımına uğramaya başlar. Sırayla üç savunma — her çağrıya açık ve kısa bir timeout, yalnızca exponential backoff ve jitter ile retry, ve hiç çağrı yapmamaya karar veren bir circuit breaker. Değerini, devre açıkken sunduğunuz fallback belirler.

Dış Servis Entegrasyonlarında Circuit Breaker — kapak görseli

Bir SMS sağlayıcısı yavaşladı — çökmedi bile, sadece yanıt süresi 30 saniyeye çıktı. Yarım saat içinde bütün uygulama yanıt veremez hâle geldi; SMS ile hiç ilgisi olmayan endpoint’ler bile zaman aşımına uğruyordu. Tek bir yavaş dış servis, koca sistemi birlikte aşağı çekmişti.

Bir dış servis er ya da geç çöker. Soru o değil. Soru şu: sizin sisteminiz onunla birlikte mi çökecek?

Zincirleme çöküş nasıl olur?

Mantık basit ve acımasız. Yavaş bir dış çağrı, onu yapan worker’ı — ya da PHP-FPM process’ini — kendine kilitler. Çağrı 30 saniye sürerse, o process 30 saniye boyunca başka hiçbir isteğe bakamaz.

İstekler birikir, process havuzu dolar. Havuz dolunca — SMS ile hiç ilgisi olmayanlar dâhil — yeni istekler de bekler. Sağlıklı endpoint’leriniz, hasta bir bağımlılık yüzünden ölür. Buna cascading failure denir ve neredeyse her zaman bir yavaşlamayla başlar.

İlk savunma: timeout

İlk ve en ucuz savunma, her dış çağrıya açık ve kısa bir timeout vermektir. Varsayılan timeout’lar — çoğu HTTP istemcisinde 30 saniye veya daha fazla — production için kabul edilemez.

$response = Http::timeout(5)        // toplam süre
    ->connectTimeout(2)             // bağlantı kurma süresi
    ->get('https://sms-provider.example/send');

Laravel queue yazısındaki kural burada da geçerli: varsayılan 30 saniye değil, 5. Bir process’in bir bağımlılığı ne kadar süre bekleyeceğini şansa bırakmayın — bu sayı bir karar olmalı.

İkinci savunma: retry — ama dikkatli

Geçici hatalar için retry mantıklıdır, ama körlemesine retry zarar verir. Çöken bir servisi hemen yeniden denemek ona daha çok yük bindirir — buna retry storm denir; servisi tam ayağa kalkamadan tekrar devirir.

Retry yapıyorsanız iki şey şart: exponential backoff (her denemede artan bekleme) ve jitter (rastgele sapma — tüm client’lar aynı anda denemesin).

Http::retry(3, function (int $attempt) {
    // exponential backoff (200, 400, 800 ms) ve üstüne jitter
    return 200 * (2 ** ($attempt - 1)) + random_int(0, 100);
}, function ($exception) {
    return $exception instanceof ConnectionException;
})->timeout(5)->get($url);

Retry sayısını düşük tutun. Üç denemeden sonra hâlâ hata varsa, sorun geçici değildir; denemeye devam etmek yalnızca kendi process’inizi daha uzun bağlar.

Üçüncü savunma: circuit breaker

Timeout tek bir çağrıyı sınırlar; circuit breaker çağrı yapmayı bırakmaya karar verir. Mantığı bir elektrik sigortasından gelir ve üç durumu vardır:

  • Closed — her şey normal, çağrılar geçer. Hatalar sayılır.
  • Open — son N çağrının çoğu başarısız oldu; devre açılır. Artık dış servise hiç gidilmez, çağrı anında hata döner.
  • Half-open — bir süre sonra devre tek bir deneme çağrısına izin verir. Başarılıysa closed’a döner, değilse tekrar open.

Kazanç şu: dış servis hastayken siz onu beklemezsiniz. 5 saniyelik timeout bile process başına 5 saniyedir; open durumda bu süre 0’a iner. Fail-fast, yavaş-fail’den iyidir.

// Kavramsal akış — eşik, sayaç ve zamanlayıcıyı olgun bir pakete bırakın.
if ($breaker->isOpen('sms')) {
    return $this->queueForLater($message);   // devre açık: hiç deneme yok
}

try {
    $response = Http::timeout(5)->post($smsUrl, $payload);
    $breaker->recordSuccess('sms');
} catch (\Throwable $e) {
    $breaker->recordFailure('sms');          // eşik aşılırsa devre açılır
    return $this->queueForLater($message);
}

Bu mantığı sıfırdan yazmak yerine olgun bir paket kullanın — durum saymayı, eşiği ve zamanlayıcıyı doğru kurmak göründüğünden inceliklidir.

Fallback: devre açıkken ne yapılır?

Circuit breaker’ın değeri, open durumda ne yaptığınızla ortaya çıkar. “Hata döndür” en zayıf seçenektir. Daha iyileri:

  • Kuyruğa al, sonra gönder. SMS hemen gitmek zorunda değilse, devre kapanınca işlenmek üzere kuyruğa bırakın.
  • Bayat ama geçerli veriyi sun. Bir döviz kuru servisi çökmüşse, son bilinen kuru göstermek hiç göstermemekten iyidir.
  • Özelliği zarifçe kıs. “Öneriler şu an yüklenemiyor” mesajı, koca sayfayı çökertmekten iyidir.

Hangi fallback’in doğru olduğu işe bağlıdır — ama “fallback yok” bir cevap değildir.

Ne zaman bu kadarına gerek yok?

Her dış çağrı circuit breaker istemez. Timeout her zaman şart. Retry, yalnızca işlem idempotent ise. Circuit breaker ise asıl olarak çağrı sık ve servis kullanıcı yolundayken değer katar — günde birkaç kez çağrılan bir entegrasyon için timeout ve makul bir retry çoğu zaman yeter.


Dış servis çökmesi bir “ihtimal” değil, bir “ne zaman” sorusudur. Onunla birlikte çökmek ise bir tasarım tercihidir — ve değiştirilebilir bir tercih.

Sisteminizi, en zayıf bağımlılığınız kadar kırılgan bırakmayın.

Sık sorulanlar

2 soru

  • Tek bir yavaş dış servis bütün uygulamayı nasıl düşürür?

    Yavaş çağrı, onu yapan worker'ı ya da PHP-FPM process'ini kilitler — 30 saniyelik bir çağrı, o process'in 30 saniye boyunca başka hiçbir şeye bakmaması demektir. İstekler birikir, process havuzu dolar ve havuz dolunca o servisle hiç ilgisi olmayan istekler de bekler. Cascading failure neredeyse her zaman bir çökmeyle değil, bir yavaşlamayla başlar.

  • Her dış çağrı circuit breaker ister mi?

    İstemez. Timeout her zaman şarttır. Retry yalnızca işlem idempotent ise ve yalnızca exponential backoff ile jitter eşliğinde yapılır. Circuit breaker ise asıl olarak çağrı sık ve servis kullanıcı yolundayken değer katar; günde birkaç kez çağrılan bir entegrasyon için timeout ve makul bir retry çoğu zaman yeter.

Kaynaklar

İlgili

Yorumlar

Yorum yapmak için GitHub hesabınızla giriş yapmanız yeterli. Yorumlar GitHub Discussions üzerinde saklanır.

Sitede Ara

Yazı, proje ve sayfalarda arama yapmak için yazmaya başlayın.

Esc ile kapat Pagefind ile güçlendirildi