「fio」コマンドを用いてEBS, EFS, FSx for OpenZFSの性能を実測して比較してみた

「fio」コマンドを用いてEBS, EFS, FSx for OpenZFSの性能を実測して比較してみた

2026.01.31

はじめに

みなさんこんにちは、クラウド事業本部コンサルティング部の浅野です。

EC2インスタンス上でNFSベースのファイルサーバーを運用しており、Amazon EFSやAmazon FSx for OpenZFSへの移行を検討することもあるかと思います。

その際に気になるのがそれぞれのサービスにおいて「実際のパフォーマンスはどの程度違うのか?」という点です。カタログスペックだけでは分かりにくい部分もあるため、今回はfioコマンドを使って、「EBS」、「EFS」、「FSx for OpenZFS」の3つのストレージを同一条件で比べてみました。

本記事では、LinuxベースのWebアプリケーションがファイルシステムにアクセスする典型的なユースケースを想定し、2つのパターンでベンチマークを実施しました。

fioコマンドとは

fio(Flexible I/O Tester)は、ストレージの性能を測定するためのベンチマークツールです。スループット、IOPS、レイテンシなどを測定でき、ランダムアクセスやシーケンシャルアクセス、読み書きの比率など様々なワークロードをデータセットの用意なしに再現できます。実際のアプリケーションの使用パターンを模倣したテストができるため、本番環境に近い性能評価ができます。

今回はこのコマンドを使用して実際のベンチマークを測定してみます。

https://fio.readthedocs.io/en/latest/fio_doc.html

それぞれのストレージサービスの違い

ストレージサービスの特徴として以下の違いがありますので、以下にまとめました。コストに関しては考慮していません。

「EBS」はローカルにアタッチできるブロックストレージで、「EFS」、「FSx for OpenZFS」はネットワークを通してアクセスできるファイルストレージです。アクセスの形式が前提として異なることに注意が必要です。

構成

CDKを用いて以下の単一VPC・サブネットにて以下の構成を用意しました。

2026-01-31-fio-ebs-efs-fsx-openzfs-benchmark-01

CDKスタック
demo-fsx-openzfs-efs-stack.ts
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as fsx from 'aws-cdk-lib/aws-fsx';
import * as efs from 'aws-cdk-lib/aws-efs';
import * as iam from 'aws-cdk-lib/aws-iam';

/**
 * ストレージ性能比較検証用スタック
 * EBS / EFS / FSx for OpenZFS をfioでベンチマーク比較
 */
export class DemoFsxOpenzfsEfsStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // VPC
    const vpc = new ec2.Vpc(this, 'Vpc', {
      maxAzs: 1,
      natGateways: 0,
      subnetConfiguration: [
        {
          cidrMask: 24,
          name: 'Public',
          subnetType: ec2.SubnetType.PUBLIC,
        },
      ],
    });

    // EC2用セキュリティグループ
    const ec2Sg = new ec2.SecurityGroup(this, 'Ec2Sg', {
      vpc,
      description: 'Security group for EC2 instance',
      allowAllOutbound: true,
    });

    // FSx用セキュリティグループ
    const fsxSg = new ec2.SecurityGroup(this, 'FsxSg', {
      vpc,
      description: 'Security group for FSx for OpenZFS',
      allowAllOutbound: true,
    });

    fsxSg.addIngressRule(ec2Sg, ec2.Port.tcp(2049), 'NFS Server');
    fsxSg.addIngressRule(ec2Sg, ec2.Port.tcp(111), 'NFS RPC');
    fsxSg.addIngressRule(ec2Sg, ec2.Port.tcpRange(20001, 20003), 'NFS Mount');

    // EFS用セキュリティグループ
    const efsSg = new ec2.SecurityGroup(this, 'EfsSg', {
      vpc,
      description: 'Security group for EFS',
      allowAllOutbound: true,
    });

    efsSg.addIngressRule(ec2Sg, ec2.Port.tcp(2049), 'NFS from EC2');

    // FSx for OpenZFS
    const fsxFileSystem = new fsx.CfnFileSystem(this, 'FsxFileSystem', {
      fileSystemType: 'OPENZFS',
      subnetIds: [vpc.publicSubnets[0].subnetId],
      securityGroupIds: [fsxSg.securityGroupId],
      storageCapacity: 64,
      openZfsConfiguration: {
        deploymentType: 'SINGLE_AZ_1',
        throughputCapacity: 512,
        diskIopsConfiguration: {
          mode: 'USER_PROVISIONED',
          iops: 5000,
        },
        rootVolumeConfiguration: {
          dataCompressionType: 'ZSTD',
          nfsExports: [
            {
              clientConfigurations: [
                {
                  clients: '*',
                  options: ['rw', 'crossmnt', 'no_root_squash'],
                },
              ],
            },
          ],
        },
      },
    });

    // EFS
    const efsFileSystem = new efs.FileSystem(this, 'EfsFileSystem', {
      vpc,
      vpcSubnets: {
        subnetType: ec2.SubnetType.PUBLIC,
      },
      securityGroup: efsSg,
      performanceMode: efs.PerformanceMode.GENERAL_PURPOSE,
      throughputMode: efs.ThroughputMode.PROVISIONED,
      provisionedThroughputPerSecond: cdk.Size.mebibytes(512),
      removalPolicy: cdk.RemovalPolicy.DESTROY,
      allowAnonymousAccess: true,
    });

    // EC2用IAMロール (SSM用)
    const ec2Role = new iam.Role(this, 'Ec2Role', {
      assumedBy: new iam.ServicePrincipal('ec2.amazonaws.com'),
      managedPolicies: [
        iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonSSMManagedInstanceCore'),
      ],
    });

    // EC2インスタンス (t3.micro, Amazon Linux 2023)
    const instance = new ec2.Instance(this, 'Instance', {
      vpc,
      vpcSubnets: {
        subnetType: ec2.SubnetType.PUBLIC,
      },
      instanceType: ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.MICRO),
      machineImage: ec2.MachineImage.latestAmazonLinux2023({
        cpuType: ec2.AmazonLinuxCpuType.X86_64,
      }),
      securityGroup: ec2Sg,
      role: ec2Role,
      // ルートボリューム
      blockDevices: [
        {
          deviceName: '/dev/xvda',
          volume: ec2.BlockDeviceVolume.ebs(100, {
            volumeType: ec2.EbsDeviceVolumeType.GP3,
            iops: 5000,
          }),
        },
      ],
    });
  }
}

CDKにおいてできるだけ各ストレージサービスの性能を近づけるため、それぞれのファイルシステムとブロックストレージを本番に近い形で以下のIOPSとスループットの性能に固定しています。

ストレージ IOPS スループット
EBS gp3 5,000 512 MB/s
FSx for OpenZFS 5,000 512 MB/s
EFS Provisioned - 512 MB/s

「EFS」はパフォーマンスモードごとにIOPSの上限が決まっており、ユーザーが明示的にIOPS値を指定することはできません。よってスループットのみの指定としています。

また、「EBS」は起動テンプレートの設定を行わないとCDKからではスループットの指定が反映されなかったので、上記のスタックをデプロイ後、CLIコマンドでスループットを更新しました。

デプロイ後の「EBS」スループットの確認

2026-01-31-fio-ebs-efs-fsx-openzfs-benchmark-02

以下のコマンドでデフォルト「128MB/s」→「512MB/s」に変更済み
※Volume IDは事前に確認済み

aws ec2 modify-volume --volume-id vol-058a87d44e452ff41 --throughput 512
{
    "VolumeModification": {
        "VolumeId": "vol-058a87d44e452ff41",
        "ModificationState": "modifying",
        "TargetSize": 100,
        "TargetIops": 5000,
        "TargetVolumeType": "gp3",
        "TargetThroughput": 512,
        "TargetMultiAttachEnabled": false,
        "OriginalSize": 100,
        "OriginalIops": 5000,
        "OriginalVolumeType": "gp3",
        "OriginalThroughput": 125,
        "OriginalMultiAttachEnabled": false,
        "Progress": 0,
        "StartTime": "2026-01-31T08:42:40+00:00"
    }
}

「EFS」と「FSx for OpenZFS」はともにNFS v4.1を使用して、TLSを用いた暗号化通信は無しにしています。

「EFS」においてアクセスのIAM認証を設定すると必ずTLS経由での設定が強制されるため、今回は匿名アクセス設定allowAnonymousAccess: true,を入れてどこからでも「EFS」にマウントできるようにしています。TLS処理のオーバーヘッドをなくして「EFS」と「FSx for OpenZFS」のアクセス時の処理に差を出さないことが狙いです。

参考:
https://docs.aws.amazon.com/ja_jp/efs/latest/ug/mounting-IAM-option.html

検証シチュエーション

今回の検証シチュエーションとしては、Webアプリケーションがファイルシステムにアクセスする典型的なユースケースを想定し、「EBS」、「EFS」、「FSx for OpenZFS」の3つのストレージを以下の同一条件でfioコマンドを実行し比較しました。

検証パターン1: キャッシュ/セッション

Webアプリケーションがセッションファイルやキャッシュファイルにアクセスする状況を想定しています。セッションやキャッシュは数百バイト〜数KBの小さなデータで、ユーザーごとに異なるファイルへランダムにアクセスします。16人のユーザーが同時にアクセスし、読み取り70%・書き込み30%の比率で60秒間テストするようにfioコマンドを実行しました。

使用したコマンド(例: EFS)
sudo fio \
	--name=cache \
	--directory=/mnt/efs \
	--rw=randrw \
	--rwmixread=70 \
	--bs=4k \
	--size=100M \
	--numjobs=16 \
	--runtime=60 \
	--time_based \
	--group_reporting

各オプションの意味はこちらです。

オプション 意味
--name cache テスト名
--directory /mnt/efs など テスト対象のディレクトリ
--rw randrw ランダム読み書き
--rwmixread 70 読み取り 70%、書き込み 30%
--bs 4k 1回の I/O サイズ
--size 100M 各ジョブのファイルサイズ
--numjobs 16 同時実行ジョブ数
--runtime 60 テスト時間(秒)
--time_based - 時間までループ継続
--group_reporting - 結果をまとめて表示

検証パターン2: ファイルアップロード

ユーザーが画像やPDFなどのファイルをアップロードする状況を想定しています。アップロードは書き込み処理のみで、1MB単位のチャンクで順次書き込みを行います。4人のユーザーが同時にファイルをアップロードし、60秒間書き込み続けることを想定しています。

使用したコマンド(例: EFS)
sudo fio \
	--name=upload \
	--directory=/mnt/efs \
	--rw=write \
	--bs=1M \
	--size=50M \
	--numjobs=4 \
	--runtime=60 \
	--time_based \
	--group_reporting

各オプションの意味はこちらです。

オプション 意味
--name upload テスト名
--directory /mnt/efs など テスト対象のディレクトリ
--rw write 順次書き込み
--bs 1M 1回の I/O サイズ
--size 50M 各ジョブのファイルサイズ
--numjobs 4 同時実行ジョブ数
--runtime 60 テスト時間(秒)
--time_based - 時間までループ継続
--group_reporting - 結果をまとめて表示

やってみた

CDKをデプロイ後、まず「「EFS」、「FSx for OpenZFS」の各ファイルシステムへEC2からマウントします。

EC2にSSM接続を行い以下のコマンドを実行しました。
※ 各ファイルシステムの{DNS名}はあらかじめ確認済みです。

# マウントポイント作成
sudo mkdir -p /mnt/{efs,fsx}

# EFS
# デフォルトで NFS v4.1 を使用
# TLS 強制のため IAM 認証は使わず
sudo mount -t nfs4 -o nfsvers=4.1 \
  fs-00bc54ce35b6770f2.efs.ap-northeast-1.amazonaws.com:/ \
  /mnt/efs

# FSx for OpenZFS (NFS v4.1を使用するように明示的に設定)
sudo mount -t nfs -o nfsvers=4.1 \
  fs-0689a8c647dcf2197.fsx.ap-northeast-1.amazonaws.com:/fsx \
  /mnt/fsx

# 確認
mount | grep efs
tracefs on /sys/kernel/tracing type tracefs (rw,nosuid,nodev,noexec,relatime,seclabel)
sunrpc on /var/lib/nfs/rpc_pipefs type rpc_pipefs (rw,relatime)
fs-00bc54ce35b6770f2.efs.ap-northeast-1.amazonaws.com:/ on /mnt/efs type nfs4 \
(rw,relatime,vers=4.1,rsize=1048576,wsize=1048576,namlen=255,hard,proto=tcp,\
timeo=600,retrans=2,sec=sys,clientaddr=10.0.0.221,local_lock=none,addr=10.0.0.178)

mount | grep fsx
fs-0689a8c647dcf2197.fsx.ap-northeast-1.amazonaws.com:/fsx on /mnt/fsx type nfs4 \
(rw,relatime,vers=4.1,rsize=1048576,wsize=1048576,namlen=255,hard,proto=tcp,\
timeo=600,retrans=2,sec=sys,clientaddr=10.0.0.221,local_lock=none,addr=10.0.0.76)

# ディスク使用量確認
df -h
Filesystem                                                   Size  Used Avail Use% Mounted on
devtmpfs                                                     4.0M     0  4.0M   0% /dev
tmpfs                                                        459M     0  459M   0% /dev/shm
tmpfs                                                        184M  408K  183M   1% /run
/dev/nvme0n1p1                                               100G  1.8G   99G   2% /
tmpfs                                                        459M     0  459M   0% /tmp
/dev/nvme0n1p128                                              10M  1.3M  8.7M  13% /boot/efi
fs-00bc54ce35b6770f2.efs.ap-northeast-1.amazonaws.com:/      8.0E  1.8G  8.0E   1% /mnt/efs
fs-0689a8c647dcf2197.fsx.ap-northeast-1.amazonaws.com:/fsx    64G  1.8G   63G   3% /mnt/fsx

「EFS」、「FSx for OpenZFS」のマウントに成功しました。「EBS」はルートボリュームとして元々アタッチされているので特別な操作は不要です。

検証パターン1の結果

それぞれのファイルシステムのマウントが成功したので実際にfioコマンドを実行してパターン1の検証を行います。

「EBS」の結果
sudo fio \
	--name=cache \
	--directory=/ \
	--rw=randrw \
	--rwmixread=70 \
	--bs=4k \
	--size=100M \
	--numjobs=16 \
	--runtime=60 \
	--time_based \
	--group_reporting

出力
cache: (g=0): rw=randrw, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=psync, iodepth=1
...
fio-3.32
Starting 16 processes
cache: Laying out IO file (1 file / 100MiB)
cache: Laying out IO file (1 file / 100MiB)
cache: Laying out IO file (1 file / 100MiB)
cache: Laying out IO file (1 file / 100MiB)
cache: Laying out IO file (1 file / 100MiB)
cache: Laying out IO file (1 file / 100MiB)
cache: Laying out IO file (1 file / 100MiB)
cache: Laying out IO file (1 file / 100MiB)
cache: Laying out IO file (1 file / 100MiB)
cache: Laying out IO file (1 file / 100MiB)
cache: Laying out IO file (1 file / 100MiB)
cache: Laying out IO file (1 file / 100MiB)
cache: Laying out IO file (1 file / 100MiB)
cache: Laying out IO file (1 file / 100MiB)
cache: Laying out IO file (1 file / 100MiB)
cache: Laying out IO file (1 file / 100MiB)
Jobs: 16 (f=16): [m(16)][100.0%][r=14.4MiB/s,w=6254KiB/s][r=3698,w=1563 IOPS][eta 00m:00s]
cache: (groupid=0, jobs=16): err= 0: pid=26196: Sat Jan 31 08:51:49 2026
  read: IOPS=3871, BW=15.1MiB/s (15.9MB/s)(907MiB/60005msec)
    clat (usec): min=332, max=37149, avg=4123.32, stdev=1240.49
     lat (usec): min=332, max=37149, avg=4123.51, stdev=1240.50
    clat percentiles (usec):
     |  1.00th=[  570],  5.00th=[ 2089], 10.00th=[ 2769], 20.00th=[ 3326],
     | 30.00th=[ 3818], 40.00th=[ 4080], 50.00th=[ 4228], 60.00th=[ 4424],
     | 70.00th=[ 4555], 80.00th=[ 4883], 90.00th=[ 5407], 95.00th=[ 5800],
     | 99.00th=[ 6587], 99.50th=[ 6980], 99.90th=[11207], 99.95th=[15664],
     | 99.99th=[28181]
   bw (  KiB/s): min=13672, max=60061, per=100.00%, avg=15502.74, stdev=272.90, samples=1904
   iops        : min= 3418, max=15007, avg=3875.51, stdev=68.17, samples=1904
  write: IOPS=1667, BW=6669KiB/s (6829kB/s)(391MiB/60005msec); 0 zone resets
    clat (usec): min=2, max=9820, avg=11.75, stdev=73.97
     lat (usec): min=2, max=9820, avg=12.03, stdev=74.36
    clat percentiles (usec):
     |  1.00th=[    3],  5.00th=[    3], 10.00th=[    3], 20.00th=[    4],
     | 30.00th=[    6], 40.00th=[    8], 50.00th=[   10], 60.00th=[   12],
     | 70.00th=[   13], 80.00th=[   14], 90.00th=[   16], 95.00th=[   20],
     | 99.00th=[   36], 99.50th=[   85], 99.90th=[  433], 99.95th=[  791],
     | 99.99th=[ 2900]
   bw (  KiB/s): min= 3960, max=26255, per=100.00%, avg=6676.13, stdev=136.86, samples=1904
   iops        : min=  990, max= 6556, avg=1668.86, stdev=34.17, samples=1904
  lat (usec)   : 4=7.62%, 10=8.27%, 20=12.92%, 50=1.09%, 100=0.08%
  lat (usec)   : 250=0.08%, 500=0.14%, 750=1.88%, 1000=0.20%
  lat (msec)   : 2=1.03%, 4=22.36%, 10=44.24%, 20=0.08%, 50=0.02%
  cpu          : usr=0.23%, sys=0.51%, ctx=232911, majf=0, minf=157
  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=232311,100040,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):
   READ: bw=15.1MiB/s (15.9MB/s), 15.1MiB/s-15.1MiB/s (15.9MB/s-15.9MB/s), io=907MiB (952MB), run=60005-60005msec
  WRITE: bw=6669KiB/s (6829kB/s), 6669KiB/s-6669KiB/s (6829kB/s-6829kB/s), io=391MiB (410MB), run=60005-60005msec

Disk stats (read/write):
  nvme0n1: ios=231916/72584, merge=0/76, ticks=944585/316730, in_queue=1261314, util=87.30%

上記の出力からスループットとIOPS(1秒あたりのI/O操作回数)は以下の箇所で確認できます。

  • 読みとり → read: IOPS=3871, BW=15.1MiB/s (15.9MB/s)(907MiB/60005msec)
  • 書き込み → write: IOPS=1667, BW=6669KiB/s (6829kB/s)(391MiB/60005msec); 0 zone resetsIOPS

合計IOPSは「読み取りIOPS + 書き込みIOPS」で算出します。

3871(READ) + 1667(WRITE) = 5,538 IOPS

実行結果

実行結果を表にまとめると以下のようになりました。

項目 実行結果
ジョブ数 16 processes
ファイルサイズ 100MiB × 16
実行時間 60005msec
ブロックサイズ 4096B
読み書き比率 907MB:391MB(約70:30)
READ 15.9MB/s, 3871 IOPS
WRITE 6.7MB/s, 1667 IOPS
合計IOPS 約5,538
「EFS」の結果
sudo fio \
	--name=cache \
	--directory=/mnt/efs \
	--rw=randrw \
	--rwmixread=70 \
	--bs=4k \
	--size=100M \
	--numjobs=16 \
	--runtime=60 \
	--time_based \
	--group_reporting
出力
cache: (g=0): rw=randrw, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=psync, iodepth=1
...
fio-3.32
Starting 16 processes
Jobs: 2 (f=2): [_(11),f(1),_(2),f(1),_(1)][100.0%][eta 00m:00s]
cache: (groupid=0, jobs=16): err= 0: pid=26282: Sat Jan 31 08:53:53 2026
  read: IOPS=3374, BW=13.2MiB/s (13.8MB/s)(791MiB/60015msec)
    clat (usec): min=587, max=73813, avg=4730.76, stdev=2505.30
     lat (usec): min=587, max=73814, avg=4730.98, stdev=2505.34
    clat percentiles (usec):
     |  1.00th=[  750],  5.00th=[ 1139], 10.00th=[ 2040], 20.00th=[ 3589],
     | 30.00th=[ 3949], 40.00th=[ 4228], 50.00th=[ 4555], 60.00th=[ 4883],
     | 70.00th=[ 5276], 80.00th=[ 5735], 90.00th=[ 6587], 95.00th=[ 7504],
     | 99.00th=[15270], 99.50th=[20055], 99.90th=[27132], 99.95th=[33162],
     | 99.99th=[43779]
   bw (  KiB/s): min= 3280, max=22512, per=100.00%, avg=13512.40, stdev=184.04, samples=1904
   iops        : min=  820, max= 5628, avg=3377.61, stdev=46.01, samples=1904
  write: IOPS=1451, BW=5805KiB/s (5944kB/s)(340MiB/60015msec); 0 zone resets
    clat (usec): min=2, max=25695, avg=10.66, stdev=125.76
     lat (usec): min=2, max=25695, avg=10.95, stdev=125.81
    clat percentiles (usec):
     |  1.00th=[    3],  5.00th=[    3], 10.00th=[    4], 20.00th=[    4],
     | 30.00th=[    6], 40.00th=[    8], 50.00th=[    9], 60.00th=[   10],
     | 70.00th=[   10], 80.00th=[   12], 90.00th=[   15], 95.00th=[   19],
     | 99.00th=[   41], 99.50th=[   77], 99.90th=[  293], 99.95th=[  529],
     | 99.99th=[ 2376]
   bw (  KiB/s): min= 1184, max=11155, per=100.00%, avg=5808.69, stdev=103.15, samples=1904
   iops        : min=  296, max= 2788, avg=1451.60, stdev=25.79, samples=1904
  lat (usec)   : 4=6.73%, 10=14.43%, 20=7.68%, 50=1.02%, 100=0.12%
  lat (usec)   : 250=0.07%, 500=0.02%, 750=0.71%, 1000=2.14%
  lat (msec)   : 2=4.02%, 4=15.12%, 10=46.62%, 20=0.99%, 50=0.35%
  lat (msec)   : 100=0.01%
  cpu          : usr=0.19%, sys=0.49%, ctx=217379, majf=60, minf=275
  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=202530,87099,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):
   READ: bw=13.2MiB/s (13.8MB/s), 13.2MiB/s-13.2MiB/s (13.8MB/s-13.8MB/s), io=791MiB (830MB), run=60015-60015msec
  WRITE: bw=5805KiB/s (5944kB/s), 5805KiB/s-5805KiB/s (5944kB/s-5944kB/s), io=340MiB (357MB), run=60015-60015msec

実行結果

項目 実行結果
ジョブ数 16 processes
ファイルサイズ 100MiB × 16
実行時間 60015msec
ブロックサイズ 4096B
読み書き比率 791MB:340MB(約70:30)
READ 13.8MB/s, 3374 IOPS
WRITE 5.8MB/s, 1451 IOPS
合計IOPS 約4,825
「FSx for OpenZFS」の結果
sudo fio \
	--name=cache \
	--directory=/mnt/fsx \
	--rw=randrw \
	--rwmixread=70 \
	--bs=4k \
	--size=100M \
	--numjobs=16 \
	--runtime=60 \
	--time_based \
	--group_reporting
出力
cache: (g=0): rw=randrw, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=psync, iodepth=1
...
fio-3.32
Starting 16 processes
Jobs: 11 (f=11): [f(3),_(2),f(1),_(1),f(4),_(1),f(3),_(1)][100.0%][r=2432KiB/s,w=1100KiB/s][r=608,w=275 IOPS][eta 00m:00s]
cache: (groupid=0, jobs=16): err= 0: pid=27303: Sat Jan 31 09:19:02 2026
  read: IOPS=20.6k, BW=80.3MiB/s (84.2MB/s)(4818MiB/60004msec)
    clat (nsec): min=1338, max=550972k, avg=763137.89, stdev=1766541.57
     lat (nsec): min=1376, max=550972k, avg=763436.29, stdev=1766836.55
    clat percentiles (usec):
     |  1.00th=[  159],  5.00th=[  235], 10.00th=[  269], 20.00th=[  314],
     | 30.00th=[  367], 40.00th=[  424], 50.00th=[  494], 60.00th=[  578],
     | 70.00th=[  709], 80.00th=[  898], 90.00th=[ 1270], 95.00th=[ 1827],
     | 99.00th=[ 4948], 99.50th=[ 7570], 99.90th=[19268], 99.95th=[23200],
     | 99.99th=[52691]
   bw (  KiB/s): min=18548, max=168703, per=100.00%, avg=82389.65, stdev=1632.14, samples=1904
   iops        : min= 4637, max=42172, avg=20596.92, stdev=408.06, samples=1904
  write: IOPS=8823, BW=34.5MiB/s (36.1MB/s)(2068MiB/60004msec); 0 zone resets
    clat (usec): min=2, max=304298, avg=20.40, stdev=1020.98
     lat (usec): min=2, max=304298, avg=20.86, stdev=1021.28
    clat percentiles (usec):
     |  1.00th=[    3],  5.00th=[    3], 10.00th=[    4], 20.00th=[    4],
     | 30.00th=[    5], 40.00th=[    5], 50.00th=[    6], 60.00th=[    6],
     | 70.00th=[    7], 80.00th=[    8], 90.00th=[   16], 95.00th=[   26],
     | 99.00th=[  229], 99.50th=[  478], 99.90th=[ 1303], 99.95th=[ 2147],
     | 99.99th=[ 7308]
   bw (  KiB/s): min= 7511, max=73603, per=100.00%, avg=35363.34, stdev=715.86, samples=1904
   iops        : min= 1875, max=18397, avg=8840.42, stdev=178.98, samples=1904
  lat (usec)   : 2=0.11%, 4=7.86%, 10=18.43%, 20=1.99%, 50=1.45%
  lat (usec)   : 100=0.25%, 250=4.65%, 500=30.65%, 750=15.55%, 1000=7.63%
  lat (msec)   : 2=8.44%, 4=2.00%, 10=0.78%, 20=0.15%, 50=0.06%
  lat (msec)   : 100=0.01%, 250=0.01%, 500=0.01%, 750=0.01%
  cpu          : usr=0.51%, sys=2.18%, ctx=1336635, majf=123, minf=323
  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=1233521,529469,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):
   READ: bw=80.3MiB/s (84.2MB/s), 80.3MiB/s-80.3MiB/s (84.2MB/s-84.2MB/s), io=4818MiB (5053MB), run=60004-60004msec
  WRITE: bw=34.5MiB/s (36.1MB/s), 34.5MiB/s-34.5MiB/s (36.1MB/s-36.1MB/s), io=2068MiB (2169MB), run=60004-60004msec

実行結果

項目 実行結果
ジョブ数 16 processes
ファイルサイズ 100MiB × 16
実行時間 60004msec
ブロックサイズ 4096B
読み書き比率 4818MB:2068MB(約70:30)
READ 84.2MB/s, 20,600 IOPS
WRITE 36.1MB/s, 8,823 IOPS
合計IOPS 約29,423

パターン1 まとめ

ストレージ READ スループット READ IOPS WRITE スループット WRITE IOPS 合計 IOPS 順位
「FSx for OpenZFS」 84.2 MB/s 20,600 36.1 MB/s 8,823 29,423 1位
「EBS」 15.9 MB/s 3,871 6.7 MB/s 1,667 5,538 2位
「EFS」 13.8 MB/s 3,374 5.8 MB/s 1,451 4,825 3位

「FSx for OpenZFS」は設定IOPS 5,000に対して約29,000 IOPSでした。「クラウドで利用可能な中でも最高レベルの、ファイルストレージ向けの低レイテンシーを提供します」と謳われているだけあって他のストレージサービスと比較して圧倒的な結果を記録しました。

「EBS」は設定IOPS 5,000に対して約5,500 IOPS、「EFS」は約4,800 IOPSでした。

「FSx for OpenZFS」が設定値を大きく超えた結果となったのは、ZFSのキャッシュ機能が関係しているのでしょうか。ZFSには頻繁にアクセスされるデータをメモリ上にキャッシュする仕組みがあるようで、今回のように同じファイルに対して繰り返しランダムアクセスを行うワークロードでは、ディスクI/Oを経由せずメモリから直接データを返すことで高速化されるようです。「EFS」が「EBS」より約13%低い結果となったのは、ネットワーク経由のオーバーヘッドが影響しているのではないかと考察しました。この検証にて同じ小ファイルの大量読み取りの場合「FSx for OpenZFS」が圧倒的に高パフォーマンスを誇るということを実感しました。

参考:
https://aws.amazon.com/jp/fsx/openzfs/features/#ハフォーマンスと拡張性--x53mgm

検証パターン2の結果

続いて検証パターン2のコマンドを実行してそれぞれ比較しました。

「EBS」の結果
sudo fio \
	--name=upload \
	--directory=/ \
	--rw=write \
	--bs=1M \
	--size=50M \
	--numjobs=4 \
	--runtime=60 \
	--time_based \
	--group_reporting
出力
upload: (g=0): rw=write, bs=(R) 1024KiB-1024KiB, (W) 1024KiB-1024KiB, (T) 1024KiB-1024KiB, ioengine=psync, iodepth=1
...
fio-3.32
Starting 4 processes
upload: Laying out IO file (1 file / 50MiB)
upload: Laying out IO file (1 file / 50MiB)
upload: Laying out IO file (1 file / 50MiB)
upload: Laying out IO file (1 file / 50MiB)
Jobs: 4 (f=4): [W(4)][100.0%][w=235MiB/s][w=235 IOPS][eta 00m:00s]
upload: (groupid=0, jobs=4): err= 0: pid=26619: Sat Jan 31 09:01:59 2026
  write: IOPS=253, BW=254MiB/s (266MB/s)(14.9GiB/60048msec); 0 zone resets
    clat (usec): min=260, max=350011, avg=10927.14, stdev=21747.18
     lat (usec): min=275, max=350073, avg=10975.63, stdev=21755.01
    clat percentiles (usec):
     |  1.00th=[   326],  5.00th=[   363], 10.00th=[   371], 20.00th=[   383],
     | 30.00th=[   408], 40.00th=[   437], 50.00th=[   486], 60.00th=[   586],
     | 70.00th=[  1909], 80.00th=[ 28967], 90.00th=[ 29754], 95.00th=[ 39584],
     | 99.00th=[113771], 99.50th=[139461], 99.90th=[191890], 99.95th=[219153],
     | 99.99th=[283116]
   bw (  KiB/s): min=57344, max=788767, per=100.00%, avg=260695.15, stdev=22832.98, samples=475
   iops        : min=   56, max=  770, avg=254.36, stdev=22.30, samples=475
  lat (usec)   : 500=51.73%, 750=15.09%, 1000=1.81%
  lat (msec)   : 2=1.43%, 4=0.79%, 10=0.68%, 20=3.99%, 50=21.60%
  lat (msec)   : 100=1.66%, 250=1.21%, 500=0.01%
  cpu          : usr=0.12%, sys=4.29%, ctx=49856, majf=20, minf=67
  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,15251,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=254MiB/s (266MB/s), 254MiB/s-254MiB/s (266MB/s-266MB/s), io=14.9GiB (16.0GB), run=60048-60048msec

Disk stats (read/write):
  nvme0n1: ios=25/89304, merge=0/32, ticks=36/429337, in_queue=429373, util=96.56%

実行結果

項目 実行結果
ジョブ数 4 processes
ファイルサイズ 50MiB × 4
実行時間 60048msec
ブロックサイズ 1024KiB
読み書き write only
WRITE 266MB/s, 253 IOPS
総書き込み量 14.9GB
「EFS」の結果
sudo fio \
	--name=upload \
	--directory=/mnt/efs \
	--rw=write \
	--bs=1M \
	--size=50M \
	--numjobs=4 \
	--runtime=60 \
	--time_based \
	--group_reporting

出力
upload: (g=0): rw=write, bs=(R) 1024KiB-1024KiB, (W) 1024KiB-1024KiB, (T) 1024KiB-1024KiB, ioengine=psync, iodepth=1
...
fio-3.32
Starting 4 processes
Jobs: 4 (f=4): [W(4)][100.0%][w=468MiB/s][w=468 IOPS][eta 00m:00s]
upload: (groupid=0, jobs=4): err= 0: pid=26746: Sat Jan 31 09:04:28 2026
  write: IOPS=488, BW=489MiB/s (512MB/s)(28.6GiB/60027msec); 0 zone resets
    clat (usec): min=279, max=148688, avg=7958.91, stdev=13201.47
     lat (usec): min=290, max=148750, avg=8017.70, stdev=13217.55
    clat percentiles (usec):
     |  1.00th=[   293],  5.00th=[   306], 10.00th=[   326], 20.00th=[   367],
     | 30.00th=[   412], 40.00th=[   465], 50.00th=[   523], 60.00th=[   635],
     | 70.00th=[  1778], 80.00th=[ 24511], 90.00th=[ 29230], 95.00th=[ 33162],
     | 99.00th=[ 40109], 99.50th=[ 46400], 99.90th=[ 85459], 99.95th=[108528],
     | 99.99th=[132645]
   bw (  KiB/s): min=186442, max=2093056, per=100.00%, avg=501507.23, stdev=64799.40, samples=476
   iops        : min=  181, max= 2044, avg=489.47, stdev=63.30, samples=476
  lat (usec)   : 500=47.14%, 750=17.55%, 1000=3.11%
  lat (msec)   : 2=2.51%, 4=2.16%, 10=1.66%, 20=4.03%, 50=21.46%
  lat (msec)   : 100=0.32%, 250=0.06%
  cpu          : usr=0.34%, sys=7.37%, ctx=30728, majf=0, minf=42
  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,29332,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=489MiB/s (512MB/s), 489MiB/s-489MiB/s (512MB/s-512MB/s), io=28.6GiB (30.8GB), run=60027-60027msec

実行結果

項目 実行結果
ジョブ数 4 processes
ファイルサイズ 50MiB × 4
実行時間 60027msec
ブロックサイズ 1024KiB
読み書き write only
WRITE 512MB/s, 488 IOPS
総書き込み量 28.6GB
「FSx for OpenZFS」の結果
sudo fio \
	--name=upload \
	--directory=/mnt/fsx \
	--rw=write \
	--bs=1M \
	--size=50M \
	--numjobs=4 \
	--runtime=60 \
	--time_based \
	--group_reporting

出力
upload: (g=0): rw=write, bs=(R) 1024KiB-1024KiB, (W) 1024KiB-1024KiB, (T) 1024KiB-1024KiB, ioengine=psync, iodepth=1
...
fio-3.32
Starting 4 processes
Jobs: 4 (f=4): [W(4)][100.0%][w=256MiB/s][w=256 IOPS][eta 00m:00s]
upload: (groupid=0, jobs=4): err= 0: pid=27777: Sat Jan 31 09:30:01 2026
  write: IOPS=255, BW=256MiB/s (268MB/s)(15.0GiB/60033msec); 0 zone resets
    clat (usec): min=288, max=630253, avg=15289.68, stdev=38180.10
     lat (usec): min=300, max=630308, avg=15340.11, stdev=38184.37
    clat percentiles (usec):
     |  1.00th=[   330],  5.00th=[   343], 10.00th=[   359], 20.00th=[   420],
     | 30.00th=[   453], 40.00th=[   498], 50.00th=[   586], 60.00th=[   709],
     | 70.00th=[  3556], 80.00th=[ 29492], 90.00th=[ 39584], 95.00th=[ 50070],
     | 99.00th=[214959], 99.50th=[261096], 99.90th=[400557], 99.95th=[467665],
     | 99.99th=[509608]
   bw (  KiB/s): min=51200, max=908858, per=99.93%, avg=261550.23, stdev=37789.51, samples=476
   iops        : min=   50, max=  887, avg=255.13, stdev=36.91, samples=476
  lat (usec)   : 500=40.28%, 750=21.03%, 1000=3.84%
  lat (msec)   : 2=3.17%, 4=1.96%, 10=1.36%, 20=1.51%, 50=21.73%
  lat (msec)   : 100=2.48%, 250=2.02%, 500=0.59%, 750=0.03%
  cpu          : usr=0.14%, sys=4.41%, ctx=18587, majf=18, minf=70
  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,15345,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=256MiB/s (268MB/s), 256MiB/s-256MiB/s (268MB/s-268MB/s), io=15.0GiB (16.1GB), run=60033-60033msec

実行結果

項目 実行結果
ジョブ数 4 processes
ファイルサイズ 50MiB × 4
実行時間 60033msec
ブロックサイズ 1024KiB
読み書き write only
WRITE 268MB/s, 255 IOPS
総書き込み量 15.0GB

パターン2 まとめ

ストレージ WRITE スループット WRITE IOPS 総書き込み量 順位
「EFS」 512 MB/s 488 28.6 GB 1位
「FSx for OpenZFS」 268 MB/s 255 15.0 GB 2位
「EBS」 gp3 266 MB/s 253 14.9 GB 3位

「EFS」は設定スループット512 MB/sに対して設定値そのままの512 MB/sを記録しました。「FSx for OpenZFS」は設定スループット512 MB/sに対して268 MB/s、「EBS」は設定スループット512 MB/sに対して266 MB/sでした。

「EFS」が設定値どおりの性能を発揮したのに対し、「EBS」と「FSx for OpenZFS」が約半分にとどまったのは、IOPS指定(5,000 IOPS)がボトルネックになっているのではないでしょうか。

1MBブロックで5,000 IOPSの場合、理論上の上限は約5,000 MB/sですが、実際にはレイテンシやオーバーヘッドにより256〜268 MB/s程度になったと推測しました。

逆に「EFS」はパフォーマンスモードごとにIOPSの上限はあるものの、ユーザー側で明示的に指定できずAWS側でスケーリングされる仕様なので、今回の書き込み量に合わせてIOPSを自動でスケーリングしたためこのような結果になったと思われます。

このようなに容量順次書き込みのワークロードでは、EFSの自動スケーリング機能が有効に機能することが確認できました。

一方で「FSx for OpenZFS」はあらかじめプロビジョニングする必要があるためこのような柔軟なスケーリングができません。

最後に

本記事では、fioコマンドを使用して「EBS」gp3、「EFS」、「FSx for OpenZFS」の3つのストレージサービスを同一条件でベンチマーク比較しました。

検証パターン1(4KBランダム読み書き)では、「FSx for OpenZFS」がZFSのキャッシュ機能により他のストレージを大きく上回る結果となりました。

検証パターン2(1MB順次書き込み)では、「EFS」のみが設定スループットどおりの性能を発揮し、最も高い書き込み性能を記録しました。

今回の検証が、各ストレージの特性をそのまま表現しているとは言えませんが、1ケースとして参考になるのではないでしょうか。

実際のストレージサービスの選定はワークロードの特性によって異なってくるので、本番ワークロードに寄せたシチュエーションを検討し、実測値ベースで比較することが重要だと思います。

この記事がどなたかの参考になれば幸いです。今回は以上です。

この記事をシェアする

FacebookHatena blogX

関連記事