ハードウェア中級 #5 ストレージ性能の実測 — fio・キュー深度・SSD の内部事情

読了 6分

第4回 までで CPU とメモリを見たので、次はストレージです。基礎 #4 で IOPS・スループット・レイテンシという 3 つの軸を押さえました。今回の問いは運用のものです。カタログに「50万 IOPS」と書かれたディスクが、自分のサービスではなぜ 5 万も出ないのか。答えは測定条件にあり、だからこの記事は自分で測るところから始めます。

カタログ数値の条件 #

ストレージの性能数値には常に条件が付いて回ります。ブロックサイズ (4KB か 128KB か)、パターン (シーケンシャルかランダムか)、読み書きの比率、そしてキュー深度です。カタログの最大 IOPS はたいてい「4KB ランダム読み取り、キュー深度数十以上」という、並列性を最大まで掛けた条件の数字です。自分のワークロードがその条件と違えば数字も違います。だから意味のある問いは「このディスクは何 IOPS か」ではなく、自分のワークロードの形でいくつ出るか です。

fio — ワークロードの形どおりに測る #

標準の測定ツールは fio です。ブロックサイズ、パターン、並列性を指定して、欲しい形の負荷を作ってくれます。

terminal
# 4KB ランダム読み取り、キュー深度 1 — レイテンシがそのまま現れる条件
fio --name=randread --filename=/data/fio.test --size=4G \
    --rw=randread --bs=4k --iodepth=1 --runtime=60 --time_based \
    --ioengine=libaio --direct=1
結果で見る 3 行
read: IOPS=11.2k, BW=43.8MiB/s
 lat (usec): avg=88.1, ...
 lat percentiles : 99.00th=[ 180], 99.90th=[ 420]

読み方を 2 つだけ押さえます。

  • --direct=1 が肝心 です。ページキャッシュを迂回してディスク自体を測るオプションです。これがないと 第3回 で見たページキャッシュが割り込み、メモリの速度を測ることになります。
  • 平均より パーセンタイルのレイテンシ を見ます。平均 88µs は良さそうに見えても、99.9 パーセンタイルが数 ms なら、千回に 1 回は遅い I/O が混ざるという意味です。ユーザーの体感とデータベースのテールレイテンシを作るのはパーセンタイルの側です。

注意したいのは、fio が実負荷だという点です。稼働中のディスクに書き込みテストを回すとサービスの I/O と競合し、--filename を誤るとデータを上書きしかねません。測定は専用ファイルと暇な時間帯で、できれば同等クラスの非本番機で行います。

キュー深度 — IOPS とレイテンシの取引 #

キュー深度 (queue depth、ディスクに同時に掛けておく未完了 I/O リクエストの数) は、カタログ数値と体感の差を説明する鍵です。SSD、特に NVMe は内部が並列構造なので、リクエストを複数掛けてやらないと全体性能が出ません。

キュー深度IOPS平均レイテンシ意味
111k0.09ms一度に 1 つ。レイテンシは最小、スループットは一部だけ
870k0.11ms並列性が効き始める
32200k0.16msスループット上昇、レイテンシも上昇
128350k0.36msカタログ付近。レイテンシは 4 倍

(数値は測定例で、機材ごとに異なります。) パターンが見えます。キューを積むほど IOPS は上がり、レイテンシも上がります。第1回の使用率と飽和がここでそのまま再現されます。キュー深度がそのまま飽和の量だからです。だから「カタログの IOPS が出ない」という不満の半分は、キュー深度 1 の直列ワークロード (例: 単一スレッドで fsync を繰り返す DB のコミット) をカタログ条件と比べたものです。そうしたワークロードの性能は IOPS ではなく キュー深度 1 のレイテンシ が決めます。

SSD の内部事情 — 書き込み増幅と TRIM #

同じ SSD が昨日は速く今日は遅い、ということがあります。原因はたいてい SSD 内部の動作にあります。

  • SSD のフラッシュは 上書きができません。消してから書き直す必要があり、消す単位 (ブロック) は書く単位 (ページ) よりずっと大きいです。そこでコントローラは空き領域に新しく書き、旧データを無効としてマークし、あとで有効ページだけを集めて移し、ブロックを消す掃除 (ガベージコレクション) を回します。
  • この過程で、ユーザーが 1 を書くと内部ではその数倍を書くことになる現象が書き込み増幅 (write amplification) です。ディスクが埋まるほど、そしてランダム書き込みが多いほど掃除が頻繁になり、増幅が大きくなって書き込み性能が落ちます。
  • TRIM は、ファイルシステムが「この領域は削除済みのデータだ」と SSD に知らせるコマンドです。コントローラが無効ページを先に知っていれば掃除が軽くなります。Linux では通常、定期的な fstrim (systemd タイマー) で回します。

運用上の含意は 3 つです。SSD は 満杯にしないこと自体が性能管理 であり (空き容量が掃除側の作業スペースです)、TRIM が実際に回っているかは確認する価値があり、書き込み性能の測定は十分長く回してこそ (短いテストは掃除が始まる前の一瞬だけの性能を測ります) 本当の数字が出ます。

クラウドディスクでは #

クラウドブロックストレージ (EBS など) では、同じ原理が違う形で現れます。IOPS とスループットが ボリュームのタイプとサイズ、そしてインスタンス自体の上限 で決まっているため、fio で測るとディスクの物理性能ではなく契約上の上限が測定されます。ディスクは速いのにインスタンス側の上限に引っかかる場合もよくあるので、ボリュームとインスタンスの両方の上限表を併せて見る必要があります。基礎 #9 で見た「スペック表の読み方」がストレージでも繰り返されるわけです。

よく出会う落とし穴 #

  • キャッシュ込みで測る — direct なしで測るとページキャッシュの速度が出ます。ディスクを測るときは --direct=1、サービス全体を測るときだけキャッシュ込みで測ります。
  • 平均レイテンシで判断する — テール (99 パーセンタイル以上) がユーザーの体感を決めます。平均が良くてもテールが長ければ「ときどき遅い」サービスになります。
  • 空の SSD で測った数字を信じる — 新品の SSD や空にした直後の SSD は掃除の負担がなく、しばらくは速いです。運用時の使用率まで埋めた状態で、十分長く測ってこそ運用性能です。

まとめ #

今回つかんだ絵です。

  • ストレージの数値はブロックサイズ・パターン・キュー深度という条件の関数です。fio で自分のワークロードの形どおりに測ります。
  • キュー深度を積むと IOPS とレイテンシが一緒に上がります。直列ワークロードの性能はキュー深度 1 のレイテンシが決めます。
  • SSD は書き込み増幅と掃除のため、埋めるほど、そして時間が経つほど書き込み性能が変わります。空き容量と TRIM が管理手段です。
  • クラウドディスクは物理性能ではなく契約上の上限が測定されます。ボリュームとインスタンスの両方の上限を見ます。

次回 — RAID 運用 #

次回の「ハードウェア中級 #6 RAID 運用の実際 — リビルド・スクラブ・バックアップ」では、ディスク 1 枚から複数枚へ進みます。基礎 #5 で RAID レベルの概念を押さえたなら、今回はディスクが実際に死んだ後の話です。リビルドがなぜ危険な時間なのか、ホットスペアとスクラブが何を防いでくれるのか、そして RAID がバックアップではない理由を、運用インシデントの目線で扱います。

X