AWS
S3
s3fs
goofys
storagegateway

S3をEC2インスタンスにマウントして使うときのStorageGateway, s3fs, goofysそれぞれのパフォーマンス


背景

オンプレミスで運用している自社システムをAWSに移行する場合に、CSVファイルとしてディスクにためているデータをどうするか。現状は複数あるサーバー間でrsyncを定期的に実行して同期を取っているが、AWS移行後は共通のファイルシステムをマウントして使うことで、同期自体が必要ない運用にしたい。

共通のEFSストレージを複数インスタンスでマウントして共有するという手もあるが、EFSはEBSのようにスナップショットを取ることができない。ということはファイルのバックアップは自前で仕組みを用意する必要がある。しかしできるだけAWSマネージドな仕組みを使うことで運用の手間を減らしたい。


選択肢

選択肢としては


  • AWS Storage Gatewayのファイルゲートウェイをセットアップし、NFSを通してEC2にマウントして使用する。

  • s3fsでファイルシステムにS3バケットを直接マウント。

  • goofysでファイルシステムにS3バケットを直接マウント。

がある。図にするとこんな感じ

ファイル保存.png

goofys_s3fs.png

storagegateway.png

いずれの方法も、S3をファイルシステムとしてマウントするため、プログラム側の変更が必要ない。

Storage GatewayがファイルゲートウェイとなるインスタンスをセットアップしてNFS等で他のインスタンスでマウントするなどの方法を取る必要があるのに対して、s3fsやgoofysは各サーバーが直接S3をマウントできる。

Storage Gatewayは構築がめんどくさそうなので、とりあえず簡単そうなs3fsとgoofysでやってみて、最後にStorage Gatewayもやってみる。


IAMロールの作成

EC2からS3にアクセスするために、S3FullAccess権限を付与した S3FsRole というロールを作成して、テスト用のEC2インスタンスを作る際に作成したロールを指定する。


s3fsのセットアップ

$ sudo apt-get install make automake autoconf git libfuse-dev libfuse2 

$ sudo apt-get install libcurl4 libcurl4-openssl-dev
$ sudo apt-get install libxml2 libxml2-dev libssl-dev libssl1.1
$ git clone https://github.com/s3fs-fuse/s3fs-fuse.git
$ cd s3fs-fuse
$ ./autogen.sh
$ ./configure
$ make
$ sudo make install

マウントポイントを作る。

$ sudo mkdir /usr/local/var/s3fs

$ sudo chown ubuntu:ubuntu /usr/local/var/s3fs

/etc/s3fs.conf を編集してマウントしたs3バケットをだれでも使えるようにする。


/etc/s3fs.conf

# Allow non-root users to specify the allow_other or allow_root mount options.

user_allow_other

マウントを実行( uid=1000,gid=1000 はubuntuユーザーのuid,gid)

$ sudo /usr/local/bin/s3fs <buckdet名> /usr/local/var/s3fs -o use_path_request_style,rw,allow_other,use_cache=/tmp,uid=1000,gid=1000,iam_role=S3FsRole


goofysのセットアップ

$ sudo apt-get install golang git

$ export GOPATH=/usr/local/go
$ chown ubuntu:ubuntu $GOPATH
$ go get github.com/kahing/goofys
$ go install github.com/kahing/goofys

マウントする

$ sudo mkdir /usr/local/var/s3

$ sudo chown ubuntu:ubuntu /usr/local/var/s3
$ /usr/local/go/bin/goofys --use-content-type <buket名> /usr/local/var/s3

ちなみに起動時にマウントするには /etc/fstab

/usr/local/go/bin/goofys#<bucket名> /usr/local/var/s3 fuse _netdev,allow_other,--use-content-type,--file-mode=0666,--uid=1000,--gid=1000 0 0


パフォーマンス測定

インスタンスに Ruby 2.5.1をインストールして以下のようなコードで測定する。


file_s3_test.rb

time = Time.now

1000.times do |v|
File.open("#{v}", "w") {|f| f.write "hello world #{v}" }
end

1000.times do |v|
File.unlink("#{v}")
end

puts
passed = Time.now - time
puts "#{passed} sec passed."



EBSでの計測

比較対象として、EBS上で実行してみよう。

$ mkdir ~/tmp

$ cd ~/tmp
$ ruby ~/file_s3_test.rb

0.055169964 sec passed.

はやい


s3fsでマウントしたS3に対して実行

$ mkdir -f /usr/local/var/s3/ruby_test

$ cd /usr/local/var/s3/ruby_test
$ ruby ~/file_s3_test.rb

167.091888939 sec passed.

当たり前だけどEBSよりはるかに遅い。


goofysでマウントしたS3に対して実行

$ mkdir -f /usr/local/var/s3/ruby_test

$ cd /usr/local/var/s3/ruby_test
$ ruby ~/file_s3_test.rb

67.559308286 sec passed.

EBSよりはるかに遅いのは同じだけど、s3fsより2.5倍ぐらい速い。


Storage Gatewayのセットアップ

ここに書いてある通りに作業してStorage Gatewayを準備する。

http://blog.serverworks.co.jp/tech/2017/03/01/filegateway/

S3バケットを別途作ってNFSとしてマウント

$ sudo apt-get install nfs-common

$ mkdir gatewayfs
$ sudo mount -t nfs -o nolock,hard 172.31.53.xxx:/<bucket名> gatewayfs


Storage Gateway + NFSでマウントしたS3に対して実行

では先ほどのスクリプトを使って試してみる。

$ cd gatewayfs

$ ruby ~/file_s3_test.rb

53.024792688 sec passed.

おお、これが一番速いようです。ただ、goofysとの差はそこまで大きくはないみたい。


まとめ

まず最初に、どの方法を使っても速度面でEBSには遠く及びません。したがって多数のファイルを横断的に処理するようなことには全く向いていないと思います。

ただ、性能面でこれで問題ないのであれば、既存のアプリのファイルアクセスをコード変更なしにS3に移行できるという点で魅力的です。S3をマウントしてファイルシステムとして保存、読み取りする方法であればプログラム変更が必要ない上にS3の機能である、AZ3箇所への冗長化や、別リージョンへのレプリケーションなどS3の機能を活用してデータの耐障害性を高めることができる上にコスト面でもEBSに保存するより有利です。

その上で性能面で比較すると一番よさそうなのはStoraga Gatewayみたいです。ただ、これ多分ゲートウェイの機能を提供するインスタンスがSPOFになる気がします。

あと、コスト面でもあまりいいとは言えないと思います。s3fsやgoofysを使う場合はEC2上に直接マウントできるのに対して、ゲートウェイ用にxlarge以上のインスタンスを常時起動しておく必要があるので、その分コストがかかります。

s3fsはこれらの問題がありませんが、StorageGatewayやgoofysに比べるとかなり遅いです。あと、正しくマウントしないと、マウントしても書き込めないなどのちょっとハマりました。

個人的に一番よい印象を受けたのはgoofysです。まずセットアップが一番簡単でした。このあたりはgolangの恩恵かもしれません。依存関係とか気にせず、go getgo install でインストールできました。あとマウントも特にハマるところもなく、すぐにファイルの書き込みや読み込みが行えましたし速度もStorageGatewayには及ばないまでも近い性能が出ています。ネットで色々見ていると不安定だという情報もありましたが、いずれも古い情報だったので現状どうなのかはもう少し試してみないとわからないです。

そんなわけで、今後はgoofysに的を絞って、もうちょっと詳しく調べてみようと思います。