【GCP】Cloud Storage FUSE と Filestore の ls コマンド速度比較
はじめに
Cloud Storage は、非構造化データを保存するためのマネージドサービスです。データを格納するだけでなく、静的ウェブサイトのホスティングや Cloud Run でのボリュームマウントなど利用範囲が拡大しています。
Cloud Storage FUSE は Cloud Storage バケットをローカルファイルシステムとしてマウントしてアクセスできるようにするアダプタですが、制限事項がありローカルディスクのファイルシステムと同様に使おうとしても遅いなどと言われています。そのため、パフォーマンスなどを気にする場合は、Filestore を使用するように公式ガイドでもアナウンスされています。
Filestore は高パフォーマンスでフルマネージドのファイル ストレージで、特に負荷の高いアプリケーションのニーズに対応しています。
今回は Cloud Storage FUSE が Filestore と比べてどの程度遅いものなのか検証したいと思います。
概要
Cloud Storage FUSE の読み書きのベンチマークはコチラに記載があります。
GCP公式ガイドによると Cloud Storage FUSE における ls コマンドの応答速度は、ディレクトリのオブジェクト数に影響されるそうです。そのため今回はオブジェクト数が異なるディレクトリを用意し、 ls コマンドの速度を検証してみようと思います。
検証環境
- Cloud Storage は Dual-region のバケットを asia(東京と大阪) リージョンで作成
- Filestore はインスタンスをゾーンで asia-northeast1-a に作成
- プロトコル:NFSv3
- パフォーマンスの見積
- 読み取り IOPS:9200
- 書き込み IOPS:2600
- 読み取りスループット(MiB/s):260
- 書き込みスループット(MiB/s):88
- Cloud Storage FUSE はデフォルト設定
- 検証用インスタンスを n2-standard-2 で asia-northeast1-b に作成
インスタンスに以下の Dockerfile を使用してコンテナを作成
# gcsfuse ビルドイメージ
FROM golang:alpine3.19 AS builder
RUN apk add --no-cache git
RUN go install github.com/googlecloudplatform/gcsfuse@master
# 基本イメージ
FROM alpine:3.19 AS app_base
# Setup fuse
RUN apk --no-cache --update \
add bash \
tini \
nfs-utils \
fuse
# ビルダーステージからgcsfuseバイナリをコピー
COPY --from=builder /go/bin/gcsfuse /usr/local/bin/gcsfuse
ENV TZ="${TZ:-Asia/Tokyo}"
USER root
# マウントポイント作成
ENV BUCKET_NAME=ex-hosting3
RUN mkdir -p /mnt/gcs
# RUN gcsfuse $BUCKET_NAME /mnt/gcs
# NFSマウント
ENV NFS_HOST=test01
RUN mkdir -p /mnt/test
# RUN mount -t nfs -o vers=3 -o nolock $NFS_HOST:/vol1 /mnt/test
ENTRYPOINT ["/bin/sh", "-c", "while true; do sleep 10; done"]
検証用インスタンスにて以下のコマンドを実行
gcsfuse $BUCKET_NAME /mnt/gcs
mount -t nfs -o vers=3 -o nolock $NFS_HOST:/vol1 /mnt/test
検証用に以下のスクリプトを作成
#!/bin/bash
### 対象ディレクトリ の ls コマンド を繰り返し回数実行します
### ex: ./single.sh <対象ディレクトリ> <繰り返し回数>
start_time=`date +%s.%3N`
### 計測したい処理・コマンド ###
for i in `seq $2`
do
ls -al $1 &>/dev/null
done
end_time=`date +%s.%3N`
run_time=$(echo "scale=3; $end_time - $start_time" | bc)
echo $run_time
#!/bin/bash
### 対象ディレクトリ の ls コマンド をプロセス数同時実行します
### ex: ./xargs.sh <対象ディレクトリ> <プロセス数>
_DIR=$1
export _DIR
function f { echo $*; ls -al $_DIR &>/dev/null; }
export -f f
start_time=`date +%s.%3N`
### 計測したい処理・コマンド ###
seq 1 $2 | xargs -I % -P $2 bash -c 'f %'
end_time=`date +%s.%3N`
run_time=$(echo "scale=3; $end_time - $start_time" | bc)
echo $run_time
ディレクトリ構成とファイルは以下のように準備
/mnt/test
| |
| |-object_1000
| ├── test_1.file
| ├── test_xxx.file
| ├── test_1000.file
| |-object_3000
| ├── test_1.file
| ├── test_xxx.file
| ├── test_3000.file
| |-object_5000
| |-object_7500
| |-object_10000
| |-object_15000
| ├── test_1.file
| ├── test_xxx.file
| ├── test_15000.file
検証方法
検証方法は以下の通りです。
- Cloud Storage FUSE と Filestore のマウント先へ向けて、以下のスクリプトを実行する。
-
single.sh
: 対象ディレクトリ の ls コマンド を繰り返し回数実行します。 -
xargs.sh
: 対象ディレクトリ の ls コマンド をプロセス数同時実行します。
-
- 実行結果を比較する。
結果比較
結果は以下の通りとなりました。実行1回または1プロセス(PS)あたりの時間が5秒(s)を超えたところはその後の計測を停止しています。
single.sh の結果比較
1回ずつ順番に処理した場合の結果。
Cloud Storage FUSE ではオブジェクト数を増やすとその分1回あたりの処理時間は増えておりますが、処理回数を増やしても1回あたりの処理時間はほとんど変わっていません。
xargs.sh の結果比較
同時に処理を実行した場合の結果。
Cloud Storage FUSE では、対象ディレクトリにオブジェクト数が10000ある場合に1500プロセス同時に処理したとき、制限がかかったのか時間が大きく変化しています。
Filestore は良いパフォーマンスです。500PS 位の実行までは一気に処理してくれましたし、500PS 以降遅れは出たものの終了時間は圧倒的に早いです。
さいごに
今回はオブジェクト数が異なるディレクトリを用意し、 ls コマンドの速度を検証してみました。Cloud Storage は list 取得が苦手とはいえ、終了時間にかなりの差が出ました。
思ったよりも同時実行の処理をしても耐えられていましたが、公式のガイドでも考慮事項として記載がある通り、Cloud Storage をローカルファイルシステムのように扱うのは用途を考える必要がありそうですね。
また、比較対象として Filestore を使用しました。パフォーマンスは良かったのですが、それなりに費用がかかりますのでコストを重視するなら自前で NFS サーバーを用意するなど別の方法となるかと思います。
Cloud Storage FUSE はデフォルト設定で検証しましたが、キャッシュなどのオプションでパフォーマンスが向上するかもしれません。今後、もう少し深堀して検証してみたいと思います。
参考
Discussion