塵も積もれば……

しくじり3つ目に行く前にちょっと休憩を挟みまして、猫ちゃんの画像で癒されつつ……。ちょっと軽いネタを入れていこうかなと思います。

170万円とまではいかなくても「なんか請求高くない?」ということがあったかなと思います。請求でけっこう高い割合を占めるのは、やっぱりサーバ。EC2の起動している時間の料金ですね。なので節約のために使わないEC2を止めるということをされている方はけっこう多いかなと思っています。

とは言えEC2を停止しているから課金がゼロになるかというとそうでもなくて、EC2で使っているEBSは課金されちゃいますし、停止したインスタンスに関連づくElastic IPもごくわずかながら課金されちゃいます。

例えばEC2を止めていると言っても使っていないEC2がめちゃくちゃ数があって、それによってEBSの合計のボリュームがすごく多くなってしまったりすると、これもちりつもで、結局EBSの料金がめちゃくちゃ高くなるということがあるかなと思います。

止めているんじゃなくて、使わなくなったAMIは消しているのに「なんか高いな」みたいな話があるかなと思います。AMIを消してもEBSのスナップショットは残っちゃいます。スナップショットを消さないと、これもちりつもになって気付いたらスナップショットがめちゃくちゃ溜まっていて、それでお金がかかっていたという話もあるかなと思います。

EBSに関連してということは、RDS系も何か残っているんじゃないかという話なんですけれども、RDSでいくと、手動のスナップショットは自動で削除されなかったりするので、ここもちりつもかなと思います。

ということでちょっと番外編なんですけれども、「EBS 塵も積もれば山となる」ということで、使っていないEBSとかも定期的に整備していければ、ちょっとはコストカットになるのかなと思います。

しくじり3:Lambda突然の死

ではしくじりの3つ目に行こうかなと思います。しくじり3つ目は「Lambda突然の死」というタイトルです。これも詳しく見ていきます。

S3にアップロードしたzipファイルをLambdaで展開して、その展開したファイルを別のS3に保管するというような要件があって、それどおりにアーキテクチャを設計して実装しました。これも最初は景気よく動いていたんですが、あるタイミングでLambdaでエラーが頻発するようになりました。

まずはCloud Watch Logsを見てみると、「No space left on device.」というエラーが出ていました。No space leftということは、「Lambdaが使っているボリュームに容量がもうないよ」ということです。Lambdaのディスク容量ってなんだ? という話ですが、Lambdaは一時的なファイル置き場として/tmpというところが利用可能になっています。

利用用途としては、今回みたいにzipファイルを展開して一時的にファイルを置きたいときに使うかなと思います。この/tmpというディレクトリは容量が512メガバイトしか使えないので、512メガバイト以上のファイルを置こうとすると今回のようにエラーになります。

今回のアーキテクチャ上は、まずS3にzipファイルを置いて、そこからイベントが発行されてLambdaが起動してzipファイルを展開してという流れになっているのですが、その各zipファイルで展開されたファイルというのは512メガバイト以内だったにもかかわらずディスクが枯渇してしまったと。

なんで枯渇してしまったのかという話なんですが、Lambdaの実行環境というのはとてもよく再利用されるというのはドキュメントにも書かれています。これは最後の1文なんですけれども、「Lambda関数を連続して呼び出す場合、AWS Lambdaはできる限り実行コンテキストを再利用します」。

ということで、今回Lambdaが再利用されるということは頭になくて、解凍したファイルをいちいち消していなかったというのが原因になります。zipファイルで展開したファイルを/tmpに置いて、そのままにしていたんですね。Lambdaの実行環境は使い回されちゃうので、どんどんファイルが蓄積されていって、最終的に512メガバイトを超えてしまったというのが今回の原因です。

Lambdaでは不要なファイルを削除する

対策としてはシンプルで、ファイルを消すようにすればいいだけでした。/tmpの配下に一時ディレクトリを作成してそこに展開し、関数が終了するときにディレクトリごと削除するように変更しました。

ということで教訓3つ目は「Lambdaは使い切りではないので、設計とか実装とかをするときは、その点を気をつけていきましょう」というような話ですね。ということでしくじり3つ目は「Lambdaが突然死した」という話でした。

しくじり4:思わぬリソースが枯渇

では最後のしくじりに行こうかなと思います。最後は「思わぬリソースが枯渇」というしくじりです。

今回の構成図はこんな感じで、よくあるWebサイトになっています。ELBがあってEC2が冗長化されていて、EFSでEC2間のファイル共有をしている。データベースはRDSでほとんど冗長化されていますよというような、すごくよくある一般的なWebサイトの構成です。

サイトがつながらない

ある日「サイトがつながらない、遅い」となりました。まず初動確認します。まず一番大事なEC2はちゃんと動いていました。じゃあ今度はEC2の中身ですね。CPU、メモリ、プロセス……。大丈夫でした。次はDBがボトルネックになっているか。コネクションとかも見たんですがDBがボトルネックになっているわけでもなさそうでした。

じゃあ何が原因なんだと思っていろいろCloud Watch Logsなどを見ていると、何かがめちゃくちゃ減っている。よく見てみるとEFSのバーストクレジットを使い切っているということがわかりました。

EFSのバーストクレジットが足りない

EFSのバーストクレジットとは何かという話なんですけれども、EFSのRead/Writeの性能というのはEFSで実際に使っている容量に依存しています。

1ギガバイトあたり50キビバイト/秒なので、1ギガバイトしか使っていなかったら50キビバイト/秒の性能しか出ないというような仕様です。この基本性能より多くの高い性能のパフォーマンスを求められる場合は、バーストクレジットというものを一時的に使ってRead/Writeの性能を引き上げるというような構造になっています。

このクレジットは貯金みたいなものを使うんですけれども、先ほど説明した1ギガバイトあたり50キビバイト/秒の基本性能より下回る期間にクレジットがどんどん回復して、逆にその基本性能を超えるパフォーマンスが必要な時はバーストクレジットを消費するというかたちです。この貯金を使い切ってしまうと基本性能しか出せなくなります。

今回サイトがダウンしたのは、基本性能、要はサイトの閲覧にそもそも耐えられなかったというのが原因になります。EFSで使っていた容量が数ギガバイトというレベルだったので、基本性能が200とか300キビバイト/秒しかなかったと。これって画像とかを読み込んだりするとすぐに超えてしまってバーストクレジット頼みになってしまいます。

結局基本性能以上のパフォーマンスをずっと求められ続けていたということで、クレジットがリリース直後からどんどん消費されていって、かつクレジットを回復する余地もなくじわじわとクレジットを消費し続けていって最終的にクレジットがなくなってパフォーマンスが出せなくなったということが原因でした。

今回EFSを使っていたんですが、こんな少ない容量だとは思わなかった、そもそも監視ができていなかったというのもあり、そこら辺はちょっと反省点かなと思っています。

プロビジョンドスループットモードで解決する

対策としては、プロビジョンドスループットモードというものに変更しています。これはあらかじめどれぐらいのパフォーマンスが必要なのかというのをこちらで指定できるモードです。なのでこのモードではそもそもクレジットという概念がないので、クレジットが枯渇するということも気にせず使うことができます。ただ先ほどのバーストのモードよりはお金がちょっと高いよというモードになっています。

クレジットに気をつける

ということで教訓4つ目としては「クレジットには気をつけろ」という話ですね。とくにバーストクレジットというものを使うようなサービスについてはクレジットが枯渇していないかどうか、枯渇しそうかどうかという辺りに気をつけてもらえればなと思います。

その他バーストクレジットがあるサービスはいくつかあります。有名なのはEC2のCPU、T2とかT3系のCPUですね。ここも同じく基本性能というのが決められていて、基本性能を超えるようなCPUのパワーが必要なときはクレジットを使って一時的にCPUのパフォーマンスを90パーとか100パーとかが出せる、基本性能以下のCPUのときにクレジットが回復する。クレジットを使い切ってしまうと基本性能しか出ないのでCPUのパワーが出せなくなって大変なことになるので、本番のところで使うときは気をつけましょうというのはよく言われている話かなと思います。

EBSについても同じです。今回EFSでしくじりが発生したんですけれども、EBSでも同じようにバーストクレジットがあるので、こちらもバーストクレジットを使い切ってしまうとEC2とかRDSとかからのアクセスがすごく遅くなってサービスに影響が出てしまう可能性があります。特にRDSもEBSを使っているという点には注意が必要かなと思っています。RDSで容量を少なめに設定して作る場合に、こんな注意書きが出てくるんですね。

「100キビバイト未満の汎用ストレージを、高スループットワークロード用にプロビジョニングした場合、初期の汎用IOクレジットバランスを使い切った時点で、レイテンシーが大きくなる場合があります」

ということで、今お話した内容の通り、少ない容量だと基本性能は出ないので、少ない容量なのにRead/Writeがすごく発生するような環境で使ってしまうと、バーストクレジットを使い切ってパフォーマンスが出なくなるよということですね。

しくじりのまとめ

ということでしくじりをまとめていきます。

しくじり1つ目は「Athenaで170万円の請求がきた」。しくじり2つ目は「EC2が復旧できない/できたのにヘン」。しくじり3つ目は「Lambdaの容量を使い切って突然死ぬ」。しくじり4つ目は「ECSのバーストクレジットを使い切ってダウンする」というようなしくじりでした。

これらについてそれぞれの教訓は、「アンチパターン、ダメ、ゼッタイ」ということで、アンチパターンは止めましょう。教訓2は「それ、ちゃんと復旧できる?」ということで、AMIから復旧テストができればしたほうがいいです。教訓3つ目は「Lambdaは使い切り、でもない」ということで、Lambdaが使いまわされることを前提として設計しましょう。教訓4は「クレジットには気をつけろ」ということで、バーストクレジットには注意が必要です。

ということで、もし少しでも気になったところがありましたら、ぜひご自身のAWS環境を確認してもらえればいいかなと思います。

最後に宣伝です。弊社cloudpackはAWSに限らずいろいろなクラウドをやっていますので、かついろいろな職種で人を募集していますので、クラウドとイチャイチャしたい人はぜひホームページなどからご応募ください。

発表としては以上になります。ご清聴ありがとうございました。