I/Oスケジューラ・チューニングでは、特に以下の点を最適化する。 カーネル-パスでメモリ・アクセスを行い、ホスティング環境での待ち時間を短縮する。この記事では、Linuxのディスク・スケジューリングをハードウェアとワークロードに適合させる方法を、実践的な方法で紹介している。 ホスティング 安全にパフォーマンスを発揮する。.
中心点
以下の要点は、この記事の内容を簡単に説明するものである。.
- スケジューラーの選択ハードウェアとワークロードに応じて、noop/none、mq-deadline、BFQ、Kyber
- 測定戦略変更前後のFio、iostat、P95/P99、IOPS、スループット
- 微調整QoSのためのReadahead、RQ-Affinity、Cgroups、ionice
- 永続性udevルールと永続的プロファイルのGRUBパラメータ
- 練習待ち時間のピーク、公平性、NVMe特有のトラブルシューティング
Linuxのディスクスケジューリングの仕組み
私は、I/Oスケジューラーを、要求を次のようなものに変換するコントロールセンターと見ている。 キュー ソート、マージ、優先順位付けを行う。HDDでは、リクエストをブロックアドレスに従って整理することで高価なヘッド移動を回避し、検索時間を短縮している。SSDとNVMeでは、並列性が支配的です。そのため、マルチキューサブシステムblk-mqは、パスをより広くし、複数のリクエストに優先順位をつけます。 CPU 分散されている。これにより、多くのサービスが同時に書き込みや読み込みを行っても、レイテンシーを減らし、ピークをスムーズにし、スループットを軌道に乗せることができる。ホスティングでは、ウェブサーバー、データベース、バックアップジョブが一緒になっているので、私は常に支配的なアクセスパターンに合わせてスケジューリングしています。.
一般的なスケジューラについて簡単に説明する。
NVMeと最新のSSDの場合、私はよく次のものを選ぶ。 なし (mq-deadlineは、読み込みと書き込みに固定のデッドラインを設定し、読み込み処理を優先し、サーバーの負荷が混在していても一定の応答時間を実現する。BFQはプロセス間で帯域幅を公平に分配し、個々のVMがディスクを占有するようなマルチテナントのセットアップに適しています。Kyberは低レイテンシーを目指し、目標時間を超えた場合は受信リクエストをスローダウンする。CFQはレガシー・ソリューションと考えられており、NVMeにはほとんど適合しません。私は、レガシー・セットアップがCFQを必要とするか、テストによって明らかな利点が示された場合にのみCFQを使用します: I/Oスケジューラガイド.
I/Oスケジューラのチューニング・ステップ・バイ・ステップ
私は明確なものから始める。 ベースライン-客観的に利益を示せるようにするためだ。合成パターンにはfioを使い、デバイス統計にはiostatを使い、リードとライトのP95/P99レイテンシを収集する。そして、デバイスごとにアクティブなスケジューラをチェックし、実行時に変更して素早くカウンターテストを行う。私は、安定した測定でその選択が正しいことがわかったときだけ、持続的な調整を行う。こうすることで、間違った判断で後で高額なロールバックを余儀なくされることを防いでいる。.
# 現在のスケジューラをチェックする
cat /sys/block//queue/scheduler
# その場で変更(例:nvme0n1からmq-deadlineへ)
echo mq-deadline | sudo tee /sys/block/nvme0n1/queue/scheduler
# fioによる高速比較(ランダムリード4k)
fio --name=rr --rw=randread --bs=4k --iodepth=32 --numjobs=4 --runtime=60 --filename=/dev/nvme0n1
私はCPUの負荷に目を光らせている。 スケジューラ を使うと、追加のコンテキスト・スイッチが発生するため、正味のパフォーマンスが低下する。レイテンシーが下がり、スループットが上がったら、すぐに決定を保存し、テストプロファイルを文書化する。それぞれのステップの後に変更を加え、次に測定を行うことで、原因と結果を明確に分けることができる。この規律は、サーバーに複数のディスククラスがインストールされ、個々のデバイスが異なる反応を示したときに実を結ぶ。.
微調整:Readahead、RQ-Affinity、Cgroups
スケジューラーを選択した後、次のように調整する。 キュー-パラメータで指定する。シーケンシャルバックアップの場合はreadaheadを上げ、ランダムIOの場合は不要なページをロードしないように下げます。RQアフィニティを使って、リクエストが発生したコアに処理が完了するようにし、レイテンシとキャッシュのローカリティを改善します。ioniceを使ってバックアップやインデックス作成などのプロセスをダウングレードし、ウェブリクエストに支障が出ないようにしています。マルチテナント環境では、Cgroups v2を使って帯域幅とIOPSを調整し、顧客ごとにハードリミットを設定しています。.
# シーケンシャルパターン用リードアヘッド
echo 128 | sudo tee /sys/block//queue/read_ahead_kb
# RQアフィニティ: 2 = 生成コアで完了
echo 2 | sudo tee /sys/block//queue/rq_affinity
# バックアッププロセスを下げる
ionice -c2 -n7 -p
# Cgroup v2: ウェイトとリミット (例 major:minor 8:0)
echo 1000 | sudo tee /sys/fs/cgroup/hosting/io.weight
echo "8:0 rbps=50M wbps=25M" | sudo tee /sys/fs/cgroup/hosting/io.max
プロファイルのホスティングには、どの選択が適切か?
を決める。 スケジューラ-ハードウェア・クラス、アクセス・パターン、ターゲット・サイズ(レイテンシ対スループット対フェアネス)に応じて選択します。シングルテナントVMのNVMe SSDは、コントローラが広範な最適化を実行し、すべてのソフトウェアレイヤーが重要であるため、通常、何のメリットもない。SSDの読み込み/書き込み負荷が混在している場合、読み込み要求を優先してレスポンスタイムを保護するmq-deadlineを使用することが多い。共有ホスティング環境では、顧客間の公平性を確保し、帯域幅の独占を防ぐためにBFQを選択します。ターゲットレイテンシーが重要で、特定のワークロードのハードリミットを守らなければならない場合は、Kyberを使っています。.
| スケジューラ | 適切なハードウェア | 典型的なワークロード | メリット | 備考 |
|---|---|---|---|---|
| Noop/なし | NVMe, モダンSSD | 多くの並列リード/ライト、VM | 最小限のオーバーヘッド、高い並列性 | SAN/RAIDでのテスト。 |
| mq-デッドライン | SSD、, 睡眠時無呼吸症候群, 高速HDD | ウェブとDBの混在負荷 | リード・レイテンシーを優先、スループットは良好 | 締切値は保守的、微調整は可能 |
| BFQ | マルチテナントにおけるSSD/HDD | 多くのユーザー、cグループ | 明確な公平性と帯域制御 | 若干の事務的労力、クリーンな重み付け |
| カイバー | SSD、, NVMe | レイテンシーが重要なサービス | 制御可能なターゲットレイテンシー | スロットルを正しく設定するために正確に測定する |
| シーエフキュー | レガシー・ハードウェア | レガシーワークロード | 旧標準液 | 最近のNVMe/SSDではほとんど役に立たない |
実用的なプロファイルと測定値
多数の小さな 読み物 P95のレイテンシは純粋なIOPSよりも重要なので、キープアライブとTLSを組み合わせたリクエストをテストしている。データベースは同期書き込みをもたらすので、fioジョブファイルでフラッシュ動作とfsyncコストをシミュレートする。バックアップ・ウィンドウにはシーケンシャル・ストリームがあることが多い。ここではスループットをMB/sで測定し、フロントエンドのリクエストが長く待たされないようにする。私のテストでは、スケジューラとリードアヘッドがワークロードにマッチしていれば、最初の状況にもよりますが、20~50 % 応答時間が短くなります。ディスクスループットの測定について、さらに詳しい説明が必要な場合は、こちらを参照してください: ホスティングにおけるディスクスループット.
永続的な構成と自動化
にアンカーを打つ。 チョイス リブート後にデバイスが適切なモードで直接起動するように、udevルールを介して恒久的に設定します。NVMeにはnone、SSDにはmq-deadline、回転メディアにはBFQを設定することが多い。同種のセットアップを実行している場合は、オプションでGRUB経由でグローバル・デフォルトを設定します。ルールは短くし、チームが追跡できるように設定リポジトリに文書化しています。より詳細なカーネル最適化については、この記事がセットアップを補足している: ホスティングにおけるカーネルのパフォーマンス.
# /etc/udev/rules.d/60-ioschedulers.rules
# NVMe: なし
ACTION=="add|change", KERNEL=="nvme[0-9]*", ATTR{queue/scheduler}="none"
# SSD: mq-deadline
ACTION=="add|change", KERNEL=="sd[a-z]|vd[a-z]", ATTR{rotational}=="0", ATTR{queue/scheduler}="mq-deadline"
# HDD: BFQ
ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{rotational}=="1", ATTR{queue/scheduler}="bfq"
# ルールのリロード/テスト
udevadm control --reload
udevadm trigger
# GRUB経由のオプションのグローバルデフォルト
# /etc/default/grub
GRUB_CMDLINE_LINUX_DEFAULT="elevator=mq-deadline" とする。
更新-grub
Cgroups v2とioniceによるQoS
どの仕事もプレートに残らないように ちっそく, 私はCgroups v2のQoSルールに依存し、ioniceで優先順位を追加しています。プレミアムテナントに対してはio.weightを上げ、うるさい隣人に対してはio.maxでハードリミットを設定している。systemdユニットをCgroupsに直接バインドして、起動時にサービスが自動的に適切なクラスに入るようにしている。顧客からの問い合わせがスムーズに続くように、短期的なメンテナンス作業を一時的にスロットルする。このような重み付け、制限、プロセスの優先順位の相互作用によって、負荷がかかっているときでも予測可能な応答時間が生まれます。.
# cgroupの作成と制限の設定
mkdir -p /sys/fs/cgroup/hosting
echo 1000 | tee /sys/fs/cgroup/hosting/io.weight
echo "8:0 rbps=100M wbps=60M" | tee /sys/fs/cgroup/hosting/io.max
#プロセスをCgroupに移動する。
echo | tee /sys/fs/cgroup/hosting/cgroup.procs
# 二次ジョブの IO 優先度を低くする
ionice -c2 -n7 -p を実行する。
モニタリングとトラブルシューティング
私は常にテレメトリーを維持している 閉じる そうしないと、判断を誤るからだ。iostatでサービス時間とキューの深さを読み、blktraceでリクエストフローを分析し、sar/dstatでシステム負荷の経時変化を見る。レイテンシーについては、平均値だけを見るのではなく、常にP95/P99を見るようにしています。もしP95が良くてもP99がダメなら、キューの深さやRQアフィニティーを調整し、競合するジョブをチェックします。各修正の後、同じ主要な数値を比較することで、効果の信頼性を保つようにしている。.
典型的なつまずきと解決策
高い レイテンシー SSDの場合、不適切なスケジューラを示していることがよくあります。すぐにmq-deadlineをテストし、読み込みが速くなったかどうかを確認します。私は、マルチテナント・セットアップにおける不公平な分散をBFQで解決し、Cgroupのウェイトをクリアして、強い顧客が弱い顧客を押しのけてしまわないようにしています。NVMeのタイムアウトは、ファームウェアまたはアグレッシブすぎるポーリングを示します。このような場合、io_pollを無効にし、安定性が戻るまで深度を下げます。バックアップウィンドウで変動するスループットは、特に大きなファイルが支配的な場合、カスタマイズされたreadaheadで平滑化できることが多い。より多くの要因が同時に回転している場合、私はステップバイステップで進める。.
スケジューラ・チューナブルの詳細
基本的な選択が終わったら、それぞれのスケジューラの調整ネジを回す。各デバイスで利用可能なパラメーターはカーネルやディストロによって異なるので、私はいつもそれを見ることから始める。.
# 利用可能なチューナブルを表示する
ls -1 /sys/block//queue/iosched
cat /sys/block//queue/iosched/* を実行します。
# 例: mq-deadline は書き込みの多いジョブに対してより保守的である。
echo 100 | sudo tee /sys/block//queue/iosched/read_expire
echo 500 | sudo tee /sys/block//queue/iosched/write_expire
echo 1 | sudo tee /sys/block//queue/iosched/front_merges
# の例: BFQ で公平性を高め、アイドル時間を短くする
echo 1 | sudo tee /sys/block//queue/iosched/low_latency
echo 0 | sudo tee /sys/block//queue/iosched/slice_idle
mq-deadlineでは、主に次のような規制を行っている。 read_expire/write_expire (ミリ秒)と front_merges 保留中のリクエストをマージするためだ。BFQでは、テナントの密度に応じて、次のように切り替える。 低遅延 そして slice_idle, フロー間の待ち時間を短縮する。不正確な有効期限は、バースト負荷の下で望ましくない待ち時間のピークを引き起こす可能性があるため、私はすべての変更を測定値で文書化する。.
ファイルシステムとマウントオプション
スケジューラーのチューニングが本領を発揮するのは、ファイルシステムがマッチしたときだけだ。私は次のことに注意している:
- リレイタイム/ノータイム不必要なメタデータの書き込みアクセスを避ける。.
- ディスカード vs フストリムSSD/NVMeでは、レイテンシのピークを避けるために、オンライン廃棄の代わりに定期的なfstrimを使うことが多い。.
- ジャーナリングext4については、以下のことが証明されている。 data=ordered (デフォルト)と適切な コミット-間隔(例えば、データ損失の許容範囲に応じて10-30秒)。.
- 障壁ライトバリアはアクティブのままである。ハードウェアが停電保護(バッテリー/キャパシター)を保証しない限り、私はそれを解除しない。.
# ext4の/etc/fstabの例
UUID= /data ext4 defaults,noatime,commit=20 0 2
# 廃棄オプションの代わりに周期的 TRIM を有効にする
systemctl enable fstrim.timer
systemctl start fstrim.timer
XFSの場合は ノータイム そしてfstrim.timerを好む。ジャーナルやバリアのオプションはディストリビューションに依存する。私はいつも特定のカーネルとFSの組み合わせをテストし、P95/P99を測定する。.
RAID、LVM、DM-crypt、マルチパス
スタックセットアップ(デバイスマッパー、LVM、mdraid、マルチパス)では、アプリケーションがI/Oを見る場所、つまり トップレベル・デバイス - そして、その下での二重選別を防ぐ。.
# スケジューラーをトップレベル(例えばdm-0)に設定する。
echo mq-deadline | sudo tee /sys/block/dm-0/queue/scheduler
# 二重スケジューリングを避けるため、NVMe/SAS デバイスを "none" にする。
for d in /sys/block/nvme*n1 /sys/block/sd*; do echo none | sudo tee $d/queue/scheduler; done
# mdraid: リードアヘッドとストライプキャッシュの最適化 (RAID5/6)
sudo blockdev --setra 4096 /dev/md0
echo 4096 | sudo tee /sys/block/md0/md/stripe_cache_size
暗号化ボリューム(dm-crypt/LUKS)では、CPUオフロード(AES-NI)に注意を払い、I/Oパスがワークキューを不必要にさまよわないようにする。特に、暗号レイヤーのために増加する可能性がある同期ライトレイテンシを測定している。マルチパス環境(SAN/iSCSI)では、マルチパスデバイス(dm-X)のスケジューラを設定し、パスのフェイルオーバーで異常値が発生しないことを確認する。.
仮想化とコンテナ:ホストとゲスト
KVMスタックでは、ホストとゲストを意図的に分けている。KVMスタックでは ゲスト 私は通常virtioデバイスに使用している。 なし, ハイパーバイザーが最適化を引き継ぐ。ハイパーバイザーは ホスト それから、ハードウェア(SSD/NVMeでは多くの場合、none/mq-deadline)に合った物理デバイスごとのスケジューラを選択する。.
# ゲスト (virtio-blk/virtio-scsi):スケジューラを "none" に設定
echo none | sudo tee /sys/block/vda/queue/scheduler
# ホスト: virtio-blk 用の iothreads および multiqueue を備えた QEMU
qemu-system-x86_64 \
-drive if=none,id=vd0,file=/var/lib/libvirt/images/guest.qcow2,cache=none,aio=ネイティブ
-object iothread,id=ioth0 ୧-͈ᴗ-͈)◞ʱʱ
-device virtio-blk-pci,drive=vd0,num-queues=8,iothread=ioth0
私はコンテナを直接Cgroups v2にバインドし、systemdプロパティ(IOWeight、IOReadBandwidthMax/IOWriteBandwidthMax)を使用して、サービスが正しいI/Oバジェットで自動的に開始するようにしている。重要:ルールの衝突を避けるため、コンテナまたはホストサービスのどちらか1つのレベルでのみ優先順位を設定すること。.
NUMA、IRQ、ポーリングの最適化
マルチソケット・システムでは、I/OとCPUを考慮する。 NUMAに近い. .NVMe割り込みの分散をチェックし、irqbalanceが最適でない場合は必要に応じて調整します。また、blk-mqオプションを使用して、完了をローカルに保ちます。.
# NVMe 割り込みのチェックとコアマスクの設定 (例)
grep -i nvme /proc/interrupts
echo | sudo tee /proc/irq//smp_affinity
# blk-mq: 生成コアの完了
echo 2 | sudo tee /sys/block//queue/rq_affinity
# オプション: ワークロードに応じてI/Oポーリングをテストする(慎重に使用する)
echo 0 | sudo tee /sys/block//queue/io_poll
NVMeの場合、CPU負荷とレイテンシの比率を滑らかにするために、コントローラの機能を使って割り込み合体パラメータを調整することができます。私はここで小さなステップを踏んで、P99が安定したままか、合体によって目に見える不調につながるかをチェックします。.
FIOの職務プロファイルと測定計画のサンプル
私は再現可能なジョブファイルを作成し、カーネル、スケジューラー、キューパラメーター、ファイルシステムのマウントをメモしている。これにより、数週間にわたって結果を比較することができる。.
# db-sync.fio - DB ライクな同期書き込み (ext4/XFS)
[グローバル]
ioengine=libaio
direct=1
filename=/dev/ファイル名
時間ベース=1
ランタイム=90
スレッド=1
ジョブ数=8
iodepth=1
[randwrite-sync4k]
rw=randwrite
bs=4k
同期=1
# web-randread.fio - ウェブライクリード
[グローバル]
ioengine=libaio
direct=1
filename=/dev/ ファイル名
時間ベース=1
ランタイム=90
スレッド=1
ジョブ数=8
iodepth=32
[randread-4k]
rw=randread
bs=4k
# 計測フレーム
# 1)ウォームアップ60秒、2)測定90秒、3)クールダウン30秒
#パラレル:iostat、pidstat、blktraceの実行
iostat -x 1| tee iostat.log &| pidstat -dl 1
pidstat -dl 1 | tee pidstat.log & を実行。
blktrace -d /dev/ -o - | blkparse -i -d trace.dump &
# トレース: fio-JSONからP95/P99を取り出す
fio --output-format=json --output=fio.json db-sync.fio
jq '.jobs[].lat_ns["percentile"]|{p95:.["95.000000"],p99:.["99.000000"]}' fio.json
スケジューラーやread_ahead_kbなど1つの変数だけを変更して、同じジョブファイルを再度比較します。数回の実行で一貫した改善が見られた場合のみ、設定をコミットする。.
変更管理:安全な導入とロールバック
生産的なホスティング環境では、私はI/Oの変更をロールアウトする。 千鳥 私はまずカナリアホストから始め、次に小規模なAZ/クラスタバッチを作成し、それから大規模なロールアウトを行います。Udevのルールをバージョン管理し、各変更を測定値付きチケットに添付する。ロールバックの際には、以前の値(スケジューラー、read_ahead_kb、Cgroup limits)を再生するスクリプトを用意しています。こうすることで、ワークロードが急遽変更になった場合でも、介入を可逆的なものに保つことができる。.
要約:私はこう進める
私は明確なものから始める。 実績値, レイテンシーとスループットを測定し、セットアップを文書化します。NVMe/仮想SSDにはnone、混合サーバー負荷にはmq-deadline、多数のユーザーがいる共有環境にはBFQなどだ。その後、リードアヘッド、RQアフィニティ、プロセス優先度を微調整し、フロントエンドのワークロードを優先させる。計測の結果、一貫してその選択が有効であれば、udev/GRUBを使って修正し、パラメータを書き込む。ワークロードが変化しても、モニタリングは有効なままである。 パフォーマンス 永久に高い。.


