こんにちは。グローバルスタジオ@東京オフィスでサーバーエンジニアをしている有澤です。
私は現在、とあるソーシャルゲームタイトルにサーバーリードという立場で携わっているのですが、個人的には初めて、立ち上げからリリース、運用までの全てのフェーズに通して関わったということもあり、とても学びの多いプロジェクトとなりました。
また、これまでは主にサーバー開発を担当していたのですが、本プロジェクトではAWSによるインフラ構築や運用も行い、そういった面でも初めて経験することが多かったです。
(弊社では、インフラ構築・運用についても基本的にはサーバーエンジニアの業務範囲となります)
そこで今回は、半年前のリリース前後の時期を振り返ってみて、主にインフラ周りで注意が必要だと思った点についてまとめてみました。
※ 本記事内でのAWSに関する内容は、あくまで記事執筆時点(2021年3月)での話であり、その後仕様が変更されている可能性もあるのでご注意下さい。
コスト
AWS Well-Architectedフレームワークの5本の柱の一つに「コスト最適化」の項目があり、コスト管理・削減の重要性が挙げられていますが、個人的にはリリース前の費用見積もりが結構大変だった記憶があります。
従量課金制という仕組みは費用を抑えるという点においてはありがたいものですが、実際に動かしてみないとどれくらいの金額になるのかが見えづらい部分も多く、ある程度の経験が必要だと感じました。
また、年単位でリソースを一括購入することで通常よりも少ないコストで購入できる、リザーブドインスタンス(RI)やSavings Plansといった仕組みがAWSにはあるのですが、適切な権限を持つIAMユーザーであれば数クリックで気軽に購入できてしまう割には、仕組みがやや複雑だったり、手が震えるほどの金額が動いてしまうことから、細心の注意が必要です。
ここでは、私の中で特に印象的だった2つの事柄について取り上げています。
リリース初期はCloudFrontのコストが非常に大きい(こともある)
コストが掛かるAWSサービスは何かと聞かれた際に、皆さんは何を思い浮かべるでしょうか?
私はこれまでの経験上、EC2、RDS、ElastiCacheなどをイメージしていたのですが、本タイトルのリリース初期においてはCloudFrontが支配的でした。
具体的には、1ヶ月後の落ち着いてきたタイミングと比較すると、初日のCloudFront費用は180倍でした。新規インストールやリセマラによるアセットダウンロードの影響ですね。
EC2やRDSなどのサービスと違い、使用量が予測しづらいため、リリース前の費用見積もりが甘くなってしまいがちですが、注意が必要です。
データ配信量の見積もり方法としては、過去のリリース時のデータを元にDAUの比率等で計算したり、(初回アセットダウンロード容量 × 想定DAU × リセマラ係数)のような計算式で導く、といった方法が考えられるかと思います。
ElastiCacheのRIはインスタンスファミリー内のサイズ柔軟性がない
リリース後、しばらくして負荷の傾向が見えてきたらRIの購入を検討されるかと思います。
その際に、EC2やRDSでは、購入したRIのインスタンスタイプが実際に稼働しているものと異なる場合でも、インスタンスファミリーが同じであれば適用される、という「サイズの柔軟性」の仕組みを利用することを前提として検討することが一般的です。
https://aws.amazon.com/jp/premiumsupport/knowledge-center/ri-size-flexibility/
そこで気を付ける必要がある点として、ElastiCacheのリザーブドキャッシュノード(RI)ではこの「サイズの柔軟性」はサポートされておらず、購入したRIのインスタンスタイプと実際に稼働しているものとで完全に一致していないと適用されません。
RI購入後にスケールアップ/ダウンすると適用されなくなってしまいますので、今後負荷の大幅な増減が全く見込まれない場合や、Redisクラスターなどの機能を活用してスケールイン/アウトが可能な場合にのみ、RIを購入することが望ましいでしょう。
Bot対応
リリース直後は想定内の負荷で特に問題なかったのですが、数日後に急にBotによるリセマラが増え出して負荷が上昇するということがありました。多い時ではBotによるアクセスの割合が全体の5割以上を占めることも。。
そこで、Botによる想定外の負荷上昇を防ぐという観点から、考えられる対策を挙げました。
負荷試験のシナリオにBotを想定した項目を含めておく
通常ユーザーのリセマラの一周は、ガチャ結果の確認までなのですが、Botの場合は引継ぎコードの発行まで行っていました。とりあえず大量にアカウントを作っておいて、後からガチャ結果の良いアカウントを選別するスタイルですね。
その違い自体は(負荷的には)大きな問題はないはずなのですが、本タイトルの場合、引継ぎコード発行時に参照されるテーブルで一部indexを貼るのが漏れている箇所があり、その処理が大量に呼ばれたことで、RDSの負荷が上昇してしまいました。
(リード側の負荷上昇だったため、リードレプリカを追加し、後日予定していた定期メンテナンスのタイミングでindex作成を行いました)
この件の教訓として、もし大量のBotが流入した場合でも問題ないよう、負荷試験のシナリオにBotを想定した項目を含めておく必要性を感じました。どのようなシナリオかはタイトルによって異なるかとは思いますが、本タイトルではリセマラを想定したシナリオに引継ぎ処理を追加しておくことで、事前に問題に気付けたかと思います。
アクセス制限の仕組みを事前に整えておく
Botが大量に出現してからアクセス制限の仕組みを整えたのでは、対応が間に合わない可能性があるので、事前にアクセス制限のフローを整えておくのが望ましいです。
本タイトルではAWS WAFを使用しています。この辺りをもう少し細かく設定出来たらな、と感じた部分もありましたが、十分対応可能でかつスムーズに導入できたので良かったです。
話が少し逸れますが、AWS WAFを使用する上で気を付けた方が良さそうな点があったので、記載しておきます。
AWS WAFの設定方法としては、複数のルールを組み合わせたWeb ACLを作成し、ELBなどのリソースへ紐付けて適用する形になるのですが、一つのリソースに複数のWeb ACLを紐付けることは出来ず、既にWeb ACLが紐付けされているリソースに別のWeb ACLを紐付けすると、既存のものが自動で解除されてしまうので注意が必要です。
Web ACLの仕組み的に一つのリソースに複数指定できない仕様なことは理解できるのですが、解除される際にユーザー側にその旨を伝えてくれるとありがたいなと思いました。
ECS/Fargate
以前勤めていた会社での話にはなりますが、オンプレ環境でDockerを使って、個人用の開発環境やGitLabなどのサービスをチーム内で運用していたことがありました。
その際の経験として、唐突にDockerデーモンが落ちてコンテナが全滅することが時々あったため、コンテナに関してはやや不安定なイメージが個人的にはありました。
しかし、本タイトルでECS/Fargate(コンテナ実行・管理サービス)を使用して開発・本番環境を運用してみて、これまで一度もトラブルなどは発生しておらず、むしろEC2などの従来のコンピューティング環境と比べて安定している印象を受けました。また、データプレーンとしてFargateを使用した場合、コンテナより下の部分を意識する必要がないので、色々と楽ですね。
そんなECS/Fargateではありますが、気を付けた方が良さそうな点もいくつかあったので紹介しておきます。
タスク数の上限緩和申請を早めに行っておく
EC2の場合ですと、同一アカウント・リージョン内で起動可能なインスタンス数の上限が存在するかと思いますが、ECS/Fargateにも同様の上限があります。サービスクォータの「Fargate On-Demand resource count」という項目です(オンデマンドの場合)。
https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/service-quotas.html
現在のデフォルトの上限値は500タスクのようですが、2020年9月に引き上げられる前のデフォルト値は100タスクでした。
https://aws.amazon.com/jp/about-aws/whats-new/2020/09/aws-fargate-increases-default-resource-count-service-quotas/
ここで想定外だったこととして、負荷試験の際に想定DAUや本番環境の構成などを整理した上で、こちらの項目の上限緩和申請を行ったのですが、AWSのサポート側とのやり取りなど発生し、実際に上限緩和が適用されるまで一週間程掛かってしまったことがありました。
申請ボタンを押して少し待つと対応済みの連絡が来るケースがほとんどな印象ですが、申請するサービスや項目によっては例外もあるようですね。
この話はあくまで半年ほど前のことなので、今も同様かは分かりませんが、タスク数の上限緩和申請についてはある程度時間が掛かることも想定しておいた方が良さそうです。
参考としてサポート側から受けたヒアリングの内容も載せておきます。
Average expected dimensions of the tasks in terms of vCPU and Memory:
*For example, 70% of the tasks 0.5 vCPU/1 GB and 30% of the tasks 2 vCPU/4 GB*Do you spread across all the AZs in the region?: *[Yes/No]*
If not, which AZs will target: *[Availability Zones]*
**We recommend customers spread across all availability zones in the region for higher availability.
Blue/Greenデプロイを行う場合、サービスクォータのタスク数上限は必要数の2倍にする
タスク数上限に関して、もう一つ注意が必要だと感じたことがありました。
ECSを利用する際には、CodeDeployと連携して、Blue/Greenデプロイメント(現在稼働している環境とは別で新たな環境を作り、向き先を切り替えるデプロイ方法)を行うことが多いかと思いますが、その場合、デプロイ時には2倍の数のタスクが起動することになります。なので、サービスクォータのタスク数上限の項目に関しては、想定している値の2倍(以上)に設定しておくのが良いでしょう。
当たり前のことかもしれませんが、この辺り意外と見落としがちな気がします。
ログ出力を大量に行う場合はawslogsドライバーを使わない
ECS/Fargateの構成でのログ出力方法ですが、現状では、awslogs/splunk/firelens/fluentd の4つのドライバーがサポートされています。
https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/AWS_Fargate.html
その中の一つであるawslogsドライバーは単純にCloudWatch Logsへログを送信するもので、気軽に導入が可能なのですが、本番環境でアクセスログなどを全てCloudWatch Logsへ流してしまうと、かなりコストが掛かります。
料金表を確認すると、収集(データの取り込み)は$0.76/GBなので、1TBだと$760になりますね。本タイトルでは、ECSの半分程のコストが掛かりました。
https://aws.amazon.com/jp/cloudwatch/pricing/
なので、ログ出力が大量に生じることが見込まれる場合は、awslogsドライバーの使用は避けて、firelensなどの別のドライバーの導入を検討した方が良いでしょう。
https://aws.amazon.com/jp/blogs/news/announcing-firelens-a-new-way-to-manage-container-logs/
まとめ
現在携わっているタイトルでのこれまでを振り返ってみて、幸い大きなトラブルはなかったものの、印象に残ることは色々ありましたし、今後も色々あるんだろうなぁと思っています。
つい最近も、AWS障害の影響を受けたのですが、事前に実施した障害試験では想定していなかったような事象(インスタンスが中途半端に死ぬ、操作を受け付けない、など)が次々に発生し、教科書通りには行かないことを痛感したばかりです。
こういったトラブルを反省し、ノウハウを積み上げていくことでサービスの信頼性向上へと活かしていきたいと思います。