Lompat ke konten
18 menit bacamateri 16 dari 96

Lakukan retry dengan bertanggung jawab

Tentukan siapa yang boleh retry, kapan, berapa kali, dan dengan jeda apa, supaya retry memulihkan kegagalan sesaat tanpa melipatgandakan beban.

Ditinjau 26 Oktober 2026

Pertanyaan

Kapan mengulang request itu menolong, dan kapan justru menjatuhkan layanan yang sedang kesulitan?

Selesai baca ini, kamu bisa menentukan pemilik retry, memilih backoff dengan jitter, menetapkan anggaran retry, dan menghitung seberapa besar retry melipatgandakan beban.

Prasyarat dan contoh

Kamu sudah baca M03.03 soal deadline, dan M03.01 soal kelas error.

Contoh: sebuah layanan database dengan kapasitas 1.000 query per detik melayani beban normal 700 per detik. Terjadi gangguan sesaat 2 detik, dan sebagian query timeout. Klien, library HTTP, dan layanan di antaranya masing-masing di-set "retry 3 kali". Rantainya tiga tingkat, jadi satu aksi pengguna bisa jadi (1+3)^3 = 64 percobaan di tingkat paling bawah. Beban efektif melonjak jauh melewati 1.000 per detik. Gangguan yang seharusnya selesai dalam 2 detik bertahan 5 menit, karena retry sendiri yang menjaga layanan tetap kelebihan beban.

Retry itu mekanisme pemulihan sekaligus pengganda beban. Pertanyaannya selalu: siapa yang boleh melakukannya, dan siapa yang membatasi.

Mekanisme

1. Satu pemilik retry per rantai. Tentukan satu lapisan (biasanya yang paling dekat dengan pengguna atau yang punya konteks bisnis) sebagai pemilik. Lapisan lain di bawahnya gagal cepat. Tiga lapisan dengan 3 retry tiap lapisan menghasilkan 64 percobaan, satu lapisan menghasilkan 4.

2. Hanya untuk kegagalan yang mungkin sementara. Boleh diulang: timeout koneksi, 503, 429 (setelah menunggu Retry-After), 502. Jangan diulang: 400, 401, 403, 404, 422, karena hasilnya akan sama. Dan jangan mengulang operasi yang nggak aman diulang (misalnya POST tanpa kunci idempotensi), karena timeout berarti hasilnya nggak diketahui (M03.05).

3. Exponential backoff. Jeda antar percobaan membesar: delay = min(cap, base * 2^n). Dengan base = 100 ms dan cap = 5 s, jedanya 100, 200, 400, 800, ... ms. Tujuannya memberi waktu layanan pulih.

4. Jitter. Backoff tanpa acak membuat semua klien yang gagal pada detik yang sama retry pada detik yang sama juga: gelombang sinkron. Beri acak, misalnya "full jitter": delay = random(0, min(cap, base * 2^n)). Dengan 10.000 klien yang gagal bersamaan, tanpa jitter ada 10.000 request di tiap kelipatan jeda. Dengan full jitter, puncak itu tersebar rata di rentang jeda.

5. Anggaran retry. Batasi retry sebagai proporsi dari trafik, bukan hanya jumlah per request. Contoh: retry nggak boleh melebihi 10% dari request biasa dalam jendela 1 menit. Saat layanan sehat, hampir semua request sukses dan anggaran selalu tersedia. Saat layanan turun total, anggaran habis cepat, dan beban tambahan dibatasi sekitar +10%, bukan 4x. Bandingkan dengan "maks 3 retry per request": saat semua gagal itu berarti 4x beban, tepat saat layanan paling nggak sanggup.

6. Hormati deadline. Retry hanya boleh jalan kalau sisa waktunya cukup untuk satu percobaan lagi plus jedanya. Retry setelah deadline lewat adalah kerja untuk klien yang sudah pergi.

Saat rancangan ini gagal

  • Retry bertingkat. Setiap library dan lapisan menyalakan retry-nya sendiri. Periksa di setiap lapisan: SDK, service mesh, load balancer, dan kode aplikasi. Hitung hasil kali (1+r) seluruhnya.
  • Retry tanpa jitter. Setelah gangguan 1 detik, semua klien kembali di detik yang sama dan menjatuhkan layanan lagi (thundering herd). Pola grafik: puncak teratur tiap 1, 2, 4, 8 detik.
  • Retry pada error permanen. 422 diulang tiga kali: tiga kali beban, nol manfaat.
  • Retry efek samping tanpa idempotensi. Timeout pada pembayaran diulang, dan pelanggan tertagih dua kali. Retry hanya aman kalau operasinya idempoten.
  • Anggaran nggak ada. Saat layanan hilang total, semua klien tetap memukul dengan frekuensi maksimum. Layanan nggak bisa pulih walaupun masalah awalnya sudah selesai. Gejala ini disebut metastable failure: beban retry memelihara kegagalan itu sendiri.

Latihan

Layanan X: kapasitas 1.000 request per detik, beban normal 600. Ada tiga lapisan (aplikasi mobile, API gateway, layanan pesanan) yang masing-masing diatur "retry 2 kali tanpa jeda". X mengalami gangguan dan 100% request gagal selama 30 detik.

  1. Berapa percobaan maksimum ke X per aksi pengguna, dan berapa beban saat gangguan?
  2. Rancang ulang: siapa pemilik retry, berapa retry, dan berapa beban saat gangguan?
  3. Tulis rumus backoff dan hitung rentang jeda percobaan ke-3 dengan base = 200 ms, cap = 3 s.
Lihat pembahasan
  1. Tiap lapisan mengirim 1 + 2 = 3 percobaan, jadi 3 * 3 * 3 = 27 percobaan per aksi, dan beban saat 100% gagal adalah sekitar 600 x 27 = 16.200 request per detik, enam belas kali kapasitas. Tanpa jeda, ini terjadi dalam hitungan milidetik, dan X nggak akan pulih bahkan setelah penyebab awalnya hilang.
  2. Pemilik retry: aplikasi mobile saja (ia yang tahu apakah pengguna masih menunggu). Gateway dan layanan pesanan gagal cepat. Dengan 2 retry beban maksimum 600 x 3 = 1.800, masih melebihi kapasitas. Tambahkan anggaran retry 10%: beban saat gangguan menjadi sekitar 600 x 1,1 = 660 per detik. Ini di bawah 1.000, dan layanan bisa pulih begitu penyebabnya hilang. Tradeoff-nya sebagian pengguna melihat error lebih cepat.
  3. delay = random(0, min(cap, base * 2^n)). Untuk percobaan ketiga (n = 3 jika n mulai dari 0, yaitu retry kedua setelah percobaan awal), 200 * 2^3 = 1.600 ms, di bawah cap 3 s, jadi jeda acak 0 sampai 1.600 ms. Percobaan berikutnya: 200 * 2^4 = 3.200, dipotong cap jadi 3.000 ms.

Perhatikan bahwa angka 16.200 itu batas atas. Kuncinya bukan angka persisnya, tapi bahwa beban efektif ditentukan oleh hasil kali, bukan jumlah.

Terkait

  • M03.03 Batasi durasi request memberi anggaran waktu yang membatasi retry.
  • M03.05 Jadikan efek idempoten membuat retry aman untuk operasi yang punya efek samping.
  • Overload, load shedding, dan metastable failure dibahas lebih dalam di modul keandalan (M16) dan pengiriman pesan di M10. Keduanya belum tersedia.
  • Lab L03 menampilkan percobaan dan efeknya, tapi belum tersedia.

Catatan

  • Asumsi: layanan sinkron yang berbagi kapasitas terbatas, dan klien yang banyak serta independen.
  • Full jitter dan anggaran retry adalah praktik umum yang didokumentasikan penyedia cloud dan library resilience. Parameter terbaik tergantung beban dan harus diuji.
  • Yang nggak dibahas: circuit breaker, hedged request, dan retry di sisi antrean pesan.
  • Terakhir ditinjau: 26 Oktober 2026.

Isi · System Design