Topik wawancara representatif

Wawancara Desain Sistem: Bagaimana Anda Mendesain Driver Block-Device Userspace yang Dapat Dipulihkan?

Desain sistemSulit
Tim Redaksi Offer.ccDipublikasikan Diperbarui

Pertanyaan

Rancang sistem yang menempatkan logika virtual block-device di userspace. Sistem harus mendukung I/O konkurensi tinggi, pemulihan crash proses userspace, isolasi izin, dan observabilitas. Jelaskan batasan protokol control/data-plane.

Petunjuk dan konteks

Rancang sistem yang menempatkan logika virtual block-device di userspace: kernel mengekspos sebuah block device sementara layanan userspace menangani loop, penyimpanan blok jarak jauh, atau pemetaan qcow2. Sistem harus mendukung I/O konkurensi tinggi, pemulihan crash proses userspace, isolasi izin, dan observabilitas.

Linux ublk memisahkan kerangka kerja ini menjadi control plane dan data plane: /dev/ublk-control mengelola perangkat, /dev/ublkb* membawa I/O blok, dan layanan userspace mengambil permintaan serta melakukan commit hasil melalui io_uring passthrough. Wawancara ini menguji siklus hidup permintaan, semantik kegagalan, dan batasan keamanan daripada sekadar memindahkan I/O file ke dalam suatu proses.

Apa yang sedang diuji oleh pewawancara

Tunjukkan batasan antara kontrol, lapisan blok kernel, io_uring, dan backend userspace. Jelaskan hubungan satu-ke-satu antara antrean, tag, buffer, dan penyelesaian (completions); pilih antara mode per-I/O dan batch; tentukan semantik requeue, fail, dan replay saat server keluar; serta tangani zero-copy, hak istimewa, isolasi kontainer, dan metrik.

Pertanyaan untuk diklarifikasi terlebih dahulu

Beban kerja dan backend

Konfirmasikan rasio baca/tulis, ukuran I/O, jumlah antrean, target latensi, apakah backend berupa file lokal, NBD jarak jauh, atau format copy-on-write, serta apakah jaminan pengurutan (ordering) diperlukan.

Kegagalan dan keamanan data

Konfirmasikan semantik untuk crash userspace, partisi jaringan, penulisan backend pendek (short write), penulisan duplikat, dan penghapusan perangkat. Pastikan apakah pemutaran ulang (replay) dapat menoleransi penulisan ganda.

Izin dan penerapan

Konfirmasikan siapa yang boleh membuat perangkat, siapa yang boleh membaca /dev/ublkc*, apakah layanan berjalan dalam kontainer, hak istimewa zero-copy mana yang diizinkan, dan bagaimana penyewa (tenants) diisolasi.

Jawaban 30 detik

"Saya memisahkan control plane dan data plane. Kontrol menegosiasikan antrean, kedalaman, dan fitur sebelum memulai perangkat; data mengambil permintaan dari io_uring berdasarkan antrean dan tag serta melakukan commit hasil. Setiap permintaan memiliki pemilik, status, dan batas waktu (timeout). Ketika server userspace keluar, saya menenangkan (quiesce) perangkat dan memilih requeue, fail, atau replay sesuai dengan jaminan backend. Penyalinan adalah bawaan (default); zero-copy dibatasi untuk backend tepercaya yang berwenang. Metrik mencakup kedalaman antrean, latensi penyelesaian, percobaan ulang, drop, dan waktu pemulihan, dengan pengujian konsistensi untuk penghapusan dan pemulihan."

Jawaban mendalam langkah demi langkah

Langkah 1: Mempartisi control plane

Ekspos perintah untuk menambah, menyetel/mendapatkan parameter, memulai, menghentikan, dan menghapus perangkat. Menambahkan perangkat akan menegosiasikan nr_hw_queues, queue_depth, dan ukuran buffer I/O maksimum; parameter dibekukan sebelum dimulai, setelah itu /dev/ublkb* diekspos. Layanan userspace menyimpan ID perangkat dan informasi khusus backend.

Langkah 2: Mendesain permintaan data-plane

Lapisan blok menetapkan tag unik per antrean, dan layanan userspace mengaitkan permintaan berdasarkan (queue, tag). Area pemetaan tetap menjelaskan offset, panjang, operasi, dan flag. Layanan menerima notifikasi melalui io_uring passthrough dan melakukan commit status serta byte yang telah selesai kembali ke kernel.

Langkah 3: Memilih mode per-I/O atau batch

Perintah per-I/O tradisional mudah dipahami, dengan satu daemon yang memiliki setiap tag. Mode batch menyiapkan dan melakukan commit banyak permintaan per antrean, mengurangi overhead syscall, dan memungkinkan tugas berbagi beban kerja secara dinamis. Jangan mencampur set perintah selama migrasi; bandingkan latensi ekor (tail latency), CPU, dan penyeimbangan beban di bawah tekanan.

Langkah 4: Menentukan state machine pemulihan

Gunakan status seperti running, quiescing, recovering, dan failed. Saat server keluar, hentikan pengiriman I/O baru, tunggu atau tandai permintaan yang sedang berjalan (in-flight), dan terbitkan START_USER_RECOVERY. REISSUE cocok untuk backend yang menoleransi penulisan duplikat; FAIL_IO membuat permintaan yang sedang berjalan dan di masa mendatang gagal secara eksplisit alih-alih merekayasa keberhasilan.

text
on_server_exit:
  quiesce_device()
  if policy == REISSUE:
    requeue_inflight()
  else:
    fail_inflight_and_future_io()
  wait_new_server_ready()
  end_user_recovery()

Langkah 5: Menangani buffer dan zero-copy

Jalur biasa menggunakan buffer userspace yang telah dialokasikan sebelumnya dan penyalinan kernel, memberikan batasan yang lebih sederhana. Zero-copy memerlukan buffer tetap yang terdaftar, penyelarasan segmen backend, dan layanan tepercaya yang mengisi data READ dan melaporkan jumlah byte dengan benar. Kesalahan dapat mengekspos buffer kernel yang belum diinisialisasi, jadi batasi hak istimewa dan audit masa pakainya.

Langkah 6: Membangun isolasi izin dan kontainer

Pisahkan perintah kontrol berhak istimewa dari akses perangkat. Dengan perangkat tanpa hak istimewa (unprivileged), kernel masih memeriksa kepemilikan perangkat karakter yang relevan; sebuah kontainer seharusnya hanya melihat node perangkat miliknya. Backend userspace tidak boleh menerima izin file, jaringan, atau KMS di luar perangkat targetnya.

Langkah 7: Memverifikasi performa dan kebenaran

Ukur IOPS, latensi p50/p99, kedalaman antrean, CPU, byte yang disalin, dan waktu pemulihan dengan fio atau beban kerja mirip produksi. Suntikkan crash server, timeout backend, penulisan pendek, penghapusan perangkat, dan pengiriman duplikat. Verifikasi bahwa setiap permintaan selesai sekali atau gagal secara eksplisit berdasarkan kebijakan; uji batas dan checksum pada mode penyalinan maupun zero-copy.

Jawaban model

Saya akan membagi sistem mirip ublk menjadi control plane, lapisan blok kernel, data plane io_uring, dan backend userspace. Kontrol menegosiasikan antrean dan buffer sebelum memulai; data melacak permintaan berdasarkan (queue, tag) dan memvalidasi status serta jumlah byte pada saat penyelesaian. Crash server memicu quiescing dan pemulihan: replay hanya untuk backend yang dapat menoleransinya, jika tidak, gagalkan (fail). Penyalinan adalah default; zero-copy dibatasi untuk layanan yang tepercaya, selaras, dan berwenang. Rilis memerlukan pengujian latensi ekor, injeksi kesalahan, isolasi izin, dan konsistensi penghapusan.

Kesalahan umum

  • Kesalahan: Membiarkan server userspace menutup perangkat secara langsung. → Mengapa gagal: Permintaan yang sedang berjalan dan status antrean kernel tetap tidak terdefinisi. → Solusi: Hentikan pengiriman, lakukan quiesce, lalu terapkan kebijakan pemulihan.
  • Kesalahan: Mengaktifkan zero-copy untuk setiap backend. → Mengapa gagal: Masa pakai buffer, hak istimewa, dan risiko data yang belum diinisialisasi meningkat. → Solusi: Gunakan penyalinan secara default dan batasi zero-copy berdasarkan kemampuan dan audit.
  • Kesalahan: Melindungi semua antrean dengan satu kunci global. → Mengapa gagal: Konkurensi multi-antrean menjadi terserialisasi. → Solusi: Pecah (shard) status berdasarkan antrean/tag dan ukur perebutan sumber daya (contention).
  • Kesalahan: Hanya mengukur throughput I/O yang sehat. → Mengapa gagal: Crash, penulisan pendek, dan penulisan duplikat menentukan konsistensi. → Solusi: Sertakan state machine pemulihan dan injeksi kesalahan dalam pengujian penerimaan (acceptance tests).

Pertanyaan lanjutan dan tanggapan

Kapan Anda harus memilih batch I/O?

Pilih batch saat overhead syscall dan notifikasi mendominasi, antrean memiliki konkurensi yang cukup, dan tugas dapat berbagi pekerjaan secara dinamis. Mode tradisional lebih mudah didebug ketika kepemilikan per-I/O penting atau konkurensi rendah.

Bagaimana REISSUE menghindari kerusakan data?

Aktifkan hanya untuk backend yang idempoten atau yang mendeteksi duplikat, menggunakan ID permintaan, versi penulisan, atau deduplikasi log. Jika idempotensi tidak dapat dibuktikan, gagalkan dan biarkan lapisan atas memulihkannya.

Bagaimana Anda membatasi dampak keamanan zero-copy?

Ikat pendaftaran buffer, pembatalan pendaftaran, dan izin perangkat ke satu layanan tepercaya; validasi alamat, panjang, penyelarasan, dan byte penyelesaian; serta larang pemetaan yang dapat ditulisi yang dibagikan ke seluruh penyewa.

Bagaimana Anda menjaga konsistensi selama penghapusan perangkat?

Hentikan permintaan baru, tunggu permintaan yang dikirimkan selesai atau gagal, konfirmasikan bahwa antrean userspace kosong, lalu lepaskan node perangkat dan pemetaan. Catat timeout sebagai kegagalan yang dapat dilacak daripada mengabaikannya begitu saja tanpa pemberitahuan.

Sumber publik

Pertanyaan terkait

Alat wawancara terkait

Gunakan Jawab untuk jawaban desain sistem

Perjelas persyaratan terlebih dahulu, lalu lanjutkan dengan skala, arsitektur, pilihan komponen, dan trade-off.

Lihat alat