この記事は Akatsuki Games Advent Calendar 2023 の2日目の記事です。昨日は @tkmruさんの「CODE BLUE参加記:食べて Decompile 寝て 繰り返す」でした。コロナで減ってしまったリアルイベントにも活気が戻ってきて良いですね!
はじめに
アカツキゲームスでサーバエンジニアをやっています柴原です。今回は自分の担当しているモバイルゲームのプロジェクトでは、ECS on EC2の環境で運用をしており、Graviton搭載のEC2に移行を行いました。 詳しい手順の紹介というよりは、その思考の過程や工夫を紹介できたらと思います。
経緯
2018年にAWSはArmアーキテクチャのプロセッサGravitonを独自開発したことを発表し、サービス提供を開始しました。 特徴としては、x86ではなくArmベースのアーキテクチャである点とIntelのプロセッサを搭載した従来インスタンスに比べコストパフォーマンスが優れている点が挙げられます。 以下に4xlargeまでのC5(第5世代intel搭載)、C6i(第6世代intel搭載)、C6g(初登場第6世代Graviton搭載)、C7g(最新の第7世代Graviton搭載)のリザーブドインスタンスの価格をまとめた表を示します。 このように前世代と同世代のintel搭載のEC2と比較してもGraviton搭載のEC2は安いことが分かります。
インスタンスタイプ | C5 | C6i | C6g | C7g |
---|---|---|---|---|
large | USD 551 | USD 577 | USD 411 | USD 490 |
xlarge | USD 1,102 | USD 1,154 | USD 882 | USD 981 |
2xlarge | USD 2,205 | USD 2,308 | USD 1,764 | USD 1,962 |
4xlarge | USD 4,409 | USD 4,615 | USD 3,527 | USD 3,923 |
ap-northeast-1のリージョンで1年分全額前払いのLinuxの価格
また、AWS re:invent 2021の「Deep dive into AWS Graviton3 and Amazon EC2 C7g instances」にて、ベンチマークにおいてIntel搭載のEC2と比較して性能は向上していることも挙げられており、コスト面以外にも恩恵を受けられる可能性があります。 コスト面、性能面から見て利点がありそうということで、私のプロジェクトではGraviton移行に取り組み始めました。
移行する時の問題点
Gravitonに移行するにあたって考えなければいけない点として次の観点が挙がりました。
- キャパシティ
- ビルド
- Arm未対応ミドルウェアの対応
このブログではキャパシティとビルドについてのみ言及します。
キャパシティ
運用型ゲームの性質上、イベントなどでアクセスが局所的に集中する傾向にあります。 AWSではAutoScalingGroupという機能によってEC2の台数を簡単に増減させることが可能です。 EC2を使っているような構成のインフラでは、アクセスの集中に合わせてスケールアウトすることで局所的なアクセスに対応することができます。 しかし、局所的にアクセスが集中する時では一度にたくさんのインスタンスを起動することがあったり、他のAWS利用者がたまたま多く同じタイプのインスタンスを使用している場合にAWS側のリソースが枯渇することがあります。 仮にコンピューティング最適化のインスタンスを使うと仮定すると、以下のタイプが存在します。
- Graviton: C6g、C7g
- Intel: C4、C5、C5a、C6i、C6a
タイプとしての種類が少ないだけでなく、昔から用意されてきたIntel系に比べるとGraviton搭載のEC2が多くないことは推測できます。 先ほどの例で言うとGraviton だけの運用をした場合、C6gとC7gのリソースを使い切ってしまうと、EC2はスケールアウトすることができなくなり、サーバの負荷が高まることが懸念されます。 ゲームに限らず言えることですが、意図しないサービスが継続できない状態は良くありません。
そこで私のプロジェクトでは、x86アーキテクチャ(Intel プロセッサ)とArmアーキテクチャ(Graviton)の両方で動作させるという方針にしました。 Gravitonだけの運用に比べて冗長性があり、リソースの枯渇に対しての対策としては十分な効果が期待できます。
ビルド
x86のみのシングルアーキテクチャの場合と異なり、マルチアーキテクチャではビルドがどうしても複雑になります。
マルチアーキテクチャビルドの問題点
よく利用されるマルチアーキテクチャの方法には以下の2つがあるようです。
CodeBuildは、コードをビルドし単体テスト実行して、イメージを作ることができるサービスです。 ビルドを実行する環境として、x86やArmを選ぶことができます。 両方のアーキテクチャでビルドを実行させることで、それぞれのアーキテクチャに対応したイメージを作成できます。 CodeBuildでのビルドを試したところ、ビルド環境の起動までの時間が長くなるケースがありました。(※2023/12月現在では、CodeBuildがLamdbaをサポートしたので起動速度について改善する可能性があります。) 開発環境のデプロイ時に毎回イメージのビルドを行っていたため、これは開発のペースが悪化する懸念がありました。 一方、buildxはdockerコマンドを拡張するCLIプラグインで、自身のマシンのアーキテクチャとは異なるものを選択してビルドを実行することできます。 buildxはqemuを用いたエミュレーションを行うため、速度低下がありますし、使用する言語・VMによってはエラーの原因になることもあります。 実際、コンテナ内に含まれていたRuby Gemのネイティブバイナリのコンパイルが非常に遅くなるケースもありました。 ここで一度立ち返ってみると、問題点は以下に集約されます。
- ビルド速度低下によるデプロイ自体の速度の低下
- buildxを採用する場合のqemuのエミュレーションの懸念
ビルドの速度低下については、単一のアーキテクチャでなくなった以上ある程度は仕方ない部分はあります。 しかし、これを最小限にしつつも速いビルドを実現し、エミュレーションであることを気にしたくはないです。 そこで、次の方針を立てました。
ビルドの工夫
デプロイは、コードを変更した時やライブラリの更新をした時などに行います。 一般的に、ライブラリの更新以上にコードの更新の方が多いです。 つまり、コードの更新の時だけでも速くなればストレスは少ないということが言えます。 そこで、イメージを分割することを考えました。 以下の図に示すように、Gem等ネイティブバイナリ部分を含むベースイメージとそのベースイメージにコードをコピーしただけのコードイメージに分けるという方法です。
ベースイメージにはネイティブイメージが含まれエミュレーションを気にしたくないため、CodeBuildを用いて必要な時(ライブラリ更新やセキュリティパッチの適用)にのみビルドさせます。 そして、そのベースイメージに対してコードのコピーや環境変数の設定のみの作業をdocker buildxに実行させます。 こうすることでコード更新によるデプロイの速度の低下を最小限にしつつ、エミュレーションを気にしないで済みます。
まとめ
このような問題点を考慮しつつビルド方針を定め、私のプロジェクトではGravitonへの移行に成功しました。 年間でかかるインフラ費用を抑えつつ、スケールアウト時の冗長性を高めることができました。 また、既存デプロイへの組み込みを無事終了し、この体制で運用をしています。 インフラにかかる費用を抑える工夫は、常に考え今後も実施していきたいですね。 AWS re:Invent 2023では、CEOのKeynote セッションにてGraviton4搭載のR8gが発表されました! 更なる高速化が期待できるので、東京リージョンに来るのが楽しみですね! 皆様も良きGravitonライフを送ってください。
明日は、Jingyuan Zhaoさんの記事となります。お楽しみに!