EBSとEFSのパフォーマンスをfioで比較してみた

EBSとEFSのパフォーマンスをfioで比較してみた

EBS(gp3)とEFS(バーストスループットモード)の単純比較です
Clock Icon2024.09.30

こんにちは、なおにしです。

単一インスタンス(AL2023)のEBSで行っているワークロードをEFSに移すことで、どのくらいの性能影響があるのか気になったのでfioを使ってベンチマークしてみました。

はじめに

EFSは直近で性能向上のアップデートも複数あり、なんとなく速そうというようなイメージもあるのではないでしょうか。(私はありました)

https://dev.classmethod.jp/articles/amazon-efs-30-gibs-read-throughput/

https://dev.classmethod.jp/articles/efs-supports-20-gibs-throughput/

ですが、上記の記事でも明記されているとおり、スループットモードがElastic である必要があります。Elastic スループットモードはAWS ドキュメント内でも推奨のモードなっており、マネジメントコンソール上の選択肢でもデフォルトの項目となっていますが、料金面で注意が必要です。

https://repost.aws/ja/knowledge-center/efs-choosing-correct-throughput-mode

https://aws.amazon.com/jp/efs/pricing/

上記のとおり、Elastic スループットモードでは読み書きするデータ量に対しても料金が発生します。したがって、予測が難しいワークロードに対して性能面では適しているものの、データ量についても予測できていない場合は、意図せず読み書きに対する料金も発生する可能性があります。

一方、そもそも記載されているような性能がElastic スループットモードであればいつでも引き出せるかというとそうではありません。

ドキュメントにも以下のとおり明記されています。

最高レベルのパフォーマンスを実現するには、アプリケーションまたはワークロードを以下のように設定して並列化を活用する必要があります。

  1. 使用中のクライアントの数と少なくとも同じ数のディレクトリを使用して、すべてのクライアントとディレクトリにワークロードを均等に分散します。
  2. 個々のスレッドを個別のデータセットやファイルに配置することで、競合を最小限に抑えます。
  3. 1 つのマウントターゲットでNFS、クライアントごとに少なくとも 64 スレッドを使用して、ワークロードを 10 以上のクライアントに分散します。

https://docs.aws.amazon.com/ja_jp/efs/latest/ug/performance.html

EFS はNFSによる共有ファイルシステムなので、性能を考える場合は上記のように並列処理を前提とするのは自然なことかと思います。ですが、例えばEC2 インスタンスをアクティブ/スタンバイな状態にしているため、共通のファイル格納先としてEFS を使用したいといった用途もあるかもしれません。

というわけで、基本的には単一インスタンスからのNFS マウントであり、読み書きされるデータ量もサイジングできていない場合、一旦はバーストスループットモードの選択肢も挙がってくるかと思います。

しかし、バーストスループットモードも色々と注意が必要です。名称のとおり、EC2 インスタンスのt系やEBS のgp2に存在するようなバーストクレジットという考え方があります。

バーストスループットモードについて

上記のドキュメントに記載のとおり、例えば以下条件のEFS を考えてみます。

  • ファイルシステムのタイプ:リージョン
  • ストレージクラス:標準
  • スループットモード:バースト
  • パフォーマンスモード:汎用
  • ファイルシステムサイズ:100GiB

バーストクレジットの保有上限

バーストクレジットの保有上限はファイルシステムサイズ1TiBあたり「2.1 TiB」です。したがって、ファイルシステムサイズが100GiBであれば、バーストクレジットの保有上限は「2.1TiB × 1 = 2.1TiB」となります。ファイルシステム作成時点で「2.1TiB」のクレジットが提供されます。

ファイルシステムは、1 TiB より小さいファイルシステムの場合、2.1 TiB、または 1 TiB を超えるファイルシステムの場合は、1 TiB あたり 2.1 TiB の最大クレジットバランスを得ることができます。この動作は、ファイルシステムが連続して最大 12 時間バーストするのに十分なクレジットを蓄積できることを示しています。

ベースラインスループット

ベースラインスループットはファイルシステムサイズ1GiBあたり「50 KiB/s」です。これは、読み取りの場合は「150 KiB/s」、書き込み場合は「50 KiB/s」と等価です。したがって、ファイルシステムサイズが100GiBであればベースラインスループットは「50 KiB/s × 100 = 5MiB/s」となり、以下のパフォーマンスが適用されます。

  • 読み込み:15 MiB/s
  • 書き込み:5 MiB/s

なお、以下の記載があるため例えばEFSに数GiBほどのファイルしか保存していない場合でも、最低限のベースラインスループットとして「1MiB/s」が提供されます。

Amazon EFS は、ベースラインレートが低い場合でも、すべてのファイルシステムに 1 MiB/s の従量制スループットを提供します。

上記のベースラインスループットを下回る期間(= 非アクティブな期間) に渡って、ファイルシステムはベースラインスループットに応じたクレジットを獲得します。したがって、ファイルシステムサイズが100GiBでであれば、非アクティブな期間に「5 MiB/s」でクレジットを獲得できます(上限2.1TiB)。

バーストスループット

バーストスループットはファイルシステムサイズ1TiBあたり「100 MiB/s」です。これは、読み取りの場合は「300 MiB/s」、書き込み場合は「100 MiB/s」と等価です。したがって、ファイルシステムサイズが100GiBであればバーストスループットは「100 MiB/s × 1 = 100MiB/s」となり、以下のパフォーマンスが適用されます。

  • 読み込み:300 MiB/s
  • 書き込み:100 MiB/s

バーストクレジットが枯渇するまでは上記のパフォーマンスを出すことができます。

レイテンシ

ファイルシステムサイズに依らず以下のとおりです。

  • 読み込み:最低 250 マイクロ秒(μs)
  • 書き込み:最低 2.7 ミリ秒(ms)

IOPS

ファイルシステムサイズに依らず以下のとおりです。

  • 読み込み:上限 35,000
  • 書き込み:上限 7,000

ドキュメントに同様のことが記載されてはいますが、少し角度を変えてまとめてみました。その他のクォータについては以下のドキュメントをご参照ください。

https://docs.aws.amazon.com/ja_jp/efs/latest/ug/limits.html

それでは実際に上記の性能指標のうち、どの部分がボトルネックになってくるのかを確認してみます。

やってみた

検証にはfioを使用します。

fioはAWSのドキュメントでもEBSのベンチマークツールとして紹介されています。

https://docs.aws.amazon.com/ja_jp/ebs/latest/userguide/benchmark_procedures.html

今回はこちらに記載の方法を参考に書き込みのベンチマークを行います。上記ドキュメントで紹介されているコマンドは以下のとおりです。

sudo fio --directory=/mnt/p_iops_vol0 --ioengine=psync --name fio_test_file --direct=1 --rw=randwrite --bs=16k --size=1G --numjobs=16 --time_based --runtime=180 --group_reporting --norandommap

オプションの説明と今回のベンチマークで設定する値については以下をご参照ください。

オプション名 説明 今回設定する値(対象:EBS) 今回設定する値(対象:EFS)
--directory テストを実行するディレクトリを指定します。このディレクトリ内にテスト用のファイルが作成され、I/O操作が行われます /home/ec2-user /mnt/efs
--ioengine I/Oエンジンの種類を指定します。psyncはPOSIXライブラリを使用した同期I/Oエンジンで、標準的なファイルシステム操作をエミュレートします psync (同左)
--name テストジョブの名前を設定します。レポートやログで識別するための識別子となります fio_ebs_test fio_efs_test
--direct ダイレクトI/Oを有効(1)にします。これにより、キャッシュをバイパスして直接ディスクにアクセスするため、より正確なストレージ性能を測定できます 1 (同左)
--rw I/Oパターンを指定します randwrite (同左)
--bs ブロックサイズを指定します 16kまたは64k (同左)
--size ジョブが使用するテストファイルのサイズを指定します 1G (同左)
--numjobs 並列して実行するジョブの数(スレッド数)を指定します 16 (同左)
--time_based テストを時間ベースで実行することを指定します。データ量ではなく、指定した時間だけテストを継続します - (同左)
--runtime テストの実行時間を指定します(秒) 60 (同左)
--group_reporting 複数ジョブからの結果をグループ化して報告します。各ジョブの個別結果ではなく、全体としての統計情報を提供します - (同左)
--norandommap 通常、fio はランダム I/O を行うときにファイルのすべてのブロックをカバーします。このオプションが指定されると、fio は過去の I/O 履歴を参照せずに新しいランダム オフセットを取得します。つまり、一部のブロックは読み取りまたは書き込みが行われず、一部のブロックは複数回読み取り/書き込みが行われるようになります - (同左)

ベンチマークに使用したEC2 インスタンスの情報は以下のとおりです。

  • インスタンスタイプ/サイズ:m6i.large
  • EBSボリュームタイプ:gp3
    • スループット:125 MiB/s
    • IOPS:3,000
    • 容量:30 GiB

実施した環境の構築方法については以下の記事をご参照ください。

https://dev.classmethod.jp/articles/amazon-efs-hands-on-with-configuration-diagram/

上記記事のパブリックサブネットのみの環境で以下のEFSを作成した状態での検証となります。

  • ファイルシステムのタイプ:リージョン
  • ストレージクラス:標準
  • スループットモード:バースト
  • パフォーマンスモード:汎用
  • ファイルシステムサイズ:- (空の状態で実施)

EBS ボリュームのベンチマーク

ブロックサイズ16KiBのランダムWrite

$ sudo fio --directory=/home/ec2-user --ioengine=psync --name=fio_ebs_test --direct=1 --rw=randwrite --bs=16k --size=1G --numjobs=16 --time_based --runtime=60 --group_reporting --norandommap
fio_ebs_test: (g=0): rw=randwrite, bs=(R) 16.0KiB-16.0KiB, (W) 16.0KiB-16.0KiB, (T) 16.0KiB-16.0KiB, ioengine=psync, iodepth=1
...
fio-3.32
Starting 16 processes
fio_ebs_test: Laying out IO file (1 file / 1024MiB)
fio_ebs_test: Laying out IO file (1 file / 1024MiB)
fio_ebs_test: Laying out IO file (1 file / 1024MiB)
fio_ebs_test: Laying out IO file (1 file / 1024MiB)
fio_ebs_test: Laying out IO file (1 file / 1024MiB)
fio_ebs_test: Laying out IO file (1 file / 1024MiB)
fio_ebs_test: Laying out IO file (1 file / 1024MiB)
fio_ebs_test: Laying out IO file (1 file / 1024MiB)
fio_ebs_test: Laying out IO file (1 file / 1024MiB)
fio_ebs_test: Laying out IO file (1 file / 1024MiB)
fio_ebs_test: Laying out IO file (1 file / 1024MiB)
fio_ebs_test: Laying out IO file (1 file / 1024MiB)
fio_ebs_test: Laying out IO file (1 file / 1024MiB)
fio_ebs_test: Laying out IO file (1 file / 1024MiB)
fio_ebs_test: Laying out IO file (1 file / 1024MiB)
fio_ebs_test: Laying out IO file (1 file / 1024MiB)
Jobs: 16 (f=16): [w(16)][100.0%][w=46.9MiB/s][w=3002 IOPS][eta 00m:00s]
fio_ebs_test: (groupid=0, jobs=16): err= 0: pid=35269: Mon Sep 30 10:03:41 2024
  write: IOPS=3048, BW=47.6MiB/s (49.9MB/s)(2858MiB/60005msec); 0 zone resets
    clat (usec): min=419, max=50945, avg=5246.92, stdev=1835.54
     lat (usec): min=420, max=50945, avg=5247.20, stdev=1835.54
    clat percentiles (usec):
     |  1.00th=[ 1074],  5.00th=[ 2573], 10.00th=[ 3359], 20.00th=[ 4686],
     | 30.00th=[ 5080], 40.00th=[ 5211], 50.00th=[ 5342], 60.00th=[ 5473],
     | 70.00th=[ 5604], 80.00th=[ 5800], 90.00th=[ 6390], 95.00th=[ 6980],
     | 99.00th=[ 9896], 99.50th=[16712], 99.90th=[24511], 99.95th=[26608],
     | 99.99th=[37487]
   bw (  KiB/s): min=31424, max=144036, per=100.00%, avg=48805.68, stdev=586.42, samples=1904
   iops        : min= 1964, max= 9002, avg=3050.35, stdev=36.65, samples=1904
  lat (usec)   : 500=0.01%, 750=0.26%, 1000=0.56%
  lat (msec)   : 2=2.48%, 4=11.26%, 10=84.44%, 20=0.66%, 50=0.32%
  lat (msec)   : 100=0.01%
  cpu          : usr=0.05%, sys=0.19%, ctx=184367, majf=0, minf=167
  IO depths    : 1=100.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0%
     submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     complete  : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     issued rwts: total=0,182940,0,0 short=0,0,0,0 dropped=0,0,0,0
     latency   : target=0, window=0, percentile=100.00%, depth=1

Run status group 0 (all jobs):
  WRITE: bw=47.6MiB/s (49.9MB/s), 47.6MiB/s-47.6MiB/s (49.9MB/s-49.9MB/s), io=2858MiB (2997MB), run=60005-60005msec

Disk stats (read/write):
  nvme0n1: ios=0/182979, merge=0/9, ticks=0/959397, in_queue=959397, util=95.89%

結果を抜粋すると以下のとおりです。

項目 結果(平均)
スループット 47.6 MiB/s
IOPS 3050.35
レイテンシ 5247.20 μs

ブロックサイズが16KiBと小さいため、IOPSの上限(3,000)がボトルネックになっているようです。

ブロックサイズ64KiBのランダムWrite

$ sudo fio --directory=/home/ec2-user --ioengine=psync --name=fio_ebs_test --direct=1 --rw=randwrite --bs=64k --size=1G --numjobs=16 --time_based --runtime=60 --group_reporting --norandommap
fio_ebs_test: (g=0): rw=randwrite, bs=(R) 64.0KiB-64.0KiB, (W) 64.0KiB-64.0KiB, (T) 64.0KiB-64.0KiB, ioengine=psync, iodepth=1
...
fio-3.32
Starting 16 processes
fio_ebs_test: Laying out IO file (1 file / 1024MiB)
fio_ebs_test: Laying out IO file (1 file / 1024MiB)
fio_ebs_test: Laying out IO file (1 file / 1024MiB)
fio_ebs_test: Laying out IO file (1 file / 1024MiB)
fio_ebs_test: Laying out IO file (1 file / 1024MiB)
fio_ebs_test: Laying out IO file (1 file / 1024MiB)
fio_ebs_test: Laying out IO file (1 file / 1024MiB)
fio_ebs_test: Laying out IO file (1 file / 1024MiB)
fio_ebs_test: Laying out IO file (1 file / 1024MiB)
fio_ebs_test: Laying out IO file (1 file / 1024MiB)
fio_ebs_test: Laying out IO file (1 file / 1024MiB)
fio_ebs_test: Laying out IO file (1 file / 1024MiB)
fio_ebs_test: Laying out IO file (1 file / 1024MiB)
fio_ebs_test: Laying out IO file (1 file / 1024MiB)
fio_ebs_test: Laying out IO file (1 file / 1024MiB)
fio_ebs_test: Laying out IO file (1 file / 1024MiB)
Jobs: 16 (f=16): [w(16)][100.0%][w=137MiB/s][w=2197 IOPS][eta 00m:00s]
fio_ebs_test: (groupid=0, jobs=16): err= 0: pid=37011: Mon Sep 30 10:18:50 2024
  write: IOPS=1987, BW=124MiB/s (130MB/s)(7453MiB/60008msec); 0 zone resets
    clat (usec): min=561, max=421661, avg=8048.72, stdev=7793.47
     lat (usec): min=563, max=421664, avg=8050.72, stdev=7793.49
    clat percentiles (usec):
     |  1.00th=[  1516],  5.00th=[  3130], 10.00th=[  4555], 20.00th=[  6915],
     | 30.00th=[  7635], 40.00th=[  7832], 50.00th=[  7963], 60.00th=[  8160],
     | 70.00th=[  8356], 80.00th=[  8717], 90.00th=[  9896], 95.00th=[ 10945],
     | 99.00th=[ 15664], 99.50th=[ 24511], 99.90th=[ 63701], 99.95th=[187696],
     | 99.99th=[396362]
   bw (  KiB/s): min= 2304, max=384510, per=100.00%, avg=127222.30, stdev=2136.33, samples=1904
   iops        : min=   36, max= 6002, avg=1987.80, stdev=33.36, samples=1904
  lat (usec)   : 750=0.04%, 1000=0.14%
  lat (msec)   : 2=2.10%, 4=5.18%, 10=83.00%, 20=8.93%, 50=0.45%
  lat (msec)   : 100=0.09%, 250=0.03%, 500=0.04%
  cpu          : usr=0.06%, sys=0.12%, ctx=119864, majf=0, minf=162
  IO depths    : 1=100.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0%
     submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     complete  : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     issued rwts: total=0,119243,0,0 short=0,0,0,0 dropped=0,0,0,0
     latency   : target=0, window=0, percentile=100.00%, depth=1

Run status group 0 (all jobs):
  WRITE: bw=124MiB/s (130MB/s), 124MiB/s-124MiB/s (130MB/s-130MB/s), io=7453MiB (7815MB), run=60008-60008msec

Disk stats (read/write):
  nvme0n1: ios=0/119261, merge=0/6, ticks=0/959163, in_queue=959164, util=96.31%

結果を抜粋すると以下のとおりです。

項目 結果(平均)
スループット 124 MiB/s
IOPS 1987.80
レイテンシ 8050.72 μs

ブロックサイズを64KiBに大きくしたためスループットが向上した結果、その上限(125 MiB/s)がボトルネックになっているようです。

EFS のベンチマーク

ブロックサイズ16KiBのランダムWrite

$ sudo fio --directory=/mnt/efs --ioengine=psync --name=fio_efs_test --direct=1 --rw=randwrite --bs=16k --size=1G --numjobs=16 --time_based --runtime=60 --group_reporting --norandommap
fio_efs_test: (g=0): rw=randwrite, bs=(R) 16.0KiB-16.0KiB, (W) 16.0KiB-16.0KiB, (T) 16.0KiB-16.0KiB, ioengine=psync, iodepth=1
...
fio-3.32
Starting 16 processes
fio_efs_test: Laying out IO file (1 file / 1024MiB)
fio_efs_test: Laying out IO file (1 file / 1024MiB)
fio_efs_test: Laying out IO file (1 file / 1024MiB)
fio_efs_test: Laying out IO file (1 file / 1024MiB)
fio_efs_test: Laying out IO file (1 file / 1024MiB)
fio_efs_test: Laying out IO file (1 file / 1024MiB)
fio_efs_test: Laying out IO file (1 file / 1024MiB)
fio_efs_test: Laying out IO file (1 file / 1024MiB)
fio_efs_test: Laying out IO file (1 file / 1024MiB)
fio_efs_test: Laying out IO file (1 file / 1024MiB)
fio_efs_test: Laying out IO file (1 file / 1024MiB)
fio_efs_test: Laying out IO file (1 file / 1024MiB)
fio_efs_test: Laying out IO file (1 file / 1024MiB)
fio_efs_test: Laying out IO file (1 file / 1024MiB)
fio_efs_test: Laying out IO file (1 file / 1024MiB)
fio_efs_test: Laying out IO file (1 file / 1024MiB)
Jobs: 16 (f=16): [w(6),f(1),w(9)][8.9%][w=24.9MiB/s][w=1591 IOPS][eta 10m:27s]
fio_efs_test: (groupid=0, jobs=16): err= 0: pid=37983: Mon Sep 30 10:27:16 2024
  write: IOPS=1560, BW=24.4MiB/s (25.6MB/s)(1463MiB/60011msec); 0 zone resets
    clat (usec): min=4015, max=46685, avg=10251.65, stdev=1650.58
     lat (usec): min=4015, max=46685, avg=10251.87, stdev=1650.58
    clat percentiles (usec):
     |  1.00th=[ 8225],  5.00th=[ 8586], 10.00th=[ 8848], 20.00th=[ 9110],
     | 30.00th=[ 9372], 40.00th=[ 9634], 50.00th=[ 9896], 60.00th=[10159],
     | 70.00th=[10552], 80.00th=[10945], 90.00th=[11731], 95.00th=[13435],
     | 99.00th=[16581], 99.50th=[18482], 99.90th=[22676], 99.95th=[25035],
     | 99.99th=[30016]
   bw (  KiB/s): min=15820, max=26726, per=100.00%, avg=24970.27, stdev=104.49, samples=1915
   iops        : min=  988, max= 1670, avg=1560.39, stdev= 6.53, samples=1915
  lat (msec)   : 10=53.28%, 20=46.44%, 50=0.27%
  cpu          : usr=0.03%, sys=0.07%, ctx=94398, majf=0, minf=115
  IO depths    : 1=100.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0%
     submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     complete  : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     issued rwts: total=0,93638,0,0 short=0,0,0,0 dropped=0,0,0,0
     latency   : target=0, window=0, percentile=100.00%, depth=1

Run status group 0 (all jobs):
  WRITE: bw=24.4MiB/s (25.6MB/s), 24.4MiB/s-24.4MiB/s (25.6MB/s-25.6MB/s), io=1463MiB (1534MB), run=60011-60011msec

結果を抜粋すると以下のとおりです。

項目 結果(平均)
スループット 24.4 MiB/s
IOPS 1560.39
レイテンシ 10251.87 μs(約10.25ms)

作成したばかりのファイルシステムであるためバーストクレジットが適用されているはずですが、スループットは上限(100 MiB/s)に届かず、IOPSも同様に上限(7,000)まで届いていません。このためEBSと比較して大きめなレイテンシが原因になりそうなので計算してみます。

今回は--runtimeで60秒を指定しているため、1ジョブあたりの実行時間が60秒になればレイテンシがボトルネックと特定できます。

  • 書き込みブロック数 = 総書き込み量/ブロックサイズ

    • (1,463 MiB * 1024) / 16KiB = 93,632 ブロック
  • 総レイテンシ = 書き込みブロック数 * 平均レイテンシ

    • 93,632 * 10251.87 μs / 1000 / 1000 = 959.9 s
  • 1ジョブあたりの実行時間 = 総レイテンシ / スレッド数(--numjobs)

    • 959.9 s / 16 = 59.99 s

というわけでほぼ60秒に近似できたため、やはりレイテンシがボトルネックになっていることが確認できました。

ブロックサイズ64KiBのランダムWrite

$ sudo fio --directory=/mnt/efs --ioengine=psync --name=fio_efs_test --direct=1 --rw=randwrite --bs=64k --size=1G --numjobs=16 --time_based --runtime=60 --group_reporting --norandommap
fio_efs_test: (g=0): rw=randwrite, bs=(R) 64.0KiB-64.0KiB, (W) 64.0KiB-64.0KiB, (T) 64.0KiB-64.0KiB, ioengine=psync, iodepth=1
...
fio-3.32
Starting 16 processes
fio_efs_test: Laying out IO file (1 file / 1024MiB)
fio_efs_test: Laying out IO file (1 file / 1024MiB)
fio_efs_test: Laying out IO file (1 file / 1024MiB)
fio_efs_test: Laying out IO file (1 file / 1024MiB)
fio_efs_test: Laying out IO file (1 file / 1024MiB)
fio_efs_test: Laying out IO file (1 file / 1024MiB)
fio_efs_test: Laying out IO file (1 file / 1024MiB)
fio_efs_test: Laying out IO file (1 file / 1024MiB)
fio_efs_test: Laying out IO file (1 file / 1024MiB)
fio_efs_test: Laying out IO file (1 file / 1024MiB)
fio_efs_test: Laying out IO file (1 file / 1024MiB)
fio_efs_test: Laying out IO file (1 file / 1024MiB)
fio_efs_test: Laying out IO file (1 file / 1024MiB)
fio_efs_test: Laying out IO file (1 file / 1024MiB)
fio_efs_test: Laying out IO file (1 file / 1024MiB)
fio_efs_test: Laying out IO file (1 file / 1024MiB)
Jobs: 16 (f=16): [w(16)][100.0%][w=99.6MiB/s][w=1593 IOPS][eta 00m:00s]
fio_efs_test: (groupid=0, jobs=16): err= 0: pid=40498: Mon Sep 30 10:48:34 2024
  write: IOPS=1614, BW=101MiB/s (106MB/s)(6056MiB/60009msec); 0 zone resets
    clat (usec): min=6244, max=29005, avg=9904.61, stdev=1406.56
     lat (usec): min=6245, max=29007, avg=9905.89, stdev=1406.57
    clat percentiles (usec):
     |  1.00th=[ 7177],  5.00th=[ 7832], 10.00th=[ 8029], 20.00th=[ 8979],
     | 30.00th=[ 8979], 40.00th=[ 9634], 50.00th=[10028], 60.00th=[10028],
     | 70.00th=[10552], 80.00th=[10945], 90.00th=[11731], 95.00th=[11994],
     | 99.00th=[13960], 99.50th=[15008], 99.90th=[17433], 99.95th=[18482],
     | 99.99th=[21890]
   bw (  KiB/s): min=81112, max=125952, per=100.00%, avg=103377.58, stdev=381.57, samples=1904
   iops        : min= 1266, max= 1968, avg=1615.26, stdev= 5.97, samples=1904
  lat (msec)   : 10=56.83%, 20=43.15%, 50=0.02%
  cpu          : usr=0.06%, sys=0.09%, ctx=101113, majf=0, minf=146
  IO depths    : 1=100.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0%
     submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     complete  : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     issued rwts: total=0,96900,0,0 short=0,0,0,0 dropped=0,0,0,0
     latency   : target=0, window=0, percentile=100.00%, depth=1

Run status group 0 (all jobs):
  WRITE: bw=101MiB/s (106MB/s), 101MiB/s-101MiB/s (106MB/s-106MB/s), io=6056MiB (6350MB), run=60009-60009msec

結果を抜粋すると以下のとおりです。

項目 結果(平均)
スループット 101 MiB/s
IOPS 1615.26
レイテンシ 9905.89 μs(約9.91ms)

ブロックサイズを64KiBに大きくしたためスループットが向上し、ほぼ上限(100 MiB/s)に届いた状態になりました。このため今回のボトルネックはスループットであるといえます。ちなみに以下のとおり先ほどと同様に1ジョブあたりの実行時間を計算すると60秒に近似できます。

  • 書き込みブロック数 = 総書き込み量/ブロックサイズ

    • (6,056 MiB * 1024) / 64KiB = 96,896 ブロック
  • 総レイテンシ = 書き込みブロック数 * 平均レイテンシ

    • 96,896 * 9905.89 μs / 1000 / 1000 = 959.8 s
  • 1ジョブあたりの実行時間 = 総レイテンシ / スレッド数(--numjobs)

    • 959.8 s / 16 = 59.99 s

まとめ

EBS(gp3)とEFS(バーストスループットモード)のベンチマークをとって比較してみました。今回の結果では、小さなブロックサイズのI/OではEFSにおいてレイテンシがボトルネックになる可能性があることが分かりました。(ちなみにAL2023のファイルシステム(xfs)ではOS標準のブロックサイズは4KBです)

ただし、あくまで今回実施した検証での結果ですので、本記事を参考にされる場合は実際にお手元の環境で改めて検証されることを推奨します。検証する上でのリソースの違いやAWSのアップデートなど、様々な要因によって結果に差異が発生する可能性があります。

なお、スループットモードはEFS作成後でもAWSマネジメントコンソールから簡単に切り替えることができるため、まずはバーストスループットモードでワークロードを確認して、必要に応じてElastic スループットモードに切り替えることも可能です。

https://docs.aws.amazon.com/ja_jp/efs/latest/ug/managing-throughput.html

https://dev.classmethod.jp/articles/how-to-change-from-amazon-efs-bursting-to-elastic-using-aws-cli/

本記事がどなたかのお役に立てれば幸いです。

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.