Circuit Breaker Membatasi Kegagalan Berantai

Dependency yang lambat atau gagal dapat menghabiskan kapasitas di luar komponen itu sendiri. Caller menunggu, melakukan retry, menahan socket, memakai worker slot, dan mempertahankan memory selama request belum selesai. Saat tekanan merambat ke upstream, gangguan lokal dapat berubah menjadi saturasi pada seluruh service.

Circuit breaker menempatkan gate berstate di sekitar call menuju dependency tersebut. Breaker mengamati outcome, masuk ke state open ketika kebijakan failure terpenuhi, menolak call selama periode tertentu, lalu mengizinkan sejumlah kecil probe. Probe yang berhasil dapat mengembalikan breaker ke traffic normal; probe yang gagal mengembalikannya ke state open.

Mekanisme ini tidak memperbaiki dependency. Fungsinya adalah membatasi kapasitas caller yang dihabiskan untuk dependency yang saat itu kecil kemungkinannya menghasilkan kerja yang berguna.

State closed membawa traffic normal

Breaker biasanya dimulai dalam state closed. Request diteruskan ke dependency, sementara breaker mencatat signal yang dipakai oleh kebijakannya.

request -> breaker(closed) -> dependency
                         <- success/failure

Signal dapat berupa failure berurutan, rasio error dalam rolling window, latency di atas threshold, atau kombinasinya. Pemilihannya penting karena tidak setiap hasil aplikasi yang gagal menandakan failure pada dependency.

Sebagai contoh, HTTP 404 yang dihasilkan dengan cepat oleh service sehat biasanya berbeda dari connection timeout. Menghitung keduanya sebagai failure yang setara dapat membuka breaker saat dependency sebenarnya bekerja normal.

Karena itu, kebijakan yang baik mengklasifikasikan outcome sebelum memperbarui state breaker.

Pembukaan memerlukan aturan observasi terbatas

Jumlah failure mentah tanpa window dapat mempertahankan insiden lama tanpa batas. Rasio tanpa minimum sample count dapat bereaksi terhadap satu failure dari satu request. Kebijakan produksi umumnya menggabungkan observation window terbatas dengan volume minimum.

Misalnya, breaker mengevaluasi 20 call terakhir yang memenuhi syarat dan masuk ke state open ketika sedikitnya 10 call sudah selesai serta lebih dari 60 persen diklasifikasikan sebagai dependency failure. Nilai persisnya bergantung pada bentuk traffic dan biaya failure; angka tersebut merupakan input kebijakan, bukan default universal.

Properti pentingnya adalah keputusan memakai bukti yang baru dan relevan. Failure lama akhirnya keluar dari observation set, sedangkan sample yang terlalu kecil tidak mendominasi transisi state.

State open menolak kerja sebelum dependency

Setelah open, breaker menghentikan call biasa agar tidak mencapai dependency.

client -> breaker(open) -X-> dependency
          |
          +-> fail fast

Fail-fast melepaskan resource caller lebih cepat daripada menunggu timeout pada setiap request. Cara ini juga mengurangi traffic ke dependency yang mungkin sudah overload.

Error yang dikembalikan sebaiknya tetap dapat dibedakan dari error yang benar-benar dihasilkan dependency. Perbedaan tersebut membantu retry policy, metrics, dan analisis insiden agar call yang ditolak secara lokal tidak dianggap sebagai bukti baru dari remote system.

Membuka breaker bukan pengganti timeout. Call yang dibuat saat closed tetap memerlukan batas connect, request, dan response time. Tanpa batas tersebut, cukup banyak call in-flight dapat menghabiskan resource caller sebelum breaker menerima outcome untuk dievaluasi.

State half-open mengendalikan traffic pemulihan

Breaker yang open tidak dapat tetap open selamanya bila recovery otomatis diharapkan. Setelah interval yang dikonfigurasi, breaker masuk ke fase probing yang umum disebut half-open.

State half-open perlu membatasi concurrency. Jika setiap request yang menunggu menjadi probe sekaligus, percobaan recovery pertama dapat menciptakan kembali lonjakan load yang ikut memperburuk failure.

open
  |
  | recovery interval elapsed
  v
half-open -> probe 1
          -> probe 2
          -X excess calls

Probe budget yang kecil memberi dependency jalur terkontrol untuk kembali melayani traffic. Breaker dapat masuk ke closed setelah kriteria sukses terpenuhi, atau kembali open segera setelah probe menunjukkan kondisi failure masih berlangsung.

Semantik probe harus sesuai dengan dependency. Health endpoint yang ringan mungkin tidak melewati jalur yang sama dengan pekerjaan nyata. Pada banyak sistem, real request dalam jumlah terbatas memberi signal recovery yang lebih representatif, selama side effect dan perilaku retry-nya aman.

Scope breaker menentukan blast radius

Breaker yang dibagi terlalu luas dapat mengubah satu target yang gagal menjadi outage bagi target sehat. Breaker yang terlalu sempit dapat memberi perlindungan kecil karena setiap caller melihat sample terlalu sedikit atau masih mengirim aggregate traffic yang besar.

Scope yang berguna sering mengikuti failure domain: upstream service tertentu, host pool, shard, endpoint yang bergantung pada tenant, atau kelas operasi. Boundary yang tepat bergantung pada failure mana yang berkorelasi.

Pertimbangkan client yang berbicara dengan tiga shard independen. Satu breaker global dapat memblokir ketiganya ketika hanya satu shard tidak sehat. Breaker per shard mempertahankan traffic ke shard sehat sekaligus melindungi caller dari shard yang gagal.

Prinsip yang sama berlaku untuk credential, region, dan endpoint ketika masing-masing memiliki failure mode independen.

Retry dan breaker memerlukan satu budget

Retry dapat melawan perlindungan breaker bila dikonfigurasi secara terpisah. Request yang gagal dapat dicoba beberapa kali sebelum breaker mencatat cukup banyak failure selesai untuk masuk ke open. Pada banyak caller, amplifikasi tersebut dapat menjadi besar.

Retry policy perlu memperhitungkan deadline dan klasifikasi failure yang sama di sekitar dependency. Call yang ditolak secara lokal oleh breaker open umumnya tidak seharusnya memicu immediate retry loop terhadap breaker yang sama. Retry setelah delay yang bermakna, fallback path, atau meneruskan failure dapat lebih sesuai.

Jitter tetap berguna ketika banyak client mungkin melanjutkan traffic pada waktu yang berdekatan. Jitter menyebarkan tekanan retry dan recovery agar tidak berkumpul pada satu batas timer.

Breaker terdistribusi tidak harus memiliki state identik

Dalam sebuah fleet, setiap process dapat menyimpan state breaker sendiri. Cara ini menghindari penambahan coordination dependency ke mekanisme perlindungan, tetapi instance yang berbeda dapat open dan closed pada waktu berbeda.

Perbedaan tersebut sering dapat diterima. Setiap instance membatasi exposure resource-nya sendiri, dan aggregate traffic turun saat lebih banyak instance mengamati fault. Breaker yang dibagi secara terpusat dapat mengoordinasikan fleet lebih rapat, tetapi juga menambah shared state, network latency, dan failure mode baru.

Pilihan desain mengikuti tujuan perlindungan. Breaker lokal melindungi setiap caller instance. Shared admission control merupakan mekanisme berbeda ketika kebutuhan utamanya adalah batas traffic fleet-wide yang ketat.

Metrics perlu menampilkan transisi state

Breaker yang menolak traffic secara diam-diam dapat menutupi fault awal. Telemetry operasional setidaknya perlu memisahkan remote attempt, remote failure, rejection lokal pada state open, outcome probe, dan transisi state.

Field yang berguna mencakup identity dependency, scope breaker, state sebelumnya, state berikutnya, alasan transisi, observation count, failure ratio, dan probe count. Transition log sangat bernilai karena rejection count yang tinggi dapat merupakan akibat dari satu keputusan open sebelumnya, bukan ribuan remote failure baru.

Metrics juga memperlihatkan oscillation yang tidak sehat. Siklus closed-to-open-to-half-open yang terlalu sering dapat menunjukkan recovery interval terlalu pendek, threshold terlalu sensitif, atau dependency beroperasi dekat capacity boundary.

Perlindungan berada di sekitar call yang dibatasi

Circuit breaker bekerja paling baik sebagai satu lapisan dalam jalur resource control yang lebih luas. Timeout membatasi satu call. Retry budget membatasi percobaan berulang. Concurrency limit membatasi pekerjaan simultan. Circuit breaker sementara menekan call ketika bukti terbaru menunjukkan dependency tidak sehat.

Kontrol tersebut menangani bagian berbeda dari failure path yang sama. Breaker menambahkan memory lintas request: setelah bukti yang cukup terakumulasi, caller berhenti membayar remote-call cost penuh sampai probe terkontrol menunjukkan bahwa traffic normal dapat dilanjutkan.