ストレージ実務 — RAID・スナップショット・iSCSI・fio
「ディスクが遅い」を数字に変える — IOPS・レイテンシ・キュー深度と fio
一言でいうと
ディスクの性能は、数字1つではなく3つです。毎秒何回か(IOPS)、毎秒どれだけか(スループット)、1回にどれだけかかるか(レイテンシ)。この3つは、ブロックサイズとキューの深さによって互いに変わるので、「何IOPS出ますか」は、条件を一緒に言わなければ何の意味もありません。fioは、その条件を固定して測るツールです。
なぜ必要なのか
「ストレージが遅い」という報告は、ほとんど証拠がありません。新しいストレージを買う前、LUNを移す前、クラウドのボリュームのグレードを選ぶ前に、同じ条件で測った数字があって初めて比較になります。ところが、dd if=/dev/zero of=파일(プレースホルダーはファイル名です)で測った数字は、ほとんどいつも間違っています。書き込みはページキャッシュに先に入ってメモリの速度が出てしまい、1回に1つずつシーケンシャルに書くので、データベースが実際に行う小さなランダム読み取りとは、まったく別のことを測っているからです。
どう動くのか
3つの数字の関係。スループット = IOPS × ブロックサイズです。4KiBで10,000 IOPSなら約40MiB/sで、1MiBで400 IOPSなら400MiB/sです。データベースのランダム読み取りは小さなブロックなので、IOPSとレイテンシが重要で、バックアップや大容量コピーは大きなブロックなので、スループットが重要です。そのため、測定は「何を模すのか」から決めます。
キューの深さとリトルの法則。同時に飛んでいるリクエスト数が、キューの深さ(queue depth)です。待ち行列理論のリトルの法則は、「システムの中にとどまる平均個数 = スループット × 平均滞在時間」です。ストレージに当てはめると、同時リクエスト数 ≈ IOPS × 平均レイテンシです。キューの深さが1なら、IOPSは1 ÷ レイテンシを超えられません。レイテンシが0.2msなら、最大5,000 IOPSです。キューの深さを上げると、デバイスが複数のリクエストを重ねて処理するのでIOPSは上がりますが、リクエスト1つ1つは列に並ぶので、レイテンシも上がります。ストレージの仕様書の大きなIOPSは、たいてい深いキューで測った値で、1回に1つずつ待つアプリケーションは、その数字を決して見られません。
平均ではなくパーセンタイル。平均レイテンシが1msでも、100回に1回50msかかるなら、リクエストごとにディスクを何回も読むサービスは、その尾をよく踏みます。そのため、p99(99パーセンタイル)のレイテンシも一緒に見ます。
fioのオプション。fioのドキュメントのオプションのうち、結果を左右するものは、いくつかです。
| オプション | 意味 | このラボの値 |
|---|---|---|
rw |
読み取り/書き込み、シーケンシャル/ランダム | randread |
bs |
ブロックサイズ | 4k |
ioengine |
リクエストを出す方式 | libaio(非同期で、キューの深さが意味を持つ) |
iodepth |
キューの深さ | 1と32 |
direct |
ページキャッシュのバイパス | 1 |
runtime・time_based |
決められた時間の間、続ける | 10秒 |
output-format |
出力形式 | json |
direct=1は、O_DIRECTで開いて、ページキャッシュを飛ばします。これを外すと、2回目の読み取りからメモリで答えが出て、ディスクではなくRAMを測ります。ioengine=libaioではなく、同期方式(psync)だと、iodepthを上げても1回に1つずつしか出ないので、キューの深さの実験になりません。
JSONの読み方。--output-format=jsonの結果のjobs[0].readの下に、iops、レイテンシの統計のlat_ns(平均はmean)、完了レイテンシのclat_ns.percentileの"99.000000"キーがあります。単位がナノ秒なので、マイクロ秒に直すときは1,000で割ります。人が読む既定の出力をコピーせず、JSONから数字を取り出すと、レポートと再現が一致します。
現場での姿
クラウドのブロックボリュームは、たいていIOPSとスループットの上限をグレードとして売ります。その上限は、十分に深いキューでしか届きません。アプリケーションがキューの深さ1で同期書き込みをすると(例: トランザクションごとにfsyncするデータベースのログ)、高いグレードを買っても、レイテンシの分しか出ません。そのとき見る数字は、IOPSではなくレイテンシです。
新しいストレージの導入試験では、本番の負荷を模した条件を2、3個決めておき、いつも同じコマンドで測ります。コマンドとJSONの結果を一緒に保管しておけば、半年後に「前より遅くなった」と言われたときに、同じコマンドをもう一度実行して、数字で答えられます。測定は、本番稼働中のファイルシステム上の専用ファイルで行い、生のデバイスに書き込み測定をするのはデータを消すことなので、空のデバイスでだけ行います。そして、測定中はiostat -xを横に表示しておくと、fioの数字と、カーネルが見たデバイスの数字が合っているかも、一緒に確認できます。
次のラボですること
同じVMの中にLIOターゲットを立ち上げて512MiBのLUNを提供し、イニシエーターでディスカバリー・ログインして、新しいディスクがiscsiとして見えるかを確認します。ext4でフォーマットして、_netdevが付いたfstabの行でマウントし、自動ログインを有効にします。その上の専用ファイルに対して、4KiBのランダム読み取りを、キューの深さ1と32で測り、JSONからIOPS・p99・平均レイテンシを取り出して、リトルの法則が合っているかを確認します。