Petunjuk dan ruang lingkup
liburing menyediakan operasi multishot accept yang dapat menghasilkan beberapa completion queue entry (CQE) dari satu pengiriman (submission). Permintaan dapat berhenti menghasilkan completion setelah terjadi error atau ketika flag multishot tidak ada. Keahlian intinya adalah pemrograman sistem asinkron dan termasuk dalam coding.
Apa yang dinilai oleh pewawancara
Jawaban yang kuat menjelaskan IORING_CQE_F_MORE, kepemilikan CQE, backpressure pada submission dan completion queue, error accept, pembatalan, dan rearming. Mereka memeriksa dukungan kernel daripada berasumsi bahwa fitur tersebut ada, menghindari penggunaan kembali buffer atau user data sebelum waktunya, dan membandingkan desain tersebut dengan loop accept non-blocking konvensional.
Pertanyaan klarifikasi awal
- Versi kernel dan liburing mana yang diterapkan?
- Apakah listening socket dibagikan ke seluruh worker atau dimiliki oleh satu ring?
- Berapa connection rate, burst size, dan anggaran file-descriptor yang diharapkan?
- Bagaimana socket yang diterima diserahkan ke protocol worker?
- Apa yang harus terjadi ketika permintaan multishot berakhir atau CQ penuh?
- Apakah diperlukan fallback portabel atau non-io_uring?
Kerangka jawaban 30 detik
"Saya akan memeriksa dukungan, mengirimkan satu multishot accept, dan memproses setiap CQE sebagai socket diterima yang independen. Saya akan memeriksa IORING_CQE_F_MORE; jika tidak ada, permintaan tidak lagi dipersenjatai (armed) dan harus dikirim ulang setelah menangani hasil terminal. Loop memerlukan kedalaman CQ yang terbatas, penanganan EMFILE dan error sementara yang eksplisit, kepemilikan handoff socket, serta loop accept fallback. Saya akan mem-benchmark CPU, accept per detik, tail latency, drop, CQ overflow, dan jeda rearm."
Jawaban langkah demi langkah
Langkah 1: Memeriksa dan mengonfigurasi
Gunakan probe ring atau pemeriksaan kapabilitas terdokumentasi untuk operasi multishot accept dan flag yang diperlukan. Tentukan ukuran antrean dari laju burst dan handoff, konfigurasikan perilaku close-on-exec dan non-blocking, serta putuskan apakah direct descriptor sebanding dengan biaya pengelolaannya.
Langkah 2: Mengirimkan satu permintaan yang berumur panjang
Siapkan permintaan multishot accept dengan user data stabil yang mengidentifikasi listening socket dan generasinya. Jangan berasumsi satu SQE menghasilkan satu CQE. Pertahankan siklus hidup permintaan dalam status event-loop dan hindari membebaskan status terkait hingga completion terminalnya dikonsumsi.
Langkah 3: Mengonsumsi setiap completion
Untuk setiap CQE, periksa hasilnya apakah terdapat descriptor yang diterima atau nilai error negatif. Transfer kepemilikan socket yang berhasil tepat satu kali ke protocol worker. Periksa IORING_CQE_F_MORE; jika tidak aktif, tandai permintaan sebagai tidak aktif meskipun CQE saat ini berhasil.
Langkah 4: Rearm dan terapkan backpressure
Setelah mengosongkan (drain) CQE yang tersedia, kirim ulang saat permintaan tidak aktif dan sistem dapat menerima lebih banyak pekerjaan. Batasi antrean handoff, jeda atau tolak pekerjaan baru di bawah tekanan file-descriptor, dan tangani EMFILE, ENFILE, serta error jaringan sementara tanpa busy loop.
Langkah 5: Shutdown dan benchmark
Batalkan atau tutup permintaan selama shutdown, kosongkan CQE, dan tutup socket yang diterima tanpa pemilik. Bandingkan multishot dan accept konvensional pada core, backlog, variasi koneksi, dan kapasitas worker yang identik. Ukur jeda rearm dan koneksi yang terputus (dropped) atau ditolak, bukan hanya jumlah syscall.
Contoh jawaban model
"Multishot accept mengurangi overhead pengiriman, tetapi ini adalah aliran CQE dengan masa hidup permintaan yang terbatas. Saya akan memeriksa dukungan, mengirimkan user data yang stabil, mengonsumsi setiap descriptor yang diterima sekali, dan memeriksa IORING_CQE_F_MORE pada setiap completion. Setelah flag tersebut hilang, saya akan menandai permintaan sebagai tidak aktif dan me-rearm-nya setelah menangani hasil terminal. Kedalaman antrean, backpressure handoff, penanganan EMFILE, pengosongan saat shutdown, dan fallback accept konvensional adalah bagian dari kebenaran sistem. Tolok ukur harus mencakup jeda rearm, drop, tail latency, dan CPU."
Kesalahan umum
- Mengasumsikan permintaan bersifat permanen → completion berhenti setelah error atau tanpa MORE → lakukan rearm secara eksplisit.
- Memperlakukan satu CQE sebagai keseluruhan hasil → socket yang diterima berikutnya terlewatkan → kuras (drain) semua CQE.
- Membebaskan user data terlalu dini → completion selanjutnya menggunakan state yang tidak valid → pertahankan state hingga completion terminal.
- Mengabaikan hasil negatif → loop berputar tanpa henti atau menyembunyikan kehabisan sumber daya → klasifikasikan error dan lakukan backoff.
- Antrean handoff tidak terbatas → descriptor yang diterima menghabiskan sumber daya proses → terapkan anggaran descriptor dan antrean.
- Hanya mem-benchmark syscall → jeda rearm dan drop tetap tersembunyi → ukur hasil koneksi end-to-end.
Pertanyaan lanjutan
Pertanyaan lanjutan 1: Apa arti dari IORING_CQE_F_MORE?
Ini menunjukkan bahwa permintaan multishot diharapkan menghasilkan lebih banyak CQE. Jika tidak ada, permintaan telah berakhir dan aplikasi tidak boleh berasumsi bahwa completion lain akan tiba.
Pertanyaan lanjutan 2: Bisakah CQE yang berhasil menjadi completion terminal?
Ya. CQE dapat berisi descriptor yang diterima secara valid meskipun tidak memiliki flag MORE. Proses socket tersebut, lalu lakukan rearm pada permintaan.
Pertanyaan lanjutan 3: Bagaimana Anda menghindari kehabisan descriptor?
Batasi handoff protokol, pantau RLIMIT_NOFILE, tangani EMFILE dan ENFILE, serta hentikan accept atau kurangi beban (shed load) hingga kapasitas pulih.
Pertanyaan lanjutan 4: Mengapa mempertahankan fallback?
Batasan kernel, liburing, kontainer, atau kebijakan dapat mencegah penggunaan io_uring. Loop accept non-blocking menjaga ketersediaan dan memberikan baseline ketepatan untuk perbandingan performa.