🗄️

Persistent Diskのパフォーマンスについて

2024/12/25に公開

こんにちは。Google Cloud Supportの笠井です。
Google Cloud Japan Advent Calendar 2024 の25日目、最後の記事になります。

最後の記事なのに少し地味ではありますが、本記事ではPersistent Disk(以下PD)のパフォーマンスについて、少し解説してみたいと思います。
Google Compute Engineでは、PDのパフォーマンスはIOPSとスループットという指標によって測られます。
本記事ではこれらのパフォーマンスについて、改めておさらいしてみたいと思います。

PDの種類

PDの種類は、こちらに記載されているように4種類あります。
基本的には上から下に進むに向かってパフォーマンスが良くなります。

  • 標準永続ディスク
  • バランス永続ディスク
  • パフォーマンス永続ディスク
  • エクストリーム永続ディスク

この記事では主に、多く使われているバランス永続ディスク、パフォーマンス永続ディスクに関して記述していきます。

パフォーマンスの計算方法

エクストリームPDを除く各PDには、ベースラインパフォーマンスと共に、GiBあたりのパフォーマンスが提供されており、これをベースに期待パフォーマンスの計算を行います。

期待されるパフォーマンスの上限として、マシンとしての上限と、ディスクあたりの上限があるため、これも考慮します。

単一PDに対する基本的な期待パフォーマンスの計算式としては、IOPSもスループットも以下のようになります。

min(マシン上限, ディスク上限, ベースライン + GiBあたり * ディスクサイズ)

計算例

例えば、以下のようなケースを考えます。

  • E2 VM
  • 4 vCPU
  • 100GiB Zonal pd-ssd

このケースでは、IOPSは

min(15000, 100000, 6000 + 100 * 30) = 9000 IOPS

となり、スループットは

min(240, 1200, 240 + 0.48 * 100) = 240 MiB

となります。

実測

こちらにあるfioコマンドを利用し、上記のpd-ssdに対してパフォーマンステストをかけてみます。

IOPS測定

ext4ファイルシステムを構成して/mount/disks/sdbにマウントし、コマンドは以下を利用します。
今回はIOPSの上限を見るため、ブロックサイズを1Kに指定します。

コマンド

sudo fio --name=read_iops --directory=/mount/disks/sdb \
--numjobs=16 --size=1G --time_based --runtime=5m --ramp_time=2s \
--ioengine=libaio --direct=1 --verify=0 --bs=1K --iodepth=64 \
--rw=randread --group_reporting=1 --iodepth_batch_submit=64 \
--iodepth_batch_complete_max=64

結果

read: IOPS=8997, BW=9000KiB/s (9217kB/s)(2638MiB/300120msec)

IOPS = 8997と、ほぼ上限に近い値が出ました。
メトリクスで見ても、9000 IOPSになっていることが分かります。

IOPS Metrics

スループット測定

今度はブロックサイズを256Kに設定し、スループット上限を確認します。

コマンド

sudo fio --name=read_throughput --directory=/mount/disks/sdb \
--numjobs=16 --size=1G --time_based --runtime=5m --ramp_time=2s \
--ioengine=libaio --direct=1 --verify=0 --bs=256K --iodepth=64 \
--rw=randread --group_reporting=1 --iodepth_batch_submit=64 \
--iodepth_batch_complete_max=64

結果

read: IOPS=1916, BW=240MiB/s (252MB/s)(70.4GiB/300532msec)

結果は240MiB/sと、こちらも上限の値が出ています。
メトリクスで確認しても以下の通りです。

Throughput Metrics

シーケンシャルな操作の場合

今まで、--rw=randreadと、ランダムアクセスによる測定を実施してきました。
次は--rw=readと、シーケンシャルなアクセスで試してみます。

IOPS測定で試したブロックサイズ 1Kに対して試してみます。

コマンド

sudo fio --name=read_iops --directory=/mount/disks/sdb \
--numjobs=16 --size=1G --time_based --runtime=5m --ramp_time=2s \
--ioengine=libaio --direct=1 --verify=0 --bs=1K --iodepth=64 \
--rw=read --group_reporting=1 --iodepth_batch_submit=64 \
--iodepth_batch_complete_max=64

結果

read: IOPS=63.6k, BW=62.1MiB/s (65.1MB/s)(18.2GiB/300015msec)

IOPS = 63600、スループット = 62.1MiBという、IOPSの上限を大幅に超えた結果が出ました。
これはどういうことでしょうか?

Disk Operationsは、前回のテストと同じ9kを示しており、この結果を説明できません。
IOPS Metrics

ここで登場するのがmerged_operation_countです。

これは、隣あったブロックに対する複数のI/O操作をカーネルがマージして1つの操作にする、I/Oのマージ操作を行った回数をカウントしています。

すごく簡単に言えば、隣あったブロックに1Kずつ、2つのI/O操作があった場合、この2つをマージして合計2K、1回のI/O操作にしてしまう、ということです。

グラフを見ると、このマージ操作の数が急増していることが見てとれます。
Merged Operations

fioからは複数のI/O操作であったとしても、PDから見た時には1つのI/O操作として見えているため、fioで測定したIOPSとPDで測定したIOPSに差が出てくるというわけですね。

例外ケース

ここまで単一のPersistent Diskを対象としてお話しして来ましたが、上で紹介した期待パフォーマンスの計算式通りに必ずしもいかないケースが存在します。

例えば、同じタイプのディスクを複数アタッチしている場合では、サイズによるパフォーマンスは合計したものが適用されますが、ベースラインパフォーマンスについてはディスク1つ分しか与えられません。

つまり、例えば50GiBのZonal pd-ssdを2つアタッチした場合、トータルの期待パフォーマンスは

min(15000, 100000, (6000 + 50 * 30) * 2) = 15000 IOPS

ではなく、100 GiBのpd-ssdを一つアタッチした場合と同じ、

min(15000, 100000, 6000 + 100 * 30) = 9000 IOPS

と、なります。
pd-ssdとpd-standardのような、タイプの異なるPDをアタッチした場合はこうはならず、それぞれにベースラインパフォーマンスが適用されます。

PD観点の他にも、ワークロードの問題や、オペレーティングシステムやファイルシステムの問題など、考慮すべき点はありますので、PDのパフォーマンスに困った際はこれらを参照してみてください。

終わりに

PDのパフォーマンスは基本的な部分ではあるものの、一方で一見して分かりにくい点があるのも事実です。
本記事が理解の一助となりましたら幸いです。

Google Cloud Japan

Discussion