ionice 入門 - ディスクI/O優先度を制御する

ionice 入門 - ディスクI/O優先度を制御する

ionice とは何か?

結論: ionice は、プロセスごとにディスク I/O の優先度を設定・確認するコマンド。nice が CPU 時間を制御するのに対し、ionice は「誰が先にディスクへアクセスできるか」を制御する。

ioniceutil-linux パッケージに含まれる標準コマンドで、ほぼすべてのディストリビューションに最初から入っている。バックアップや大量コピーのような I/O 負荷の高い処理を「他のプロセスの邪魔をしないように」走らせたいときに使う。

基本の構文は 2 通り。

# これから起動するコマンドに優先度を付ける
ionice [オプション] コマンド [引数...]

# 既に動いているプロセス(PID 指定)の優先度を変更・確認する
ionice [オプション] -p PID...

なぜ ionice が必要なのか?

結論: バックアップや rsync が走るとサーバ全体が重くなる典型原因はディスク I/O の奪い合い。ionice で重い処理を低優先度に下げれば、本番サービスの応答を守れる。

CPU に余裕があっても、ディスクが 1 台しかなければ I/O は順番待ちになる。tarddrsyncdu のような処理がディスクを占有すると、同じディスクを使う Web サーバや DB のレスポンスが一気に悪化する。

nice で CPU 優先度だけ下げても、I/O 待ちが原因の遅延は解消しない。ここで効くのが ionice。重いバッチ処理を idle クラスに落とせば、「他に誰もディスクを使っていないときだけ動く」状態にできる。

topwa(iowait)が高いときは CPU ではなく I/O がボトルネック。この状況こそ ionice の出番。

スケジューリングクラスと優先度をどう指定するのか?

結論: クラスは -c で指定する。1=realtime(最優先・要 root)、2=best-effort(既定)、3=idle(暇なときだけ)。-n で 0(最高)〜7(最低)の優先度を付ける。

I/O スケジューリングクラスは 4 種類ある。

番号 クラス 意味 -n 優先度
0 none 明示クラスなし。CPU の nice 値から自動決定 無視
1 realtime 常に最優先でディスクへアクセス。他を飢餓させ得る 0〜7
2 best-effort 既定クラス。通常の処理 0〜7
3 idle 他がディスクを使っていないときだけ動く 無視

優先度 -n0 が最高、7 が最低。realtime と best-effort クラスでのみ意味を持ち、idle クラスでは無視される(idle は常に最低だから)。

# バックアップを idle クラスで実行(他の処理を一切邪魔しない)
ionice -c 3 tar czf /backup/data.tar.gz /var/data

# 大量コピーを best-effort の最低優先度で実行
ionice -c 2 -n 7 cp -a /src/huge.img /mnt/

# realtime クラス(最優先)。root 権限が必要
sudo ionice -c 1 -n 0 dd if=/dev/sdb of=/dev/sdc bs=1M

realtime(クラス 1)は root 権限が必須で、使い方を誤ると他のプロセスを完全に I/O 飢餓に追い込む。本番では基本的に idlebest-effort を使い、realtime は明確な理由があるときだけにする。

実行中のプロセスに後から適用するには?

結論: -p PID で動作中のプロセスにも適用できる。-p だけなら現在の優先度を確認、-c/-n と併用すれば変更できる。

起動時に ionice を付け忘れた重い処理にも、後から優先度を変えられる。

# PID 1234 の現在の I/O 優先度を確認
ionice -p 1234
best-effort: prio 4
# 動作中の PID 1234 を idle クラスに変更
ionice -c 3 -p 1234

# ユーザー単位・プロセスグループ単位でも指定できる
ionice -c 3 -u 1000      # UID 1000 の全プロセス
ionice -c 3 -P 5678      # プロセスグループ 5678

すでに暴走している dursync を見つけたら、pgrep rsync で PID を拾って ionice -c 3 -p $(pgrep rsync) で idle に落とすと、kill せずにサーバを軽くできる。

ionice が効かない時は何を確認するのか?

結論: I/O 優先度を尊重するのは BFQ スケジューラ(と旧 CFQ)だけ。多くの現代システム既定の mq-deadline / none では ionice のクラス指定が効かない。

これが ionice 最大の落とし穴。優先度は「I/O スケジューラ」が解釈して初めて効く。優先度をきちんと扱うのは歴史的には CFQ、現在は BFQ のみ。CFQ は Linux 5.0 で削除済みで、NVMe などで既定の nonemq-deadline は I/O 優先度を区別しない。

まず対象ディスクの現在のスケジューラを確認する。

# sda のスケジューラを確認([] で囲まれたものが現在の設定)
cat /sys/block/sda/queue/scheduler
none mq-deadline kyber [bfq]

[bfq] のように bfq が選択されていれば ionice が効く。[mq-deadline] などの場合は切り替える。

# bfq モジュールを読み込み(必要な場合)
sudo modprobe bfq

# sda のスケジューラを bfq に切り替え(再起動で元に戻る一時設定)
echo bfq | sudo tee /sys/block/sda/queue/scheduler

スケジューラの変更はディスクの全体特性に影響する。BFQ は公平性に強い一方、超高 IOPS の NVMe ではスループットが落ちる場合がある。本番では影響を検証してから恒久化(udev ルール等)すること。-c idle を付けても重い処理が他を圧迫し続けるなら、まずスケジューラを疑う。

nice と ionice はどう使い分けるのか?

結論: CPU バウンドな処理は nice、I/O バウンドな処理は ionice。両方重い処理には両方を併用するのが定石。

ボトルネック 使うコマンド
CPU(計算・圧縮) nice gzip, ffmpeg, ビルド
ディスク I/O ionice tar, rsync, dd, du
両方 併用 バックアップ全般

バックアップは CPU(圧縮)と I/O(読み書き)の両方を食うため、両方を下げるのが王道。

# CPU も I/O も最低優先度でバックアップ
nice -n 19 ionice -c 3 tar czf /backup/data.tar.gz /var/data

実務でよく使うパターンは?

結論: 「夜間バックアップ」「巨大ファイルのコピー・削除」「暴走プロセスの応急処置」の 3 つが定番。idle クラスを軸にコピペで使える型を持っておく。

# 1) cron の夜間バックアップを idle + nice で(本番に影響させない)
nice -n 19 ionice -c 3 rsync -a /var/www/ /backup/www/

# 2) 巨大ファイルの削除でディスクを占有させない
ionice -c 3 rm -rf /var/log/old-huge-dir/

# 3) 動作中の重いプロセスを応急で idle に落とす
ionice -c 3 -p "$(pgrep -d, -f backup-script)"

-t(--ignore)オプションを付けると、優先度設定に失敗してもコマンド自体は続行する。スケジューラが対応していない環境でもスクリプトを止めたくない場合に有効。

次に読む