ionice: Controlling Disk I/O Priority
What Is ionice?
Conclusion:
ionicesets and queries the disk I/O priority of a process. Wherenicecontrols CPU time,ionicecontrols who gets to access the disk first.
ionice ships with the util-linux package and is preinstalled on virtually every distribution. You use it to run I/O-heavy jobs (backups, bulk copies) so they stay out of the way of everything else.
There are two basic forms:
# Apply a priority to a command you are about to start ionice [options] command [args...] # Change or query a process that is already running (by PID) ionice [options] -p PID...
Why Do You Need ionice?
Conclusion: When a backup or
rsyncmakes the whole server crawl, the usual cause is disk I/O contention. Lowering the heavy job's priority withioniceprotects the response time of your real services.
Even with plenty of free CPU, a single disk serializes I/O requests. When tar, dd, rsync, or du saturates the disk, any web server or database on the same disk suddenly slows to a crawl.
Lowering CPU priority with nice does nothing for delays caused by I/O wait. That is exactly where ionice helps: drop a heavy batch job into the idle class and it only runs "when nobody else is using the disk."
A high wa (iowait) in top means the bottleneck is I/O, not CPU. That is precisely when ionice earns its keep.
How Do You Specify the Class and Priority?
Conclusion: Set the class with
-c:1=realtime (top priority, root only),2=best-effort (default),3=idle (only when idle). Use-nfor a level from 0 (highest) to 7 (lowest).
There are four I/O scheduling classes.
| Number | Class | Meaning | -n priority |
|---|---|---|---|
| 0 | none | No explicit class; derived from the CPU nice value | ignored |
| 1 | realtime | Always gets disk access first; can starve others | 0–7 |
| 2 | best-effort | Default class for normal work | 0–7 |
| 3 | idle | Runs only when no one else needs the disk | ignored |
The -n level runs 0 (highest) to 7 (lowest). It only matters for the realtime and best-effort classes; the idle class ignores it (idle is always lowest).
# Run a backup in the idle class (never disturbs other work) ionice -c 3 tar czf /backup/data.tar.gz /var/data # Bulk copy at best-effort lowest priority ionice -c 2 -n 7 cp -a /src/huge.img /mnt/ # realtime class (top priority); requires root sudo ionice -c 1 -n 0 dd if=/dev/sdb of=/dev/sdc bs=1M
realtime (class 1) requires root and, misused, can completely I/O-starve other processes. In production, stick to idle or best-effort; reach for realtime only with a clear reason.
How Do You Apply It to a Running Process?
Conclusion: Use
-p PIDon a live process.-palone shows the current priority; combine it with-c/-nto change it.
You can re-prioritize a heavy job even if you forgot ionice at launch.
# Show the current I/O priority of PID 1234 ionice -p 1234
best-effort: prio 4
# Move the running PID 1234 into the idle class ionice -c 3 -p 1234 # You can also target by user or process group ionice -c 3 -u 1000 # all processes of UID 1000 ionice -c 3 -P 5678 # process group 5678
Spot a runaway du or rsync? Grab its PID with pgrep rsync and drop it to idle with ionice -c 3 -p $(pgrep rsync) — you lighten the server without killing the job.
What If ionice Has No Effect?
Conclusion: Only the BFQ scheduler (and the legacy CFQ) honors I/O priorities. The
mq-deadline/noneschedulers that are default on many modern systems ignoreioniceclasses.
This is the biggest gotcha. A priority only takes effect once the I/O scheduler interprets it. Historically that was CFQ; today only BFQ does. CFQ was removed in Linux 5.0, and the none or mq-deadline defaults common on NVMe do not distinguish I/O priorities.
First, check the current scheduler for the target disk.
# Check sda's scheduler (the value in [] is active) cat /sys/block/sda/queue/scheduler
none mq-deadline kyber [bfq]
If [bfq] is selected, ionice works. If it shows [mq-deadline] or similar, switch it.
# Load the bfq module if needed sudo modprobe bfq # Switch sda's scheduler to bfq (temporary; reverts on reboot) echo bfq | sudo tee /sys/block/sda/queue/scheduler
Changing the scheduler affects the disk's overall behavior. BFQ is strong on fairness but can reduce throughput on very high-IOPS NVMe. Validate the impact before making it permanent (e.g. via a udev rule). If -c idle still lets a heavy job crowd everyone out, suspect the scheduler first.
When Do You Use nice vs ionice?
Conclusion: Use
nicefor CPU-bound work andionicefor I/O-bound work. For jobs that are heavy on both, combine them.
| Bottleneck | Command | Examples |
|---|---|---|
| CPU (compute) | nice |
gzip, ffmpeg, builds |
| Disk I/O | ionice |
tar, rsync, dd, du |
| Both | combine | backups in general |
Backups consume both CPU (compression) and I/O (read/write), so lowering both is the standard move.
# Lowest priority for both CPU and I/O nice -n 19 ionice -c 3 tar czf /backup/data.tar.gz /var/data
What Are the Common Real-World Patterns?
Conclusion: The three staples are "nightly backups," "copying/deleting huge files," and "first aid for a runaway process." Keep copy-paste templates built around the idle class.
# 1) Nightly cron backup at idle + nice (no impact on production) nice -n 19 ionice -c 3 rsync -a /var/www/ /backup/www/ # 2) Delete huge files without hogging the disk ionice -c 3 rm -rf /var/log/old-huge-dir/ # 3) First aid: drop a running heavy process to idle ionice -c 3 -p "$(pgrep -d, -f backup-script)"
The -t (--ignore) option lets the command keep running even if setting the priority fails. Handy when you do not want a script to abort on systems whose scheduler does not support priorities.