AZを跨いだFSx for OpenZFSとEFSの速度比較を行ってみた

AZを跨いだFSx for OpenZFSとEFSの速度比較を行ってみた

2026.02.23

はじめに

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

今回は、アクセス時にAZ跨ぎが発生するFSx for OpenZFS Multi-AZと、発生しないAmazon EFSの観点で「fio」コマンドを用いて性能比較した結果をまとめます。

なぜこの検証を行うのか

FSx for OpenZFS Multi-AZとEFSはどちらもマルチAZ対応の共有ファイルストレージですが、クライアントから見た通信経路が異なります。

FSx for OpenZFS Multi-AZはアクティブ/スタンバイ方式であり、複数のEC2からマウントする場合はアクティブENIは1つのAZに固定され、別AZのEC2からは必ずAZを跨いでアクセスする形式になり、AZ跨ぎが発生します。

2026-02-23-fsx-multiaz-vs-efs-az-benchmark-01

しかしEFSの場合、マルチAZで使用する場合は各AZにマウントターゲットが配置することが可能で、EC2は常に同じAZから接続するためアクセスにAZ跨ぎが発生しません。

2026-02-23-fsx-multiaz-vs-efs-az-benchmark-02

ファイルサーバーを使用したいEC2が複数AZに分散している環境では、この仕様の違いが性能にどれほど影響するのかを「fio」コマンドを用いて数値で把握してみたいと思います。

そのため本検証では、FSx for OpenZFSはAZ跨ぎを発生させ、EFSでは発生させないパターンでの速度比較を行います。

同一AZアクセスでの性能比較は以下の記事を参考にしてください。

https://dev.classmethod.jp/articles/2026-01-31-fio-ebs-efs-fsx-openzfs-benchmark/

CDKの用意

以下のリソースを一式CDKにて構築しました。

  • VPC
    • CIDR: 10.0.0.0/16
    • サブネット ap-northeast-1a: 10.0.0.0/24
    • サブネット ap-northeast-1c: 10.0.1.0/24
    • VPCエンドポイント: SSM、SSMMessages、S3 Gateway
  • EC2
    • インスタンスタイプ: t3.micro
    • OS: Amazon Linux 2023
    • 配置AZ: ap-northeast-1c
  • FSx for OpenZFS Multi-AZ
    • ストレージ容量: 1000GB
    • スループット: 160MB/s
    • アクティブENI: ap-northeast-1a
    • 圧縮: LZ4
  • EFS
    • パフォーマンスモード: 汎用モード
    • スループットモード: Elastic
    • マウントターゲット: 両AZ(ap-northeast-1a、ap-northeast-1c)

EC2はap-northeast-1c、FSxのアクティブENIはap-northeast-1aに配置しており、EC2からFSxへのアクセスが必ずAZを跨ぐ構成を意図的に作っています。これによりAZ跨ぎが性能に与える影響をワーストケースで計測できます。

EFSはスループットモードをElasticに設定しています。Elasticはスループットを事前にプロビジョニングせずAWSが自動でスケールする設定で、特定の用途に最適化せず汎用的な実運用に近い構成として選択しています。

FSx for OpenZFSは1000GB・160MB/sで設定しています。これはプロビジョニング形式であるため、実際の運用で想定するストレージ容量とスループットを明示的に指定する必要があります。今回はこの性能値を実運用の想定値として検証しています。

CDKスタック全文
demo-fsx-efs-az-benchmark-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';

export class DemoFsxEfsAzBenchmarkStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // VPC - 2AZ構成 (ap-northeast-1a, ap-northeast-1c)
    const vpc = new ec2.Vpc(this, 'Vpc', {
      availabilityZones: ['ap-northeast-1a', 'ap-northeast-1c'],
      natGateways: 0,
      ipAddresses: ec2.IpAddresses.cidr('10.0.0.0/16'),
      subnetConfiguration: [
        {
          cidrMask: 24,
          name: 'Private',
          subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
        },
      ],
    });

    const subnet1a = vpc.isolatedSubnets[0]; // ap-northeast-1a
    const subnet1c = vpc.isolatedSubnets[1]; // ap-northeast-1c

    // VPCエンドポイント用セキュリティグループ
    const vpcEndpointSg = new ec2.SecurityGroup(this, 'VpcEndpointSg', {
      vpc,
      securityGroupName: 'az-benchmark-vpce-sg',
      description: 'Security group for VPC Endpoints',
      allowAllOutbound: true,
    });
    vpcEndpointSg.addIngressRule(ec2.Peer.ipv4(vpc.vpcCidrBlock), ec2.Port.tcp(443), 'HTTPS from VPC');

    // S3ゲートウェイエンドポイント(dnfリポジトリアクセス用)
    vpc.addGatewayEndpoint('S3Endpoint', {
      service: ec2.GatewayVpcEndpointAwsService.S3,
      subnets: [{ subnetType: ec2.SubnetType.PRIVATE_ISOLATED }],
    });

    // SSM用VPCエンドポイント(EC2が1cにあるため1cサブネットに配置)
    vpc.addInterfaceEndpoint('SsmEndpoint', {
      service: ec2.InterfaceVpcEndpointAwsService.SSM,
      subnets: { subnets: [subnet1c] },
      securityGroups: [vpcEndpointSg],
    });
    vpc.addInterfaceEndpoint('SsmMessagesEndpoint', {
      service: ec2.InterfaceVpcEndpointAwsService.SSM_MESSAGES,
      subnets: { subnets: [subnet1c] },
      securityGroups: [vpcEndpointSg],
    });

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

    const fsxSg = new ec2.SecurityGroup(this, 'FsxSg', {
      vpc,
      securityGroupName: 'az-benchmark-fsx-sg',
      description: 'Security group for FSx for OpenZFS Multi-AZ',
      allowAllOutbound: true,
    });
    fsxSg.addIngressRule(ec2Sg, ec2.Port.tcp(111), 'NFS RPC from EC2');
    fsxSg.addIngressRule(ec2Sg, ec2.Port.tcp(2049), 'NFS from EC2');
    fsxSg.addIngressRule(ec2Sg, ec2.Port.tcpRange(20001, 20003), 'NFS mount/status/lock from EC2');

    const efsSg = new ec2.SecurityGroup(this, 'EfsSg', {
      vpc,
      securityGroupName: 'az-benchmark-efs-sg',
      description: 'Security group for EFS',
      allowAllOutbound: true,
    });
    efsSg.addIngressRule(ec2Sg, ec2.Port.tcp(2049), 'NFS from EC2');

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

    new ec2.Instance(this, 'Instance', {
      vpc,
      vpcSubnets: { subnets: [subnet1c] }, // ap-northeast-1c
      instanceType: ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.MICRO),
      machineImage: ec2.MachineImage.latestAmazonLinux2023({ cpuType: ec2.AmazonLinuxCpuType.X86_64 }),
      securityGroup: ec2Sg,
      role: ec2Role,
    });

    // FSx for OpenZFS Multi-AZ
    const routeTableIds = vpc.isolatedSubnets.map((subnet) => subnet.routeTable.routeTableId);

    new fsx.CfnFileSystem(this, 'FsxFileSystem', {
      fileSystemType: 'OPENZFS',
      subnetIds: [subnet1a.subnetId, subnet1c.subnetId],
      securityGroupIds: [fsxSg.securityGroupId],
      storageCapacity: 1000,
      openZfsConfiguration: {
        deploymentType: 'MULTI_AZ_1',
        throughputCapacity: 160,
        preferredSubnetId: subnet1a.subnetId, // アクティブサブネット(ap-northeast-1a)
        routeTableIds: routeTableIds,
        rootVolumeConfiguration: {
          dataCompressionType: 'LZ4',
          nfsExports: [
            {
              clientConfigurations: [
                { clients: '*', options: ['rw', 'crossmnt', 'no_root_squash'] },
              ],
            },
          ],
        },
      },
      tags: [{ key: 'Name', value: 'fsx-openzfs-multiaz-az-benchmark' }],
    });

    // EFS
    new efs.FileSystem(this, 'EfsFileSystem', {
      vpc,
      securityGroup: efsSg,
      performanceMode: efs.PerformanceMode.GENERAL_PURPOSE,
      throughputMode: efs.ThroughputMode.ELASTIC,
      removalPolicy: cdk.RemovalPolicy.DESTROY,
      allowAnonymousAccess: true,
    });
  }
}

やってみた

CDKデプロイ後、EC2にSSM接続してマウントと初期設定を行います。

# fio インストール
sudo dnf install -y fio

# マウントポイント作成・マウント NFS v4.1に両方合わせています
sudo mkdir -p /mnt/fsx /mnt/efs
sudo mount -t nfs -o nfsvers=4.1 {実際のFSx DNS名}:/fsx /mnt/fsx
sudo mount -t nfs -o nfsvers=4.1 {実際のEFS DNS名}:/ /mnt/efs

続いて、マウントファイルの権限について、EFSのルートディレクトリはデフォルトでroot:root 755のため書き込み権限を付与します。FSxはデフォルトで777なので変更不要です。

sudo chmod 777 /mnt/efs

実際にファイルシステムのマウントポイントのAZがどこに存在するか確認してみます。
各DNS名が解決するIPと/proc/mountsを確認することで、EC2(ap-northeast-1c)からFSxへのAZ跨ぎが発生していることを確認できます。

# FSxのDNS名が解決するIPを確認
dig +short {実際のFSx DNS名}
# → 10.0.0.0/24(ap-northeast-1a)のアドレス。FSxアクティブENIはap-northeast-1aに存在することが確認
10.0.255.222

2026-02-23-fsx-multiaz-vs-efs-az-benchmark-03
2026-02-23-fsx-multiaz-vs-efs-az-benchmark-04
2026-02-23-fsx-multiaz-vs-efs-az-benchmark-05

# EFSのDNS名が解決するIPを確認
dig +short {実際のEFS DNS名}
# → 10.0.1.0/24(ap-northeast-1c)のアドレス。EC2(ap-northeast-1c)と同AZのマウントターゲットで接続されていることを確認
10.0.1.6

2026-02-23-fsx-multiaz-vs-efs-az-benchmark-06

cat /proc/mounts | grep nfs
sunrpc /var/lib/nfs/rpc_pipefs rpc_pipefs rw,relatime 0 0
# addr=10.0.255.222(ap-northeast-1a)→ EC2(ap-northeast-1c, clientaddr=10.0.1.20)からap-northeast-1aへAZ跨ぎ接続されていることを確認
{実際のFSx DNS名}:/fsx /mnt/fsx nfs4 rw,relatime,vers=4.1,rsize=1048576,wsize=1048576,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=10.0.1.20,local_lock=none,addr=10.0.255.222 0 0
# addr=10.0.1.6(ap-northeast-1c)→ EC2(ap-northeast-1c, clientaddr=10.0.1.20)と同AZ接続されていることを確認
{実際のEFS DNS名}:/ /mnt/efs nfs4 rw,relatime,vers=4.1,rsize=1048576,wsize=1048576,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=10.0.1.20,local_lock=none,addr=10.0.1.6 0 0

これにてEC2から各ファイルシステムへ接続しているマウントポイントのAZ所在が確認できました。

それでは実際に「fio」コマンドを叩いてみます。計測条件は以下のとおりです。
今回は「アプリケーションから画像ファイルを共有ファイルシステムにアップロードする」ことを想定して以下のオプションを設定しました

パラメータ 意味
--name seq-write-fsx 等 ジョブ名
--rw write / read I/Oパターン。シーケンシャル書き込み・読み込み
--bs 4m 1回のI/Oリクエストサイズ。画像1枚相当の4MBを指定
--size 4g テストデータの総量。4GBを繰り返し読み書き
--numjobs 1 並列ジョブ数。1=シングルスレッドで1ファイルを想定
--iodepth 1 I/Oキューの深さ。1=前のI/Oが完了してから次を発行
--ioengine libaio I/Oの発行方式。libaioはLinuxのカーネルレベル非同期I/OでNFSベンチマークの標準的な選択。iodepth=1の場合、実際には1件ずつ順番に処理するため挙動は同期的だが、slat(発行レイテンシ)とclat(完了レイテンシ)を分けて計測できる
--runtime 60 計測時間(秒)
--time_based - sizeに達しても60秒間回し続ける
--filename /mnt/fsx/testfile 等 読み書き対象ファイルのパス
--group_reporting - 複数ジョブの結果を集計して表示
--direct 0 / 1 バッファリングの有無。詳細は下記

--direct オプションについて

--directはI/Oにバッファリングを使うかどうかを制御するオプションです。

  • --direct=0(バッファリングあり): データをいったんメモリ(バッファ)に書き込み、プログラムはすぐに完了扱いになる。実際にストレージへ書き出すのはOSが非同期で行う
  • --direct=1(バッファリングなし): バッファを使わずデータが実際にストレージへ書き込まれるまでプログラムが待つ

今回この2条件で計測するのは、バッファリングの有無によって結果がどう変わるかを確認するためです。--direct=1はバッファの影響を排除してストレージ実性能を測れる条件です。

参考:
https://fio.readthedocs.io/en/latest/fio_doc.html#cmdoption-arg-direct

--direct=0(OSページキャッシュを経由)

FSx for OpenZFS の結果(書き込み)
fio --name=seq-write-fsx \
    --rw=write \
    --bs=4m \
    --size=4g \
    --numjobs=1 \
    --iodepth=1 \
    --ioengine=libaio \
    --runtime=60 \
    --time_based \
    --filename=/mnt/fsx/testfile \
    --group_reporting
出力
seq-write-fsx: (g=0): rw=write, bs=(R) 4096KiB-4096KiB, (W) 4096KiB-4096KiB, (T) 4096KiB-4096KiB, ioengine=libaio, iodepth=1
fio-3.32
Starting 1 process
Jobs: 1 (f=1): [W(1)][100.0%][w=236MiB/s][w=59 IOPS][eta 00m:00s]
seq-write-fsx: (groupid=0, jobs=1): err= 0: pid=28382: Sun Feb 22 08:13:43 2026
  write: IOPS=62, BW=252MiB/s (264MB/s)(14.8GiB/60123msec); 0 zone resets
    slat (usec): min=1819, max=171036, avg=15734.90, stdev=15971.13
    clat (nsec): min=1791, max=125428, avg=6997.54, stdev=5446.64
     lat (usec): min=1821, max=171042, avg=15741.89, stdev=15972.47
    clat percentiles (usec):
     |  1.00th=[    3],  5.00th=[    4], 10.00th=[    4], 20.00th=[    5],
     | 30.00th=[    6], 40.00th=[    7], 50.00th=[    8], 60.00th=[    8],
     | 70.00th=[    8], 80.00th=[    9], 90.00th=[    9], 95.00th=[   10],
     | 99.00th=[   20], 99.50th=[   30], 99.90th=[  122], 99.95th=[  124],
     | 99.99th=[  126]
   bw (  KiB/s): min=188416, max=385024, per=100.00%, avg=258244.34, stdev=29239.54, samples=120
   iops        : min=   46, max=   94, avg=63.03, stdev= 7.14, samples=120
  lat (usec)   : 2=0.21%, 4=12.74%, 10=82.27%, 20=3.81%, 50=0.77%
  lat (usec)   : 100=0.08%, 250=0.13%
  cpu          : usr=0.71%, sys=16.38%, ctx=5929, majf=0, minf=13
  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,3784,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=252MiB/s (264MB/s), 252MiB/s-252MiB/s (264MB/s-264MB/s), io=14.8GiB (15.9GB), run=60123-60123msec
スループット avg レイテンシ
252 MiB/s 15.7ms(lat avg=15,741.89μs)
EFS の結果(書き込み)
fio --name=seq-write-efs \
    --rw=write \
    --bs=4m \
    --size=4g \
    --numjobs=1 \
    --iodepth=1 \
    --ioengine=libaio \
    --runtime=60 \
    --time_based \
    --filename=/mnt/efs/testfile \
    --group_reporting
出力
seq-write-efs: (g=0): rw=write, bs=(R) 4096KiB-4096KiB, (W) 4096KiB-4096KiB, (T) 4096KiB-4096KiB, ioengine=libaio, iodepth=1
fio-3.32
Starting 1 process
seq-write-efs: Laying out IO file (1 file / 4096MiB)
Jobs: 1 (f=1): [W(1)][100.0%][w=384MiB/s][w=95 IOPS][eta 00m:00s]
seq-write-efs: (groupid=0, jobs=1): err= 0: pid=28148: Sun Feb 22 08:06:16 2026
  write: IOPS=91, BW=366MiB/s (384MB/s)(21.4GiB/60015msec); 0 zone resets
    slat (usec): min=1763, max=71621, avg=10710.11, stdev=9007.78
    clat (nsec): min=1663, max=2182.2k, avg=8424.48, stdev=45750.74
     lat (usec): min=1766, max=71630, avg=10718.54, stdev=9009.49
    clat percentiles (usec):
     |  1.00th=[    4],  5.00th=[    5], 10.00th=[    5], 20.00th=[    6],
     | 30.00th=[    6], 40.00th=[    7], 50.00th=[    7], 60.00th=[    8],
     | 70.00th=[    8], 80.00th=[    8], 90.00th=[    9], 95.00th=[   10],
     | 99.00th=[   22], 99.50th=[   28], 99.90th=[  167], 99.95th=[ 1647],
     | 99.99th=[ 2180]
   bw (  KiB/s): min=90112, max=434176, per=100.00%, avg=374749.95, stdev=46576.62, samples=119
   iops        : min=   22, max=  106, avg=91.45, stdev=11.39, samples=119
  lat (usec)   : 2=0.04%, 4=4.28%, 10=91.33%, 20=2.95%, 50=1.09%
  lat (usec)   : 100=0.13%, 250=0.09%, 500=0.02%, 1000=0.02%
  lat (msec)   : 2=0.04%, 4=0.02%
  cpu          : usr=1.08%, sys=24.55%, ctx=7512, majf=0, minf=11
  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,5488,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=366MiB/s (384MB/s), 366MiB/s-366MiB/s (384MB/s-384MB/s), io=21.4GiB (23.0GB), run=60015-60015msec
スループット avg レイテンシ
366 MiB/s 10.7ms(lat avg=10,718.54μs)
FSx for OpenZFS の結果(読み込み)
fio --name=seq-read-fsx \
    --rw=read \
    --bs=4m \
    --size=4g \
    --numjobs=1 \
    --iodepth=1 \
    --ioengine=libaio \
    --runtime=60 \
    --time_based \
    --filename=/mnt/fsx/testfile \
    --group_reporting
出力
seq-read-fsx: (g=0): rw=read, bs=(R) 4096KiB-4096KiB, (W) 4096KiB-4096KiB, (T) 4096KiB-4096KiB, ioengine=libaio, iodepth=1
fio-3.32
Starting 1 process
Jobs: 1 (f=1): [R(1)][100.0%][r=204MiB/s][r=51 IOPS][eta 00m:00s]
seq-read-fsx: (groupid=0, jobs=1): err= 0: pid=28440: Sun Feb 22 08:15:18 2026
  read: IOPS=70, BW=281MiB/s (295MB/s)(16.5GiB/60003msec)
    slat (usec): min=534, max=258954, avg=14038.21, stdev=29922.29
    clat (nsec): min=1116, max=2218.5k, avg=7441.70, stdev=39802.63
     lat (usec): min=536, max=258962, avg=14045.65, stdev=29923.38
    clat percentiles (nsec):
     |  1.00th=[   1384],  5.00th=[   1752], 10.00th=[   2024],
     | 20.00th=[   2608], 30.00th=[   3376], 40.00th=[   4320],
     | 50.00th=[   5536], 60.00th=[   6816], 70.00th=[   7328],
     | 80.00th=[   7776], 90.00th=[   8384], 95.00th=[  12224],
     | 99.00th=[  36608], 99.50th=[  44800], 99.90th=[ 168960],
     | 99.95th=[ 292864], 99.99th=[2211840]
   bw (  KiB/s): min=139264, max=598016, per=100.00%, avg=288757.39, stdev=120824.44, samples=119
   iops        : min=   34, max=  146, avg=70.45, stdev=29.50, samples=119
  lat (usec)   : 2=9.45%, 4=27.52%, 10=57.63%, 20=1.26%, 50=3.74%
  lat (usec)   : 100=0.17%, 250=0.14%, 500=0.05%
  lat (msec)   : 2=0.02%, 4=0.02%
  cpu          : usr=0.12%, sys=13.38%, ctx=4249, majf=0, minf=1034
  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=4222,0,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=281MiB/s (295MB/s), 281MiB/s-281MiB/s (295MB/s-295MB/s), io=16.5GiB (17.7GB), run=60003-60003msec
スループット avg レイテンシ
281 MiB/s 14.0ms(lat avg=14,045.65μs)
EFS の結果(読み込み)
fio --name=seq-read-efs \
    --rw=read \
    --bs=4m \
    --size=4g \
    --numjobs=1 \
    --iodepth=1 \
    --ioengine=libaio \
    --runtime=60 \
    --time_based \
    --filename=/mnt/efs/testfile \
    --group_reporting
出力
seq-read-efs: (g=0): rw=read, bs=(R) 4096KiB-4096KiB, (W) 4096KiB-4096KiB, (T) 4096KiB-4096KiB, ioengine=libaio, iodepth=1
fio-3.32
Starting 1 process
Jobs: 1 (f=1): [R(1)][100.0%][r=392MiB/s][r=98 IOPS][eta 00m:00s]
seq-read-efs: (groupid=0, jobs=1): err= 0: pid=28323: Sun Feb 22 08:12:18 2026
  read: IOPS=126, BW=505MiB/s (529MB/s)(29.6GiB/60006msec)
    slat (usec): min=529, max=206033, avg=7778.06, stdev=13433.97
    clat (nsec): min=1290, max=1778.7k, avg=7867.42, stdev=33292.19
     lat (usec): min=531, max=206040, avg=7785.93, stdev=13436.07
    clat percentiles (nsec):
     |  1.00th=[   1720],  5.00th=[   2192], 10.00th=[   2512],
     | 20.00th=[   3216], 30.00th=[   3824], 40.00th=[   4448],
     | 50.00th=[   5216], 60.00th=[   6304], 70.00th=[   7392],
     | 80.00th=[   8032], 90.00th=[   9152], 95.00th=[  25472],
     | 99.00th=[  39680], 99.50th=[  52480], 99.90th=[ 175104],
     | 99.95th=[ 224256], 99.99th=[1777664]
   bw (  KiB/s): min=212992, max=630784, per=99.97%, avg=516712.83, stdev=81919.42, samples=119
   iops        : min=   52, max=  154, avg=126.08, stdev=19.98, samples=119
  lat (usec)   : 2=3.08%, 4=30.06%, 10=58.72%, 20=1.44%, 50=6.17%
  lat (usec)   : 100=0.37%, 250=0.13%
  lat (msec)   : 2=0.04%
  cpu          : usr=0.10%, sys=25.43%, ctx=8018, majf=0, minf=1035
  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=7572,0,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=505MiB/s (529MB/s), 505MiB/s-505MiB/s (529MB/s-529MB/s), io=29.6GiB (31.8GB), run=60006-60006msec
スループット avg レイテンシ
505 MiB/s 7.8ms(lat avg=7,785.93μs)

--direct=1(OSページキャッシュをバイパス)

FSx for OpenZFS の結果(書き込み)
fio --name=seq-write-fsx-direct \
    --rw=write \
    --bs=4m \
    --size=4g \
    --numjobs=1 \
    --iodepth=1 \
    --ioengine=libaio \
    --direct=1 \
    --runtime=60 \
    --time_based \
    --filename=/mnt/fsx/testfile \
    --group_reporting
出力
seq-write-fsx-direct: (g=0): rw=write, bs=(R) 4096KiB-4096KiB, (W) 4096KiB-4096KiB, (T) 4096KiB-4096KiB, ioengine=libaio, iodepth=1
fio-3.32
Starting 1 process
seq-write-fsx-direct: Laying out IO file (1 file / 4096MiB)
Jobs: 1 (f=1): [W(1)][100.0%][w=168MiB/s][w=42 IOPS][eta 00m:00s]
seq-write-fsx-direct: (groupid=0, jobs=1): err= 0: pid=28943: Sun Feb 22 08:32:44 2026
  write: IOPS=43, BW=174MiB/s (182MB/s)(10.2GiB/60006msec); 0 zone resets
    slat (usec): min=353, max=3427, avg=559.57, stdev=131.75
    clat (usec): min=19600, max=83214, avg=22476.04, stdev=2432.86
     lat (usec): min=20129, max=83739, avg=23035.60, stdev=2446.90
    clat percentiles (usec):
     |  1.00th=[21365],  5.00th=[21365], 10.00th=[21627], 20.00th=[21627],
     | 30.00th=[21627], 40.00th=[21890], 50.00th=[21890], 60.00th=[22152],
     | 70.00th=[22152], 80.00th=[22414], 90.00th=[23462], 95.00th=[25560],
     | 99.00th=[31065], 99.50th=[33817], 99.90th=[55313], 99.95th=[59507],
     | 99.99th=[83362]
   bw (  KiB/s): min=155337, max=188416, per=100.00%, avg=177811.97, stdev=5588.38, samples=119
   iops        : min=   37, max=   46, avg=43.40, stdev= 1.40, samples=119
  lat (msec)   : 20=0.08%, 50=99.81%, 100=0.12%
  cpu          : usr=1.11%, sys=1.35%, ctx=2812, majf=0, minf=11
  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,2604,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=174MiB/s (182MB/s), 174MiB/s-174MiB/s (182MB/s-182MB/s), io=10.2GiB (10.9GB), run=60006-60006msec
スループット avg レイテンシ
174 MiB/s 23ms(lat avg=23,035.60μs)
EFS の結果(書き込み)
fio --name=seq-write-efs-direct \
    --rw=write \
    --bs=4m \
    --size=4g \
    --numjobs=1 \
    --iodepth=1 \
    --ioengine=libaio \
    --direct=1 \
    --runtime=60 \
    --time_based \
    --filename=/mnt/efs/testfile \
    --group_reporting
出力
seq-write-efs-direct: (g=0): rw=write, bs=(R) 4096KiB-4096KiB, (W) 4096KiB-4096KiB, (T) 4096KiB-4096KiB, ioengine=libaio, iodepth=1
fio-3.32
Starting 1 process
seq-write-efs-direct: Laying out IO file (1 file / 4096MiB)
Jobs: 1 (f=1): [W(1)][100.0%][w=40.0MiB/s][w=10 IOPS][eta 00m:00s]
seq-write-efs-direct: (groupid=0, jobs=1): err= 0: pid=28952: Sun Feb 22 08:34:06 2026
  write: IOPS=11, BW=45.2MiB/s (47.4MB/s)(2712MiB/60009msec); 0 zone resets
    slat (usec): min=427, max=34750, avg=688.08, stdev=1320.35
    clat (msec): min=62, max=145, avg=87.81, stdev=13.45
     lat (msec): min=62, max=146, avg=88.50, stdev=13.49
    clat percentiles (msec):
     |  1.00th=[   65],  5.00th=[   70], 10.00th=[   73], 20.00th=[   77],
     | 30.00th=[   81], 40.00th=[   84], 50.00th=[   86], 60.00th=[   90],
     | 70.00th=[   93], 80.00th=[   99], 90.00th=[  106], 95.00th=[  113],
     | 99.00th=[  128], 99.50th=[  138], 99.90th=[  146], 99.95th=[  146],
     | 99.99th=[  146]
   bw (  KiB/s): min=32768, max=57344, per=99.96%, avg=46260.02, stdev=5703.05, samples=119
   iops        : min=    8, max=   14, avg=11.29, stdev= 1.40, samples=119
  lat (msec)   : 100=83.48%, 250=16.52%
  cpu          : usr=0.24%, sys=0.42%, ctx=939, majf=0, minf=10
  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,678,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=45.2MiB/s (47.4MB/s), 45.2MiB/s-45.2MiB/s (47.4MB/s-47.4MB/s), io=2712MiB (2844MB), run=60009-60009msec
スループット avg レイテンシ
45.2 MiB/s 88.5ms(lat avg=88.50ms)
FSx for OpenZFS の結果(読み込み)
fio --name=seq-read-fsx-direct \
    --rw=read \
    --bs=4m \
    --size=4g \
    --numjobs=1 \
    --iodepth=1 \
    --ioengine=libaio \
    --direct=1 \
    --runtime=60 \
    --time_based \
    --filename=/mnt/fsx/testfile \
    --group_reporting
出力
seq-read-fsx-direct: (g=0): rw=read, bs=(R) 4096KiB-4096KiB, (W) 4096KiB-4096KiB, (T) 4096KiB-4096KiB, ioengine=libaio, iodepth=1
fio-3.32
Starting 1 process
Jobs: 1 (f=1): [R(1)][100.0%][r=280MiB/s][r=70 IOPS][eta 00m:00s]
seq-read-fsx-direct: (groupid=0, jobs=1): err= 0: pid=29010: Sun Feb 22 08:35:58 2026
  read: IOPS=74, BW=299MiB/s (313MB/s)(17.5GiB/60014msec)
    slat (usec): min=239, max=16325, avg=365.29, stdev=600.51
    clat (msec): min=4, max=113, avg=13.01, stdev= 3.31
     lat (msec): min=8, max=114, avg=13.38, stdev= 3.36
    clat percentiles (msec):
     |  1.00th=[    8],  5.00th=[    8], 10.00th=[    9], 20.00th=[   12],
     | 30.00th=[   14], 40.00th=[   14], 50.00th=[   14], 60.00th=[   14],
     | 70.00th=[   14], 80.00th=[   15], 90.00th=[   15], 95.00th=[   16],
     | 99.00th=[   22], 99.50th=[   29], 99.90th=[   42], 99.95th=[   48],
     | 99.99th=[  114]
   bw (  KiB/s): min=180224, max=483328, per=100.00%, avg=306371.57, stdev=52966.87, samples=119
   iops        : min=   44, max=  118, avg=74.77, stdev=12.92, samples=119
  lat (msec)   : 10=16.59%, 20=82.14%, 50=1.23%, 100=0.02%, 250=0.02%
  cpu          : usr=0.04%, sys=2.47%, ctx=4560, majf=0, minf=1034
  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=4484,0,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=299MiB/s (313MB/s), 299MiB/s-299MiB/s (313MB/s-313MB/s), io=17.5GiB (18.8GB), run=60014-60014msec
スループット avg レイテンシ
299 MiB/s 13.4ms(lat avg=13.38ms)
EFS の結果(読み込み)
fio --name=seq-read-efs-direct \
    --rw=read \
    --bs=4m \
    --size=4g \
    --numjobs=1 \
    --iodepth=1 \
    --ioengine=libaio \
    --direct=1 \
    --runtime=60 \
    --time_based \
    --filename=/mnt/efs/testfile \
    --group_reporting
出力
seq-read-efs-direct: (g=0): rw=read, bs=(R) 4096KiB-4096KiB, (W) 4096KiB-4096KiB, (T) 4096KiB-4096KiB, ioengine=libaio, iodepth=1
fio-3.32
Starting 1 process
seq-read-efs-direct: Laying out IO file (1 file / 4096MiB)
Jobs: 1 (f=0): [f(1)][100.0%][r=204MiB/s][r=51 IOPS][eta 00m:00s]
seq-read-efs-direct: (groupid=0, jobs=1): err= 0: pid=29066: Sun Feb 22 08:37:32 2026
  read: IOPS=47, BW=191MiB/s (200MB/s)(11.2GiB/60025msec)
    slat (usec): min=246, max=17789, avg=342.74, stdev=400.59
    clat (usec): min=12658, max=56271, avg=20586.96, stdev=6547.61
     lat (usec): min=14308, max=59826, avg=20929.70, stdev=6563.46
    clat percentiles (usec):
     |  1.00th=[14615],  5.00th=[15139], 10.00th=[15401], 20.00th=[15795],
     | 30.00th=[16188], 40.00th=[16909], 50.00th=[18482], 60.00th=[20055],
     | 70.00th=[21890], 80.00th=[23987], 90.00th=[28443], 95.00th=[34341],
     | 99.00th=[45351], 99.50th=[49021], 99.90th=[53216], 99.95th=[53216],
     | 99.99th=[56361]
   bw (  KiB/s): min=163840, max=229376, per=100.00%, avg=195365.57, stdev=13767.14, samples=119
   iops        : min=   40, max=   56, avg=47.69, stdev= 3.36, samples=119
  lat (msec)   : 20=59.10%, 50=40.55%, 100=0.35%
  cpu          : usr=0.04%, sys=1.71%, ctx=2891, majf=0, minf=1035
  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=2863,0,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=191MiB/s (200MB/s), 191MiB/s-191MiB/s (200MB/s-200MB/s), io=11.2GiB (12.0GB), run=60025-60025msec
スループット avg レイテンシ
191 MiB/s 20.9ms(lat avg=20,929.70μs)

まとめ

--direct=0(バッファリングあり)

条件 指標 FSx for OpenZFS EFS 速い方
書き込み スループット 252 MiB/s 366 MiB/s EFS
平均レイテンシ 15.7ms 10.7ms
読み込み スループット 281 MiB/s 505 MiB/s EFS
平均レイテンシ 14.0ms 7.8ms

--direct=1(バッファリングなし)

条件 指標 FSx for OpenZFS EFS 速い方
書き込み スループット 174 MiB/s 45.2 MiB/s FSx(約4倍)
平均レイテンシ 23ms 88.5ms
読み込み スループット 299 MiB/s 191 MiB/s FSx
平均レイテンシ 13.4ms 20.9ms

結果の考察に入る前に、前提として、EFSはクライアントが同AZのマウントターゲットへ接続してファイルを書き込む際に特定の条件で内部では複数AZにまたがるデータ同期を行っています。

公式ドキュメント引用:

Amazon EFS は、アプリケーションが NFS に求める close-to open 整合性セマンティクスを提供します。
Amazon EFS では、以下の状況において、リージョンファイルシステムの書き込みオペレーションがアベイラビリティーゾーン間で永続的に保存されます。
アプリケーションは、同期書き込みオペレーションを実行します (たとえば、open フラグで O_DIRECT Linux コマンドを使用するか、または fsync Linux コマンドを使用します)。
アプリケーションがファイルを閉じます。
Amazon EFS は、アクセスパターンによっては、close-to-open セマンティクスよりも強力な整合性をもたらします。同期データアクセスを実行し、非追加書き込みを実行するアプリケーションは、データアクセスのための書き込み後の読み取り整合性を保ちます。

参考:

FSx for OpenZFS Multi-AZへの書き込み時もアクティブ→スタンバイへの同期レプリケーションを行ってくれています。

公式ドキュメント引用:

シングル AZ(非 HA および HA)ファイルシステムと比較して、マルチ AZ (HA) ファイルシステムは、各アベイラビリティゾーン内および 2 つのアベイラビリティゾーン間でデータを同期的に複製することで、耐久性が向上します。

参考:

この仕様を踏まえて結果を振り返ると、--direct=0--direct=1で結果が逆転しているのは以下の理由によるものと考えています。

--direct=0(バッファリングあり)では、書き込みデータはまずEC2上のRAM(OSキャッシュ)に書かれた時点でアプリケーションへ完了が返り、実際にNFSサーバー(EFS)へ届けるのはOSが後から非同期に行います。EFSの公式ドキュメントによると、EFSが書き込みをAZ全体へ永続化するのは「O_DIRECTフラグ付きの同期書き込み」または「ファイルをクローズしたとき」とされており、--direct=0では個々のwriteはAZ間レプリケーションを待ちません。そのため同AZ接続のEFSが低レイテンシで計測されたと考えられます。一方FSxはAZ跨分のレイテンシに加えて、AZ間のデータ同期分のレイテンシも乗るため相対的に遅くなったと思われます。

--direct=1(バッファリングなし)では、データが実際にストレージへ書き込まれるまでアプリケーションが待つため、EFSの内部データ同期完了までの時間がそのまま計測値に現れ、書き込みavgレイテンシが「88ms」になったと考えられます。FSxはAZ跨ぎがあっても「23ms」で完了しており、同期レプリケーションの速度の違いが出た可能性があります。

また、読み込みで--direct=1にもかかわらずFSxが速い点については、クライアントのOSキャッシュをバイパスしてもFSx for OpenZFSが持つインメモリキャッシュ機能が機能しているためではないかと考えています。EFSはそれに相当するサーバー側キャッシュがなく都度バックエンドへアクセスしているため、AZ跨ぎのあるFSxに逆転される結果になったと推測しています。

最後に

今回の検証結果を実際のアプリケーションに当てはめる際の参考として、--directオプションとアプリの動作の対応を整理します。

一般的なWebアプリケーションでのファイル保存はwrite()close()の流れで行われ、fsync()を明示的に呼ぶパターンは少ないです。よってアプリケーションからファイルを保存する動作は--direct=0の結果レイテンシに近くなると思います。この条件では今回の検証においてEFSが少し速いという結果でした。

一方、アプリケーションが書き込み後にfsync()を呼ぶ実装の場合は--direct=1相当の動作になります。この条件では書き込みavgレイテンシが今回の条件にてFSxは「23ms」、EFSは「88ms」という結果になりFSxの方が高速でした。

また、今回は 「AZを跨いだFSx for OpenZFSアクセス vs AZを跨がないEFSアクセス」 という特定観点での比較のため、実際のファイルシステムにてどちらを採用するという判断はこの検証だけではできないことに注意が必要です。

ニッチケースですが、この記事がどなたかの参考になれば幸いです。今回は以上です。

この記事をシェアする

FacebookHatena blogX

関連記事