背景
チームのシステムではバッチで生成したファイルやバックアップの保存でプライベートサブネットにあるEFSボリュームを利用しています。普段はそこまで大きなアクセスが発生するボリュームではないので、必要な時に最大の性能を出せるバーストモードで設定しています。
今月チームメンバーからなぜかあるEFSボリュームのバーストクレジット徐々に減っていくという連絡を受け、調査と対応をしましたので一連の流れを書いてみます。
起きていた現象
減少量に違いはあるものの、約15分ごとにクレジットが減り回復を続けていることがわかります。また、完全に回復する前にクレジットを消費してしまうので、全体的にバーストクレジットが減り続けているようでした。
この時点で、EFSとS3の間を約15分間隔で同期しているジョブを思い出しました。しかし、そのジョブはほとんどの場合、ファイル転送が発生せずに終了しています。これが原因だと確信できなかったため、より詳しく調べることにしました。
もっと調べてみる
VPC フローログの確認
VPC フローログからどのようなところとやり取りがあったか確認します。当時はS3バケットから生のログをダウンロードしてエクセルで頑張って確認していたのですが、それよりはAthenaを利用した方がSQLを利用してより手軽に確認できるのでおすすめします。
ログの確認結果、特定のIPアドレスから15分おきで普段より大きいデータ量のトラフィックが発生していることを確認しました。
ログから取得したIPアドレスやENI(Elastic Network Interface)のIDを元に、ENIのリストを確認しましたが、該当するリソースは存在していませんでした。しかし、先ほどの疑わしいジョブはECS(Fargate)上で動作しているため、タスクが生成される際にENIが生成され、タスク終了後に削除されている可能性があると考えました。
CloudTrailの確認
ENIのリストからは該当のIPアドレスを確認できなかったため、CloudTrailの記録からIPアドレスをキーワードとして検索します。CloudTrailのログはCloudWatchとS3に保存していますが、今回はCloudWatch Logs Insightsを使用して確認することにします。
以下の記事を参考にして、クエリを書きます。
CreateNetworkInterfaceのイベントの中でENI IDをキーワードに検索するクエリの例
parse @message '"privateIpAddressesSet":{"item":[{"privateIpAddress":"*"' as PrivateIP
| fields
eventTime as Time,
userIdentity.accountId as AccountID,
userIdentity.principalId as Principal,
awsRegion as Region,
eventName as Action,
responseElements.networkInterface.networkInterfaceId as ENI
| filter
eventName = "CreateNetworkInterface" and
(
ENI = "ENIのID"
)
| sort @timestamp desc
検索してヒットした結果を見ると、ロググループ名に疑わしいジョブ名が書かれており、IPアドレスもフローログでみたIPアドレスと一致してました。
これで、バーストクレジットが減る原因は15分おきで実行しているジョブであるかことが確定しました。
ファイル転送がない同期だけでもクレジットは消費されてしまうのか
原因と特性されたジョブは
- EFSボリュームをマウントする
- S3 Syncコマンドよりバケットと同期する
という動作をする単純なジョブです。
ファイル転送が行われていない状態でバーストクレジットが減少することに疑問を感じ、個別にジョブを実行してみましたが、やはりクレジットは減少しました。
さらに、EC2インスタンスにEFSボリュームをマウントし、フォルダー間を同期するrsyncコマンドを使用しました。ファイルに差分がない状態で実行しましたが、同様にクレジットが減少することを確認しました。
ネットでいろいろ調べてみると、
同期(rsyncやs3sync)の過程で、比較するファイルが同一であることを確認するために、ファイルの容量やタイムスタンプなどの情報をチェックします。その過程で、各ファイルのメタデータ(ファイルあたり約2KiB)を読み込む必要があります。今回は、1つ1つのファイルの容量は小さいものの、ファイル数が多いため、結果的にバーストクレジットの消費が増えてしまったと推測しています。
また、EFSのバーストモードでは、標準(スタンダード)クラスの容量に応じて、バーストクレジットを消費せずに利用できるベースラインスループットが決まります。しかし、今回の大半のファイルがIA(Infrequent Access)クラスであったため、ベースラインスループットが低く、クレジットをより多く消費する原因になったと考えています。
対応
バーストが必要な時にバーストクレジットが減ること自体は問題ないです。しかし、今回はクレジットが完全に回復されずに全体的にクレジットが減っています。このままだといつかクレジットが0になり、必要な時にバーストできなくなるので、なんだかの対応をする必要がある思いました。
ネットなどを調べ、以下の対応方法を考えました。
- ベースラインスループットを上げる
- 標準(スタンダード)クラスのファイル容量を増やし、ベースラインスループットを上げます
- スループットモードの変更
- バーストクレジットを使わない他モードに変更します
- EFSのスループットモードについて
- ジョブ実行間隔を長くする
- ジョブでクレジットを消費して元のクレジット量に戻ってない状態でまたクレジットが消費してしまうことなので、クレジットが完全に回復する時間間隔でジョブ実行間隔を延ばす
今回は、1の方法を採用しました。「スループットモードの変更」方法については、今回のリソースで選択できるのがプロビジョンドモード(Provisioned)のみで、通常はスループットを確保する必要がなく、バーストモードよりも料金が増加してしまう点から見送りました。
また、「ジョブ実行間隔を長くする」方法については、ジョブがS3のレプリケーションからDR環境がある大阪にデータを同期しているため、間隔を長くすると目標復旧地点(RPO)に影響を与えるという理由で見送りました。
「ベースラインスループットの上げる」方法で対応するにあたって、現在ボリュームのファイルクラス状況を確認します。ほとんどがIAクラスでした。
標準クラスのファイルの容量が多ければ多いほど、ベースラインスループットがあがる方式であるので、よく大きいの空ファイルを生成しておく方法が用いられます。ただし、今回はボリュームの状況をIAクラスを標準クラスに戻すだけでスループットが上がりそうだったので、まずは標準クラスに戻す方法を試してみようと思います。
IAクラスのファイルを標準に戻すためには(メタデータではない)ファイルの実際データに1回アクセスする必要があります。
上記のポストではcpコマンドでファイルをコピーする方法が書かれていますが、作業端末のディスク容量が小さいこともあり、フォルダー配下のファイルを一回catすることでファイルへアクセスすることにしました。
sudo find ./フォルダ名/ -type f -exec cat {} > /dev/null \;
また、EFSボリュームのオプションより、またIAに移行されることを防ぐために古いファイルでもIA移行はなし、IAやアーカイブファイルに1回アクセスしたら標準クラスへファイルを戻す設定をしています。
上記の対応を実施した結果、バーストクレジットがたまり続けていることを確認しています。
おわりに
今回、EFSのバーストクレジットが減り続ける現象について、VPCフローログやCloudWatch Logs Insightsを活用して原因を特定し、ベースラインスループットを上げることでクレジットの減少を止めることができました。
システムへの影響は少なく、対応も非常に簡単でしたが、さまざまなAWSのサービスを使いながら原因を特定し、対応方法を考える中で、AWSに関する知識を深めることができたと思います。また、「AWSエンジニアとして活躍している!」という実感を強く感じ、とても楽しく充実した経験でした。