Compute Engine クライアントを使用したパフォーマンス テスト

このページでは、Compute Engine クライアントを使用して Google Cloud Managed Lustre インスタンスのパフォーマンスをテストする方法について説明します。このドキュメントでは、fio を使用して単一クライアントのパフォーマンスを測定し、IOR ベンチマーク ツールを使用してマルチクライアントのパフォーマンスを集計する手順について説明します。

単一クライアントのパフォーマンスを測定する

単一の Compute Engine クライアントから読み取りと書き込みのパフォーマンスをテストするには、fioFlexible I/O テスター)コマンドライン ツールを使用します。

  1. fio をインストールします。

    Rocky 8

    sudo dnf install fio -y
    

    Ubuntu 20.04 と 22.04

    sudo apt update
    sudo install fio
    
  2. 次のコマンドを実行します。

    fio --ioengine=libaio --filesize=32G --ramp_time=2s \
    --runtime=5m --numjobs=16 --direct=1 --verify=0 --randrepeat=0 \
    --group_reporting --directory=/lustre --buffer_compress_percentage=50 \
    --name=read --blocksize=1m --iodepth=64 --readwrite=read
    

テストの完了には、約 5 分かかります。完了すると、結果が表示されます。構成によっては、VM の最大ネットワーク速度までのスループットと、TiB あたり数千の IOPS が期待できます。

マルチクライアントのパフォーマンスを測定する

複数の Compute Engine クライアントから Managed Lustre の読み取り / 書き込みパフォーマンスをテストするには、IOR ベンチマーク ツールを使用します。次の手順では、クライアントの設定を自動化し、IOR を使用して複数のクライアント マシンからの集約 I/O をテストする方法について説明します。IOR は、メッセージ パッシング プロトコルである MPI を使用して、複数のクライアント マシンが相互に連携できるようにします。

始める前に、ネットワークの mtu 値が 8896 に設定されていることを確認してください。

環境変数を設定して SSH 認証鍵を生成する

クラスタをデプロイする前に、ローカルマシンで SSH 認証鍵を生成します。この鍵は、作成時にクライアント マシンに配布され、MPI のパスワードなしの通信を有効にします。

export SSH_USER="lustre-user"
export CLIENT_PREFIX="lustre-client"

# Generate an SSH key for the specified user
ssh-keygen -t rsa -b 4096 -C "${SSH_USER}" -N '' -f "./id_rsa"
chmod 600 "./id_rsa"

# Create a metadata file formatted for Google Cloud
echo "${SSH_USER}:$(cat "./id_rsa.pub") ${SSH_USER}" > "./keys.txt"

起動スクリプトを作成する

次の内容をローカルマシンの install-ior.sh という名前のファイルに保存します。このスクリプトは、オペレーティング システムを検出し、ブートロックが解除されるのを待ってから、Lustre クライアントと依存関係を安全にインストールし、IOR の安定版をコンパイルして、Managed Lustre ファイル システムをマウントします。

LUSTRE_IP は Managed Lustre インスタンスの IP アドレスに、FS_NAME はファイル システムの名前に置き換えます。

#!/bin/bash
source /etc/os-release

if [[ "$ID" == "ubuntu" ]]; then
    # Ubuntu
    # Wait for apt lock
    while fuser /var/lib/dpkg/lock-frontend >/dev/null 2>&1; do sleep 5; done

    # Configure Artifact Registry repo for Ubuntu
    curl -fsSL https://us-apt.pkg.dev/doc/repo-signing-key.gpg | sudo gpg --dearmor -o /usr/share/keyrings/us-apt-pkg-dev.gpg

    if [[ "$VERSION_ID" == "22.04" ]]; then
        REPO_NAME="lustre-client-ubuntu-jammy"
    elif [[ "$VERSION_ID" == "24.04" ]]; then
        REPO_NAME="lustre-client-ubuntu-noble"
    fi

    echo "deb [signed-by=/usr/share/keyrings/us-apt-pkg-dev.gpg] https://us-apt.pkg.dev/projects/lustre-client-binaries $REPO_NAME main" | sudo tee /etc/apt/sources.list.d/lustre-client.list

    sudo apt-get update
    while ! sudo apt-get install -y lustre-client-modules-$(uname -r) lustre-client-utils openmpi-bin libopenmpi-dev make gcc g++ wget git automake autoconf libaio-dev; do
        sleep 5
    done
    sudo modprobe lustre
else
    # Red Hat / Rocky Linux
    while systemctl is-active --quiet dnf-makecache.service; do sleep 5; done

    if [[ "$ID" == "rocky" && "$VERSION_ID" == 8* ]]; then
        REPO="lustre-client-rocky-8"
    elif [[ "$ID" == "rocky" && "$VERSION_ID" == 9* ]]; then
        REPO="lustre-client-rocky-9"
    elif [[ "$ID" == "rhel" && "$VERSION_ID" == 9* ]]; then
        REPO="lustre-client-rocky-9"
    fi

    gcloud beta artifacts print-settings yum --repository=$REPO --location=us --project=lustre-client-binaries | sudo bash

    while ! sudo dnf -y --enablerepo=$REPO install kmod-lustre-client lustre-client; do sleep 5; done
    sudo modprobe lustre

    while ! sudo dnf install -y openmpi openmpi-devel make gcc gcc-c++ wget git automake autoconf libaio-devel; do sleep 5; done

    export PATH=$PATH:/usr/lib64/openmpi/bin
fi

# Build IOR from source
echo "Cloning repo: https://github.com/hpc/ior.git and building IOR"
pushd /tmp
git clone -b 4.0.0 https://github.com/hpc/ior
cd ior
./bootstrap
./configure --disable-dependency-tracking --with-aio
make clean
make -j"$(nproc)"
sudo make install
popd
echo "Finished building IOR"

# Mount the Managed Lustre file system
mkdir -p /lustre

if ! grep -q "/lustre" /etc/fstab; then
    echo "LUSTRE_IP@tcp:/FS_NAME /lustre lustre defaults,_netdev 0 0" >> /etc/fstab
fi

mount -a

クライアント マシンをデプロイする

次のコマンドを実行して、Compute Engine クライアント マシンを一括作成します。

gcloud compute instances bulk create \
  --name-pattern="${CLIENT_PREFIX}-####" \
  --zone="ZONE" \
  --machine-type="MACHINE_TYPE" \
  --scopes="https://www.googleapis.com/auth/cloud-platform" \
  --network-interface=subnet=SUBNET,nic-type=GVNIC \
  --network-performance-configs=total-egress-bandwidth-tier=TIER_1 \
  --metadata-from-file=ssh-keys=./keys.txt,startup-script=install-ior.sh \
  --create-disk=auto-delete=yes,boot=yes,\
image-family=IMAGE_FAMILY,\
image-project=IMAGE_PROJECT,\
mode=rw,size=100,type=DISK_TYPE \
  --count NUM_NODES
  • ZONESUBNET は、特定のデプロイの値に置き換えます。

  • MACHINE_TYPE を選択します。ベンチマークの全体的なパフォーマンスは、クライアント マシンタイプによって異なります。最適なスループットを実現するマシンタイプの選択については、パフォーマンスに関する考慮事項をご覧ください。

  • マシンタイプが TIER_1 ネットワーキングをサポートしていない場合は、コマンドから --network-performance-configs 行を削除します。

  • DISK_TYPEhyperdisk-balanced(世代名に 4 が含まれるマシンタイプ(c4an4 など)の場合)または pd-balanced のいずれかに設定します。

  • IMAGE_FAMILYIMAGE_PROJECT を指定します。サポートされている値は次のとおりです。

    OS イメージ ファミリー(x86) イメージ ファミリー(ARM) イメージ プロジェクト
    HPC Rocky Linux 8 hpc-rocky-linux-8 非対応 cloud-hpc-image-public
    Rocky Linux 9 rocky-linux-9 rocky-linux-9-arm64 rocky-linux-cloud
    RHEL 9 rhel-9 rhel-9-arm64 rhel-cloud
    Ubuntu 22.04 LTS ubuntu-2204-lts ubuntu-2204-lts-arm64 ubuntu-os-cloud
    Ubuntu 24.04 LTS 非対応 ubuntu-2404-lts-arm64 ubuntu-os-cloud
  • NUM_NODES を指定します。ファイル システムを飽和させるには、クラスタの合計ネットワーク容量がファイル システムのプロビジョニングされたスループットを約 20% 超える必要があります。

    Tier 1 ネットワーキングが有効になっているマシンでは、VM ファミリーと CPU 数に応じて、1 台のマシンで 25 Gbps ~ 200 Gbps(約 3,000 ~ 25,000 MBps)をプッシュできます。標準インスタンスの場合、下り(外向き)は通常、vCPU あたり約 2 Gbps に制限されます。

    たとえば、Managed Lustre インスタンスの容量で理論上のスループットが 100,000 MBps になる場合、それを飽和させるには、クライアントの下り(外向き)の合計が 120,000 MBps(100,000 * 1.2)必要です。

    • 標準インスタンスの場合: 各クライアント マシンの公開下り(外向き)が 2,000 MBps の場合は、少なくとも 60 個のクライアント(120,000 / 2,000)をプロビジョニングする必要があります。
    • Tier 1 ネットワーキングを使用する場合: 各クライアント マシンの下り(外向き)が 10,000 Mbps(約 80 Gbps)の場合、少なくとも 12 個のクライアント(120,000 / 10,000)をプロビジョニングする必要があります。

鍵とファイルをコピーする

クライアント マシンで起動スクリプトが完了するのを待っている間に、次のコマンドをローカルで実行して、ノード間通信用にすべてのノードを自動的に構成します。

  1. クライアント マシンのプライベート IP アドレスを MPI ホストファイルに保存し、クライアント マシンへの SSH アクセスと SCP アクセス用のパブリック IP アドレスを保存します。

    gcloud compute instances list --filter="name ~ '^${CLIENT_PREFIX}*'" --format="csv[no-heading](INTERNAL_IP)" > hosts.txt
    gcloud compute instances list --filter="name ~ '^${CLIENT_PREFIX}*'" --format="csv[no-heading](EXTERNAL_IP)" > external_ips.txt
    
  2. 秘密鍵をすべてのクライアントにコピーします。これにより、ベンチマーク中にワーカーノードが安全に相互通信できるようになります。

    while IFS= read -r IP || [[ -n "$IP" ]]
    do
      [[ -z "$IP" ]] && continue
      echo "Preparing and copying to ${SSH_USER}@${IP}..."
      # Ensure the .ssh directory exists
      ssh -i ./id_rsa -o StrictHostKeyChecking=no "${SSH_USER}@${IP}" "mkdir -p ~/.ssh && chmod 700 ~/.ssh"
      # Copy the file
      scp -i ./id_rsa -o StrictHostKeyChecking=no ./id_rsa "${SSH_USER}@${IP}:~/.ssh/id_rsa"
    done < "./external_ips.txt"
    
  3. ヘッドノードを指定し、ホストファイルをコピーします。これは、ベンチマークを実行するマシンになります。

    export HEAD_NODE=$(head -n 1 ./external_ips.txt)
    scp -i ./id_rsa -o "StrictHostKeyChecking=no" -o UserKnownHostsFile=/dev/null ./hosts.txt ${SSH_USER}@${HEAD_NODE}:~/hostfile
    

接続と確認

  1. ヘッドノードに接続します。

    ssh -i ./id_rsa -o "StrictHostKeyChecking=no" -o UserKnownHostsFile=/dev/null ${SSH_USER}@${HEAD_NODE}
    
  2. ベンチマークを実行する前に、起動スクリプトが完了し、ファイル システムが正常にマウントされていることを確認します。

    起動スクリプトのログを確認するには:

    sudo journalctl -u google-startup-scripts.service -f
    

    ファイル システムがマウントされていることを確認するには:

    df -h | grep lustre
    

    ファイル システムが表示されない場合は、バックグラウンド インストール スクリプトが完了するまで数分待ちます。マウントされると、絶対パス /lustre で使用できるようになります。

IOR ベンチマークを実行する

  1. Rocky Linux と RHEL のみ: ヘッドノードから OpenMPI モジュールを読み込みます。

    if [ -f /etc/profile.d/modules.sh ]; then
        source /etc/profile.d/modules.sh
        module load mpi/openmpi-$(arch)
    fi
    
  2. テスト ディレクトリを作成し、所有権を取得します。

    sudo mkdir -p /lustre/test
    sudo chown -R $USER:$USER /lustre/test
    
  3. テスト変数を定義します。

    export NUM_NODES="NUM_NODES"
    export PROCESSES_PER_NODE="PROCESSES_PER_NODE"
    export NUM_PROCESSES=$(( NUM_NODES * PROCESSES_PER_NODE ))
    

    ここで

    • NUM_NODES: テストに参加しているクライアント マシンの合計数。
    • PROCESSES_PER_NODE: 各クライアント マシンで実行する MPI ランクの数。まず、クライアント マシンの物理コア数(または vCPU 数の半分)と一致するように設定することをおすすめします。ハイ パフォーマンス マシンタイプの場合、通常、この値を 816 の間に設定すると、ネットワーク スループットが最大になります。この値を大きくしすぎると、コンテキスト切り替えのオーバーヘッドが発生し、ベンチマークのパフォーマンスが低下する可能性があります。
  4. コマンドを実行してベンチマークを開始します。

    Rocky Linux と RHEL

    書き込みスループット

    このコマンドは、ピーク時の定常状態のスループットをテストするために、60 秒間継続的に書き込みを行います。タスクごとのファイルサイズは、60 秒のタイマーが切れるまでタスクが書き込みを続けるように、上限を 50 TiB に設定します。

    mpirun \
      --allow-run-as-root \
      --mca plm_rsh_no_tree_spawn 1 \
      --mca opal_set_max_sys_limits 1 \
      --mca plm_rsh_num_concurrent ${NUM_NODES} \
      --mca plm_rsh_args "-o StrictHostKeyChecking=no" \
      --prefix /usr/lib64/openmpi \
      --npernode ${PROCESSES_PER_NODE} \
      --np ${NUM_PROCESSES} \
      --hostfile ~/hostfile \
      /usr/local/bin/ior \
      -a AIO \
      --posix.odirect \
      -F -g -v -w -k \
      -t 4m -b 50t \
      -D 60 \
      -O stoneWallingWearOut=1 \
      -O stoneWallingStatusFile=/lustre/test/ior-easy.stonewall \
      -o /lustre/test/ior_file

    読み取りスループット

    このフェーズでは、60 秒間の書き込みスループット テストで正常に書き込まれたデータ量を正確に読み取ります。タスクごとのファイルサイズ(-b)は、書き込みフェーズのジオメトリに合わせて 50 TiB に設定されていますが、-O stoneWallingWearOut=1 フラグは、IOR がストーンウォール ステータス ファイルに記録された正確なデータ境界に達するとすぐに読み取りを停止するように指示します。

    mpirun \
      --allow-run-as-root \
      --mca plm_rsh_no_tree_spawn 1 \
      --mca opal_set_max_sys_limits 1 \
      --mca plm_rsh_num_concurrent ${NUM_NODES} \
      --mca plm_rsh_args "-o StrictHostKeyChecking=no" \
      --prefix /usr/lib64/openmpi \
      --npernode ${PROCESSES_PER_NODE} \
      --np ${NUM_PROCESSES} \
      --hostfile ~/hostfile \
      /usr/local/bin/ior \
      -a AIO \
      --posix.odirect \
      -F -g -v -r -k \
      -t 4m -b 50t \
      -D 60 \
      -O stoneWallingWearOut=1 \
      -O stoneWallingStatusFile=/lustre/test/ior-easy.stonewall \
      -o /lustre/test/ior_file

    書き込み IOPS

    このテストでは、小さい 4 KiB の転送サイズと 8 GiB のタスクごとのファイルサイズを使用して、ファイル システムが処理できる最大 1 秒あたりの入出力オペレーション(IOPS)を測定します。

    mpirun \
      --allow-run-as-root \
      --mca plm_rsh_no_tree_spawn 1 \
      --mca opal_set_max_sys_limits 1 \
      --mca plm_rsh_num_concurrent ${NUM_NODES} \
      --mca plm_rsh_args "-o StrictHostKeyChecking=no" \
      --prefix /usr/lib64/openmpi \
      --np ${NUM_PROCESSES} \
      --oversubscribe \
      --map-by node \
      --bind-to socket \
      --hostfile ~/hostfile \
      /usr/local/bin/ior \
      -e \
      -t 4k \
      -b 8g \
      -s 1 \
      -a AIO \
      --posix.odirect \
      --aio.max-pending=256 \
      -w \
      -F \
      -z \
      -Q 1 \
      -G 1745405099 \
      -D 45 \
      -O stoneWallingWearOut=1 \
      -o /lustre/test/ior-random

    読み取り IOPS

    スパース ファイルからの読み取りを防ぐため、このテストでは 2 つのコマンドを使用します。1 つは、4 MiB の転送サイズと 8 GiB のタスクごとのファイルサイズを使用してソリッド ファイルを作成する書き込みです。もう 1 つは、実際の 4 KiB ランダム読み取り IOPS テストです。

    1. 読み取るファイルを作成します。

      mpirun \
        --allow-run-as-root \
        --mca plm_rsh_no_tree_spawn 1 \
        --mca opal_set_max_sys_limits 1 \
        --mca plm_rsh_num_concurrent ${NUM_NODES} \
        --mca plm_rsh_args "-o StrictHostKeyChecking=no" \
        --prefix /usr/lib64/openmpi \
        --npernode ${PROCESSES_PER_NODE} \
        --np ${NUM_PROCESSES} \
        --oversubscribe \
        --map-by node \
        --bind-to socket \
        --hostfile ~/hostfile \
        /usr/local/bin/ior \
        -a AIO \
        --posix.odirect \
        -w \
        -F \
        -k \
        -t 4m \
        -b 8g \
        -s 1 \
        -Q 1 \
        -G 1745405099 \
        -o /lustre/test/ior_rand_read
    2. IOR 読み取りテストを実行します。

      mpirun \
        --allow-run-as-root \
        --mca plm_rsh_no_tree_spawn 1 \
        --mca opal_set_max_sys_limits 1 \
        --mca plm_rsh_num_concurrent ${NUM_NODES} \
        --mca plm_rsh_args "-o StrictHostKeyChecking=no" \
        --prefix /usr/lib64/openmpi \
        --oversubscribe \
        --map-by node \
        --bind-to socket \
        --npernode ${PROCESSES_PER_NODE} \
        --np ${NUM_PROCESSES} \
        --hostfile ~/hostfile \
        /usr/local/bin/ior \
        -a AIO \
        --posix.odirect \
        --aio.max-pending 256 \
        -r \
        -F \
        -z \
        -t 4k \
        -b 8g \
        -s 1 \
        -Q 1 \
        -G 1745405099 \
        -D 45 \
        -O stoneWallingWearOut=1 \
        -o /lustre/test/ior_rand_read

    Ubuntu

    書き込みスループット

    このコマンドは、ピーク時の定常状態のスループットをテストするために、60 秒間継続的に書き込みを行います。タスクごとのファイルサイズは、60 秒のタイマーが切れるまでタスクが書き込みを続けるように、上限を 50 TiB に設定します。

    mpirun \
      --allow-run-as-root \
      --mca plm_rsh_no_tree_spawn 1 \
      --mca opal_set_max_sys_limits 1 \
      --mca plm_rsh_num_concurrent ${NUM_NODES} \
      --mca plm_rsh_args "-o StrictHostKeyChecking=no" \
      --npernode ${PROCESSES_PER_NODE} \
      --np ${NUM_PROCESSES} \
      --hostfile ~/hostfile \
      /usr/local/bin/ior \
      -a AIO \
      --posix.odirect \
      -F -g -v -w -k \
      -t 4m -b 50t \
      -D 60 \
      -O stoneWallingWearOut=1 \
      -O stoneWallingStatusFile=/lustre/test/ior-easy.stonewall \
      -o /lustre/test/ior_file

    読み取りスループット

    このフェーズでは、60 秒間の書き込みスループット テストで正常に書き込まれたデータ量を正確に読み取ります。タスクごとのファイルサイズ(-b)は、書き込みフェーズのジオメトリに合わせて 50 TiB に設定されていますが、-O stoneWallingWearOut=1 フラグは、IOR がストーンウォール ステータス ファイルに記録された正確なデータ境界に達するとすぐに読み取りを停止するように指示します。

    mpirun \
      --allow-run-as-root \
      --mca plm_rsh_no_tree_spawn 1 \
      --mca opal_set_max_sys_limits 1 \
      --mca plm_rsh_num_concurrent ${NUM_NODES} \
      --mca plm_rsh_args "-o StrictHostKeyChecking=no" \
      --npernode ${PROCESSES_PER_NODE} \
      --np ${NUM_PROCESSES} \
      --hostfile ~/hostfile \
      /usr/local/bin/ior \
      -a AIO \
      --posix.odirect \
      -F -g -v -r -k \
      -t 4m -b 50t \
      -D 60 \
      -O stoneWallingWearOut=1 \
      -O stoneWallingStatusFile=/lustre/test/ior-easy.stonewall \
      -o /lustre/test/ior_file

    書き込み IOPS

    このテストでは、小さい 4 KiB の転送サイズと 8 GiB のタスクごとのファイルサイズを使用して、ファイル システムが処理できる最大 1 秒あたりの入出力オペレーション(IOPS)を測定します。

    mpirun \
      --allow-run-as-root \
      --mca plm_rsh_no_tree_spawn 1 \
      --mca opal_set_max_sys_limits 1 \
      --mca plm_rsh_num_concurrent ${NUM_NODES} \
      --mca plm_rsh_args "-o StrictHostKeyChecking=no" \
      --np ${NUM_PROCESSES} \
      --oversubscribe \
      --map-by node \
      --bind-to socket \
      --hostfile ~/hostfile \
      /usr/local/bin/ior \
      -e \
      -t 4k \
      -b 8g \
      -s 1 \
      -a AIO \
      --posix.odirect \
      --aio.max-pending=256 \
      -w \
      -F \
      -z \
      -Q 1 \
      -G 1745405099 \
      -D 45 \
      -O stoneWallingWearOut=1 \
      -o /lustre/test/ior-random

    読み取り IOPS

    スパース ファイルからの読み取りを防ぐため、このテストでは 2 つのコマンドを使用します。1 つは、4 MiB の転送サイズと 8 GiB のタスクごとのファイルサイズを使用してソリッド ファイルを作成する書き込みです。もう 1 つは、実際の 4 KiB ランダム読み取り IOPS テストです。

    1. 読み取るファイルを作成します。

      mpirun \
        --allow-run-as-root \
        --mca plm_rsh_no_tree_spawn 1 \
        --mca opal_set_max_sys_limits 1 \
        --mca plm_rsh_num_concurrent ${NUM_NODES} \
        --mca plm_rsh_args "-o StrictHostKeyChecking=no" \
        --npernode ${PROCESSES_PER_NODE} \
        --np ${NUM_PROCESSES} \
        --oversubscribe \
        --map-by node \
        --bind-to socket \
        --hostfile ~/hostfile \
        /usr/local/bin/ior \
        -a AIO \
        --posix.odirect \
        -w \
        -F \
        -k \
        -t 4m \
        -b 8g \
        -s 1 \
        -Q 1 \
        -G 1745405099 \
        -o /lustre/test/ior_rand_read
    2. IOR 読み取りテストを実行します。

      mpirun \
        --allow-run-as-root \
        --mca plm_rsh_no_tree_spawn 1 \
        --mca opal_set_max_sys_limits 1 \
        --mca plm_rsh_num_concurrent ${NUM_NODES} \
        --mca plm_rsh_args "-o StrictHostKeyChecking=no" \
        --oversubscribe \
        --map-by node \
        --bind-to socket \
        --npernode ${PROCESSES_PER_NODE} \
        --np ${NUM_PROCESSES} \
        --hostfile ~/hostfile \
        /usr/local/bin/ior \
        -a AIO \
        --posix.odirect \
        --aio.max-pending 256 \
        -r \
        -F \
        -z \
        -t 4k \
        -b 8g \
        -s 1 \
        -Q 1 \
        -G 1745405099 \
        -D 45 \
        -O stoneWallingWearOut=1 \
        -o /lustre/test/ior_rand_read

    mpirun フラグは次のとおりです。

    • --mca plm_rsh_no_tree_spawn 1: ツリーベースのデーモン スポーンを無効にして、ノード間の起動の信頼性を向上させます。
    • --mca opal_set_max_sys_limits 1: システムの上限(オープン ファイルの最大数など)を許容される最大値に自動的に設定しようとします。
    • --mca plm_rsh_num_concurrent: ワーカー デーモンを起動するときに mpirun が使用する同時 SSH 接続の最大数を設定します。
    • --mca plm_rsh_args ...: 厳密なホストキー チェックをバイパスして、インタラクティブな SSH プロンプトが MPI プロセスの起動をハングアップしないようにします。
    • --prefix ...: Rocky Linux と RHEL の OpenMPI インストール パスを明示的に定義します。これにより、ワーカーノードは必要なデーモン(orted)を見つけることができます。
    • --allow-run-as-root: mpirun が root ユーザーとして実行できるようにします。
    • --oversubscribe: MPI が使用可能な物理コアよりも多くのプロセスをノードにスケジュールできるようにします。
    • --map-by node: 使用可能なノードに MPI プロセスをラウンドロビン方式で均等に分散します。
    • --bind-to socket: MPI プロセスを物理 CPU ソケットにバインドして、メモリアクセスとキャッシュ パフォーマンスを最適化します。
    • --npernode: ノードあたりのプロセス数。
    • --np: 起動する MPI プロセスの合計数。
    • --hostfile: 実行するホストのリストを含むファイルを指定します。

    ior フラグは次のとおりです。

    • -a AIO --posix.odirect: POSIX Direct I/O と組み合わせた非同期 I/O(AIO)エンジンを使用します。これにより、クライアントサイドの RAM ページ キャッシュがバイパスされ、同時実行の非ブロッキング書き込みがストレージ サーバーに直接強制的に行われるため、ベンチマークではメモリ バッファではなく、実際のネットワーク ストレージのパフォーマンスが測定されます。
    • --aio.max-pending=256: プロセスごとに処理中の非同期 I/O オペレーションの最大数を決定します。
    • -C: 読み取りパフォーマンスを最適化するためにタスクの順序を変更します。
    • -F: プロセスごとのファイルモード。
    • -g: バリアを使用して、テストの書き込みフェーズと読み取りフェーズを分離します。
    • -v: 詳細ロギングを出力します。
    • -w / -r: IOR に書き込み(-w)または読み取り(-r)のパフォーマンス テストを実行するよう指示します。
    • -k: IOR が書き込み後にテストファイルを削除しないようにし、読み取りテストで使用できるようにします。
    • -e: 書き込みフェーズの後に fsync を実行して、データがストレージ ドライブに commit されることを保証します。
    • -z: 順次アクセスではなくランダム アクセス I/O を実行するように IOR に指示します。
    • -s 1: セグメントの数を 1 に設定します。
    • -Q 1: ノードあたりのタスク オフセットを設定し、すべてのノードでベンチマーク座標が正しく調整されるようにタスクを調整します。
    • -G 1745405099: 読み取りフェーズで書き込みフェーズで使用されたものとまったく同じランダム ファイル オフセットが生成されるように、ランダム シード タイムスタンプをハードコードします。
    • -t: 各 I/O オペレーションの転送サイズを設定します(例: スループットの場合は 4m、IOPS の場合は 4k)。
    • -b: テストの実行中にペイロード データが不足しないように、プロセスあたりのターゲット ブロックサイズ(スループットの場合は 50t、IOPS の場合は 8g など)を設定します。
    • -D: テストの実行時間を特定の秒数(6045 など)に制限します。この「ストーンウォール」により、ベンチマークが均等に終了し、真の定常状態の測定値が取得されます。
    • -O stoneWallingWearOut=1: すべての同時実行スレッドに、期間全体にわたって継続的な書き込み負荷を生成させ、高速なスレッドが早期に完了してネットワーク全体の負荷が低下するのを防ぎます。
    • -O stoneWallingStatusFile=<path>: 書き込みフェーズの最後に状態検証ファイルを書き込みます。後続の読み取りフェーズでは、このファイルを使用して正常に commit されたブロックのみを読み取り、読み取り中の null ポインタ エラーを防ぎます。
    • -o: Managed Lustre ファイル システム上のテストファイルのパス。

結果を見る

ベンチマークが完了すると、すべてのクライアント VM または Pod の集計パフォーマンス指標がターミナルに直接表示されます。出力の下部にある [結果] テーブルで、最大スループットまたは IOPS を確認します。

主な指標

  • aggregate filesize: テスト中にすべての参加クライアントで書き込まれたデータまたは読み取られたデータの合計量。

  • bw(MiB/s) / Max Write / Max Read: 順次テストで最も重要な指標。これは、Managed Lustre ファイル システムで実現された合計帯域幅を示します。

  • IOPS: ランダム I/O テストで最も重要な指標。これは、1 秒あたりの最大入出力オペレーション数を示しています。

結果をファイルにエクスポートする

結果をプログラムで解析したり、データベースにフィードしたり、後で分析するために保存したりする場合は、画面に表示するだけでなく、JSON 形式と CSV 形式で概要データをエクスポートするように IOR に指示できます。

これを行うには、ior コマンド文字列の末尾に -O フラグを追加します。

-O summaryFormat=JSON \
-O summaryFile=/lustre/test/perf-results/summary.json \
-O saveRankPerformanceDetailsCSV=/lustre/test/perf-results/details.csv

ベンチマークを実行する前に、出力ディレクトリがファイル システムに存在している必要があります。

予測パフォーマンスと実際のパフォーマンス

ファイル システムの数学的な最大スループットは、プロビジョニングされた容量とパフォーマンス ティアに基づいて計算できます。ストレージ容量はギビバイト(GiB)単位でプロビジョニングされ、階層はテビバイト(TiB)単位で評価されるため、まず容量を変換する必要があります。

Capacity GiB / 1024)* Tier MBps = 理論上の最大 MBps

たとえば、500 Mbps / TiB ティアの 216,000 GiB インスタンスは、数学的に 105,469 Mbps のスループットを提供します((216000 / 1024)* 500)。

観測される最大スループットは、ファイル システムのプロビジョニングされたスループット容量とクライアント マシンのネットワーク下り(外向き)上限の合計のいずれか小さい方によって常に制限されます。

ベンチマークの数値が理論上の速度に達しない一般的な理由には、次のようなものがあります。

  • TCP/IP オーバーヘッド: 標準のネットワーク カプセル化とパケット ヘッダーは、生の帯域幅の約 5 ~ 10% を消費します。数学的な最大値にはこのオーバーヘッドが含まれますが、IOR ベンチマークではディスクに書き込まれた未加工のペイロードのみが測定されます。

  • クライアント ネットワークの上限: クライアント マシンには、下り(外向き)帯域幅の厳しい上限が設定されています。少数のクライアントまたはノードを使用する場合、または Tier 1 ネットワーキングが有効になっていないマシンタイプを使用する場合、Managed Lustre ファイル システムが上限に達する前にクライアントがベンチマークをスロットリングします。

  • MPI コンテキスト切り替え: PROCESSES_PER_NODE がクライアント マシンの物理コア数よりも大きい値に設定されている場合、CPU 競合とコンテキスト切り替えのオーバーヘッドにより、ベンチマークの I/O パフォーマンスが人為的に低下します。

  • Direct I/O がない: --posix.odirect フラグが省略されている場合、データはクライアントの RAM ページ キャッシュを通過します。これにより、メモリのボトルネックと CPU オーバーヘッドが発生し、実際のネットワーク ストレージのパフォーマンスが隠蔽されます。

クリーンアップ

このページで使用したリソースについて、 Google Cloud アカウントに課金されないようにするには、次の操作を行います。

  1. マネージド Lustre ボリュームからテストファイルを削除します。

    ssh -i ./id_rsa -o "StrictHostKeyChecking=no" -o UserKnownHostsFile=/dev/null ${SSH_USER}@${HEAD_NODE} "rm -rf /lustre/test"
    
  2. 一括作成された Compute Engine クライアント マシンを削除します。

    gcloud compute instances delete $(gcloud compute instances list \
      --filter="name~'^${CLIENT_PREFIX}-'" --format="value(name)" --zones="ZONE") \
      --zone="ZONE"
    

    または、正確な名前がわかっている場合や、個別に削除する場合は、次の手順を行います。

    gcloud compute instances delete CLIENT_PREFIX-0001 CLIENT_PREFIX-0002 ... --zone=ZONE
    
  3. カスタム イメージを作成した場合は、次の手順で削除できます。

    gcloud compute images delete CUSTOM_IMAGE_NAME
    
  4. このテスト専用に Managed Lustre インスタンスを作成し、不要になった場合は、次の手順で削除します。

    gcloud lustre instances delete INSTANCE_ID --location=LOCATION
    

一般的なベンチマークのボトルネックのトラブルシューティング

ベンチマークの結果が想定されるストレージ パフォーマンス ティアよりも大幅に低い場合は、一般的なボトルネックのトラブルシューティングをご覧ください。