CPU dijadwalkan, memori dipetakan — dan di ujung rantai itu menunggu perangkat paling lambat di sistem: penyimpanan. Pada harddisk mekanis, berpindah antar posisi data (seek) berbiaya milidetik yang setara ribuan siklus CPU, sehingga urutan operasi baca-tulis menentukan nasib latensi seluruh sistem. Kernel menempatkan wasit di antara antrean proses dan antrean perangkat: I/O scheduler, yang menyusun ulang, menggabungkan, dan memprioritaskan permintaan I/O sebelum dikirim ke disk. Pada chapter ini kita menyurvei scheduler yang tersedia di /sys, memilih yang sesuai jenis perangkat, lalu memprioritaskan proses lewat ionice.

Masalah: Antrean di Ujung Disk #

Ambil skenario klasik server ber-harddisk: backup raksasa sedang menyalin jutaan file sambil dua belas user menunggu editor mereka membuka dokumen kecil. Tanpa wasit, kedua beban itu masuk ke disk dalam urutan kedatangan — kepala disk bolak-balik antara sektor backup dan sektor dokumen, dan editor yang seharusnya selesai 5 milidetik menunggu 50. Dua trik menjadi senjata utama scheduler. Pertama, merging: dua permintaan yang menyangkut sektor bersebelahan digabung menjadi satu. Kedua, sorting: permintaan diurutkan mengikuti posisi sektor sehingga kepala disk bergerak satu arah yang efisien. Pada perangkat modern urutannya berubah lagi — SSD dan NVMe tidak punya kepala mekanis, sehingga biaya “melompat” nyaris nol dan pengurutan malah menambah jeda yang tidak perlu.

Tiga Scheduler yang Sering Kita Temui #

Kernel modern membawa beberapa scheduler, dan tiap block device memilih salah satunya secara terpisah:

SchedulerKarakterCocok untuk
nonetidak mengurutkan, langsung terusNVMe dan perangkat cepat lain
mq-deadlinememberi tenggat tiap permintaan agar tidak kelaparanSSD — pilihan bawaan banyak distro
bfqmembagi bandwidth adil per proses, mengutamakan interaktifHDD dan desktop
kybermenyetel latensi target baca/tulis, ringanNVMe/SSD berbeban tinggi

Pilihan aktif per perangkat terbaca dari sysfs — mari kita intip milik lingkungan latihan ini:

bash
for d in /sys/block/*; do
    printf '%-8s %-30s rotational=%s\n' \
        "$(basename "$d")" \
        "$(cat "$d/queue/scheduler")" \
        "$(cat "$d/queue/rotational")"
done

Output yang Dihasilkan:

text
pmem0    none                           rotational=0
vda      [mq-deadline] kyber bfq none   rotational=1
zram0    none                           rotational=0

Cara membaca output di atas:

  1. /sys/block/*: satu direktori per block device — di lingkungan ini ada pmem0, vda, dan zram0; di komputer Anda daftarnya mengikuti perangkat yang terpasang.
  2. queue/scheduler: daftar scheduler yang tersedia, dengan yang aktif ditandai tanda kurung siku — vda sedang memakai mq-deadline.
  3. queue/rotational: penanda apakah perangkat berputar (1) atau tidak (0); zram0 (RAM terkompresi) dan pmem0 memilih none karena keduanya bukan disk sungguhan.

Mengganti Scheduler untuk Sebuah Perangkat #

Penggantian dilakukan dengan menulis ke file yang sama kita baca tadi: echo bfq | sudo tee /sys/block/sda/queue/scheduler mengganti scheduler sda saat itu juga, tanpa reboot dan tanpa mengganggu antrean yang sedang berjalan. Perubahannya tidak bertahan melewati reboot — cara membuatnya permanen justru memakai mekanisme yang akan kita bahas di chapter berikutnya: sebuah udev rule yang bereaksi saat perangkat terdeteksi. Untuk disk data yang sibuk, anggapan terbaiknya sederhana: HDD satu-satunya di sistem memakai bfq agar beban backup tidak menggagalkan sesi interaktif, sementara SSD cukup dengan mq-deadline.

Prioritas I/O dengan ionice #

Scheduler juga menerima keinginan dari user space. Perintah ionice(1) menempelkan kelas dan prioritas pada proses:

KelasNamaPerilaku
1real-timedilayani lebih dulu — butuh CAP_SYS_ADMIN
2best-effortbawaan semua proses, prioritas 0–7
3idlehanya kalau tidak ada antrean lain

Berikut dua kelas yang bisa kita coba tanpa root; argumen -p 0 meminta ionice membaca prioritas prosesnya sendiri:

bash
ionice -c 2 -n 7 ionice -p 0
ionice -c 3 ionice -p 0

Output yang Dihasilkan:

text
best-effort: prio 7
idle

Perintah pertama membungkus proses dengan kelas best-effort prioritas 7 (paling sopan di antara yang bukan idle), dan perintah kedua menurunkannya ke idle. Bandingkan dengan kelas pertama yang menuntut privilege:

bash
ionice -c 1 -n 4 true 2>&1

Output yang Dihasilkan:

text
ionice: ioprio_set failed: Operation not permitted

Kernel menolak karena kelas real-time membutuhkan CAP_SYS_ADMIN — persis pemeriksaan capability yang kita bedah di chapter capabilities . Batasan pentingnya: prioritas ionice dihormati penuh oleh bfq, disadari sebagian oleh mq-deadline, dan diabaikan none — di NVMe tanpa antrean, tidak ada yang perlu diprioritaskan. Untuk pembatasan yang lebih tegas per kelompok proses, mekanisme io controller pada cgroups menetapkan kuota bandwidth, bukan sekadar urutan antrean.

Membaca Efek Scheduler dari /proc/diskstats #

Hasil kerja scheduler terlihat di /proc/diskstats, yang mencatat antara lain jumlah operasi baca/tulis yang selesai dan berapa yang berhasil digabung. Snapshot berikut (fixture) membandingkan tiga perangkat dengan beban berbeda:

bash
cat > diskstats.txt <<'FIX'
# maj min nama     baca_selesai baca_merge tulis_selesai tulis_merge
  259   0 nvme0n1      1248032     481772        903112      610238
    8   0 sda          2104320    3122031       1408210     1613478
  252   0 zram0          88120           0        127341           0
FIX
awk 'NR > 1 {
    baca = $4 + $5
    tulis = $6 + $7
    printf "%-8s baca: %7d op, %3d%% termerge   tulis: %7d op, %3d%% termerge\n", \
           $3, baca, $5 * 100 / baca, tulis, $7 * 100 / tulis
}' diskstats.txt

Output yang Dihasilkan:

text
nvme0n1  baca: 1729804 op,  27% termerge   tulis: 1513350 op,  40% termerge
sda      baca: 5226351 op,  59% termerge   tulis: 3021688 op,  53% termerge
zram0    baca:   88120 op,   0% termerge   tulis:  127341 op,   0% termerge

Bedah perhitungannya:

  1. baca = $4 + $5: total operasi baca adalah jumlah yang selesai ditambah yang berhasil digabung — merge menyerap permintaan sehingga tidak dihitung dua kali sebagai operasi disk.
  2. $5 * 100 / baca: persentase permintaan baca yang dihemat scheduler lewat penggabungan.
  3. Pola hasilnya: sda (HDD) menunjukkan lebih dari separuh permintaannya termerge — tanda scheduler rajin mengurutkan demi menghemat seek; nvme0n1 lebih rendah karena tidak ada kepala yang perlu dihemat; zram0 nol persen karena perangkat RAM memakai scheduler none.

Desain antreannya dijelaskan lebih lanjut di dokumentasi I/O priority dan dokumentasi BFQ kernel.

Perhatikan benang merah chapter ini: agar setelan scheduler bertahan melewati reboot, kita menunggu momen perangkat muncul di sistem dan bereaksi saat itu juga. Momen kemunculan itu sendiri adalah sebuah event yang bisa kita tangkap dengan aturan — topik chapter udev rules berikutnya.