Petunjuk dan konteks
Sebuah layanan memanggil database, penyedia pembayaran, dan sistem rekomendasi. Rekomendasi melambat dari 10 ms menjadi 1 detik. Permintaan in-flight meningkat hingga thread dan koneksi habis terpakai, dan API yang tidak memerlukan rekomendasi pun ikut gagal. Rancang bulkhead agar dependensi yang lambat hanya memengaruhi fungsionalitas terkait.
AWS Builders’ Library menggambarkan hal ini sebagai kelebihan beban konkurensi akibat latensi (latency-driven concurrency overload): timeout bukanlah batas konkurensi. Sumber daya harus diisolasi di sekitar setiap dependensi atau klien, guna melindungi layanan itu sendiri maupun sistem downstream.
Hal yang dievaluasi pewawancara
- Anda menjelaskan intuisi Hukum Little (Little’s Law) bahwa waktu layanan yang lebih lama akan meningkatkan beban kerja in-flight pada tingkat kedatangan (arrival rate) yang sama.
- Anda mengalokasikan konkurensi berdasarkan dependensi, API, tenant, atau resource pool sehingga satu dependensi yang lambat tidak dapat menghabiskan kapasitas global.
- Anda membandingkan kuota hard, soft, dan dinamis beserta pertukaran antara keadilan (fairness) dan utilisasinya.
- Anda merancang penolakan cepat, degradasi, batas waktu (deadline), perilaku circuit, pemulihan, dan observabilitas.
- Anda membuktikan bahwa API yang tidak terkait tetap sehat tanpa antrean tak terbatas atau kelaparan sumber daya (starvation).
Pertanyaan klarifikasi awal
- API mana yang memanggil rekomendasi dan mana yang kritis? Apakah ada jalur yang dapat didegradasi?
- Berapa batas thread, koneksi, memori, dan antrean serta bagaimana distribusi konkurensi saat ini?
- Apakah dependensi mendukung pembatalan, idempotensi, batching, atau caching? Bagaimana deadline pemanggil dipropagasi?
- Apakah alokasi diisolasi berdasarkan API, dependensi, tenant, atau Availability Zone? Apakah peminjaman kuota diperlukan?
- Pengalaman pengguna, kontrak kesalahan, dan target pemulihan apa yang berlaku selama kegagalan?
Jawaban 30 detik
“Saya membuat bulkhead konkurensi berbatas dan antrean per dependensi, dengan pool terpisah untuk API kritis dan API yang dapat didegradasi. Setiap permintaan membawa deadline; pekerjaan yang melebihi kuota akan gagal dengan cepat (fail fast) atau menyajikan data cache daripada menunggu tanpa batas. Saya menggunakan kuota soft untuk efisiensi utilisasi tetapi menerapkan batas global dan per kelas yang hard, dengan peminjaman berbatas. Metrik mencakup pekerjaan in-flight, penolakan, waktu tunggu, timeout, degradasi, dan pemulihan berdasarkan dependensi dan API. Pengujian dependensi lambat harus memastikan API yang tidak terkait tetap sehat.”
Solusi langkah demi langkah
Langkah 1: Kuantifikasi konkurensi akibat latensi
Ukur tingkat kedatangan, waktu layanan, permintaan in-flight, dan timeout per dependensi. Jika waktu layanan naik dari 10 ms menjadi 1 detik, pekerjaan in-flight dapat melonjak sekitar 100 kali lipat pada tingkat kedatangan yang sama. Temukan sumber daya yang terbatas sebelum menentukan ukuran bulkhead.
Langkah 2: Partisi kumpulan sumber daya (resource pools)
Berikan setiap dependensi connection pool, semaphore, dan antrean berbatas tersendiri; pisahkan API kritis dan API yang dapat didegradasi untuk dependensi yang sama. Pastikan bahwa isolasi tersebut nyata: thread, koneksi, dan status tidak boleh tetap dipakai bersama di balik penghitung (counter) yang terpisah.
Langkah 3: Pilih kuota hard, soft, dan dinamis
Kuota hard melindungi API tetapi membuang kapasitas saat terjadi ketimpangan beban. Kuota soft meminjam kapasitas menganggur di bawah batas global. Kuota dinamis beradaptasi terhadap beban tetapi memerlukan jaminan minimum, batas maksimum, dan laju perubahan yang aman. Tambahkan partisi tenant jika keadilan menjadi prioritas.
global_limit = 500
payments = hard 150
recommendations = soft 200, borrow <= 100
other_apis = reserved 50Langkah 4: Tolak dan degradasi secara terencana
Jika tidak ada izin yang tersedia, kembalikan kesalahan eksplisit atau hasil cache alih-alih memasukkannya ke dalam antrean tak terbatas. Hormati deadline pemanggil dan batalkan pekerjaan yang memungkinkan untuk dibatalkan. Percobaan ulang (retries) membutuhkan anggaran, backoff, dan idempotensi; operasi penulisan kritis tidak boleh didegradasi secara diam-diam.
Langkah 5: Pulihkan tanpa osilasi
Setelah pemulihan, tingkatkan izin secara bertahap dan gunakan probe half-open untuk menghindari lonjakan tiba-tiba. Pertahankan data runtun waktu (time series) untuk penolakan, timeout, dan batas antrean (watermarks), yang disegmentasikan berdasarkan dependensi, API, tenant, dan cell. Buat versi konfigurasi dan siapkan mekanisme rollback.
Langkah 6: Verifikasi batas isolasi
Injeksikan latensi, kesalahan, dan habisnya koneksi ke salah satu dependensi. Amati penolakan rekomendasi, keberhasilan pembayaran, penggunaan thread/koneksi global, dan tail latency. Uji lonjakan beban mendadak, ketimpangan tenant, perubahan konfigurasi, dan kegagalan cell; SLO API yang tidak terkait dan batas antrean adalah tolok ukur penerimaannya.
Contoh jawaban yang kuat
“Saya menggunakan tingkat kedatangan, waktu layanan, dan pekerjaan in-flight untuk menunjukkan mengapa dependensi rekomendasi yang lambat melipatgandakan konkurensi. Setiap dependensi memiliki semaphore, pool, dan antrean berbatas tersendiri; API kritis dan yang dapat didegradasi dipisahkan. Pembayaran mendapatkan reservasi hard; rekomendasi menggunakan kuota soft dengan peminjaman berbatas. Setiap panggilan mempropagasi deadline dan langsung gagal cepat atau mengembalikan cache saat izin habis.”
“Pemulihan menggunakan probe half-open dan peningkatan izin secara bertahap. Metrik mencakup pekerjaan in-flight, penolakan, waktu tunggu, timeout, frekuensi degradasi, kesalahan downstream, dan waktu pemulihan. Simulasi pengujian hanya memperlambat rekomendasi dan memeriksa bahwa tail latency, pool, dan thread untuk pembayaran serta API tak terkait tetap berada dalam batas aman.”
Kesalahan umum
- Hanya menaikkan timeout → pekerjaan in-flight melonjak → tetapkan batas konkurensi tingkat dependensi.
- Menggunakan satu thread pool dan connection pool bersama → satu dependensi lambat melumpuhkan seluruh layanan → partisi berdasarkan dependensi dan tingkat kekritisan.
- Menggunakan antrean tak berbatas → memori dan latensi lepas kendali → batasi antrean dan tolak dengan cepat.
- Kuota hard statis di semua tempat → ketimpangan beban menyisakan kapasitas menganggur → izinkan peminjaman kuota soft yang berbatas.
- Retry tanpa batas anggaran → kelebihan beban downstream makin teramplifikasi → propagasikan deadline, batasi percobaan, dan wajibkan idempotensi.
- Hanya menguji dependensi yang gagal → isolasi belum terbukti → verifikasi SLO API yang tidak terkait secara bersamaan.
Pertanyaan lanjutan dan jawaban
Mengapa timeout bukan merupakan batas konkurensi?
Timeout hanya membatasi durasi satu kali tunggu, tetapi permintaan yang sedang menunggu tersebut tetap memakai thread, koneksi, dan memori. Latensi dependensi yang lebih tinggi menyebabkan lebih banyak permintaan in-flight, sehingga izin akseslah yang harus dibatasi.
Bagaimana peminjaman soft mencegah satu API mengambil semua sumber daya?
Gunakan batas global, reservasi minimum per API, batas pinjaman maksimum, dan tingkat pengembalian (reclaim rate). Begitu peminjam mencapai batas maksimalnya, sistem akan gagal cepat alih-alih terus tumbuh tanpa batas.
Kapan penyajian data cache aman dilakukan?
Untuk operasi baca di mana data basi dalam batas tertentu (bounded staleness) dapat diterima, kembalikan nilai cache yang memiliki stempel waktu. Hasil pembayaran, otorisasi, dan operasi tulis tidak boleh digantikan secara diam-diam oleh data basi.
Bagaimana Anda membuktikan bahwa isolasi berhasil?
Injeksikan kelambatan dan kesalahan pada satu dependensi, lalu periksa pekerjaan in-flight, tail latency, penggunaan thread/koneksi, dan tingkat keberhasilan pada API yang tidak terkait. Degradasi yang terjadi secara sinkron menandakan bahwa masih ada sumber daya bersama atau batasan antrean yang belum terisolasi.