AWSでゲームサーバーを最大90%安く利用する方法

吉田英世氏:みなさん、こんばんは。私はAmazonのソリューションアーキテクトという部署にいまして、ゲームのお客様を主に担当している技術者です。AWS上でどういうサービスを使ってどういうゲームを作るか、みなさんいろいろな課題をお持ちですが、そちらを技術的なところでご支援させていただくポジションです。

今回お話しするのは「AWSでゲームサーバーを最大90パーセント安く利用する方法」です。今回はゲームサーバーを中心に置きます。ゲームを作る上で欠かせないサーバーなんですが、こちらをいかにAWSで安く使っていただくかをご紹介したいと思います。みなさん、AWSをご利用いただいている方はいらっしゃいますか?

(会場挙手)

どうもありがとうございます。なるべく有益な情報を持って帰っていただけるように、がんばりたいと思います。

自己紹介の続きなんですが、私はもともとゲーム会社に勤めておりまして、インフラストラクチャーのメンテナンスを8年間ほどやっておりました。当時は1,500台の物理サーバーを3人で見てました。

その後いろいろな会社を渡り歩いて、IoT系のソフトウェアアーキテクトを経て、2014年に入社しました。当時は流通のサービスを担当していたんですが、どうしてもゲームに戻りたかったので、最近ゲームに戻ってきたという経歴を持っております。

始め口で恐縮なんですが、今年開催されるCEDEC2019で、おかげさまでアワードを受賞することができました。

(会場拍手)

ありがとうございます(笑)。優秀賞を受賞させていただいて、スライドにあるように「安定したパフォーマンスのインフラを提供してゲーム業界に貢献していただきました」という賞賛をいただいて、最優秀賞にもノミネートをしておりますので、CEDEC行かれる方はぜひご投票をお願いしたいと思います。

ゲームサーバーのコストを下げる3つの方法

では、本題に入っていきたいと思います。今日のお話は3本立てです。ゲームサーバーのコストをいかに下げるかという観点で、3つのテーマに分かれています。

まず1つは、インスタンスの価格自体を下げていただくところで、スポットインスタンスの紹介をしたいと思います。一般的なスポットインスタンスのご紹介は、いろいろなAWSの講演で聞かれてるかと思いますが、こちらをよりゲームに落としたかたちで紹介したいと思います。

あとは、ゲームサーバーのオペレーションコストも非常にスケールが大きくなってきて、煩雑になっているので、GameLiftというサービスを使ってどうマネージするかも紹介したいと思います。

最後に、「対価格性能比を上げる」こともゲームサーバーのコストを下げるためには非常に重要なところです。そういったEC2のチューニングについても、お話ししたいと思っております。

ではさっそく、スポットインスタンスの活用についてご説明させていただきます。

こちらおさらいなんですが、現在EC2の購入オプションは3つございまして、まず1つはデフォルトのオンデマンドインスタンスですね。こちらはコンソール上げていただいてポチッとしたら、デフォルトで1秒単位で課金されるモデルです。定価でEC2インスタンスをお使いいただくモデルになっております。

もう1つ、リザーブドインスタンスといいまして、1年や3年など、まとまった期間で契約いただく代わりに大幅なディスカウントをご提供するプランもございます。例えばデータベースなど、まとまった期間ずっとインスタンスを立ち上げっぱなし、といったようなものに対して適用いただく場合などでよくお使いいただいております。

もう1つはスポットインスタンスですね。こちらが今回のメインのお話です。のちほど詳しくご説明させていただきますが、Amazon EC2のリソースプールも常に100%使われているというわけではないため、どうしても使われていないリソースがあります。そんな空きリソースを安くご利用いただくプランになっております。こちらを今回、メインでお話させていただきたいと思います。

スポットインスタンスとはなにか?

こちらがスポットインスタンスの概念です。

こちらは実際にAWSの東京リージョンで、各アベイラビリティゾーンが2つある図です。その中でインスタンスタイプごとに、インスタンスのプールがそれぞれございます。

それぞれお客様がいろいろなインスタンスタイプを選ぶので、インスタンスタイプごとに使ったり使わなかったり、いろいろな空きリソースが発生します。そちらの空きリソースを安く使う、という概念になっております。

スポットインスタンスの価格なんですが、実は需要と供給によって変動します。マネジメントコンソールの中から確認いただくものになっております。

こちらが一昨日のC5ラージのインスタンスのお値段で。オンデマンドが0.158ドルに対して、それぞれアベイラビリティゾーンごとに値段は違うのですが、0.0158と0.0180。約1/10の値段でお使いいただけます。こちらは時間によって変動はしますが、空きリソースがある限りはこの値段でお使いいただけるかたちになります。

じゃあ全部スポットインスタンスを使えばいいじゃん、と思われるかもしれません。なぜオンデマンドインスタンスとスポットインスタンスのそれぞれが存在するか、というところが非常に気になるポイントかと思います。それを次でご説明させていただきたいと思います。

スポットインスタンスにはルールがございます。

空きリソースを利用していただくというところが1つポイントなのですが、空きリソースを利用するがゆえに、需要と供給によって価格が変動するということは先ほど申し上げたとおりです。もう1つは、スポットインスタンスに割いている空きリソースが逼迫してくると、AWS側でインスタンスを停止することがあります。こちらが非常に大きなポイントです。

AWSが停止するタイミングは「空きリソースが使用できなくなったとき」というのがまず1つ。もう1つが、価格で入札するという概念があるのですが、市場価格が入札価格がを上回ったときに停止させていただく場合があります。この2つのタイミングがありますので、ご注意いただければと思います。

逆に考えると、こちらの2つのハンドリングがちゃんとできていれば、先ほどのだいたい1/10のお値段でEC2インスタンスを使うことができます。

みなさん、いかがでしょうか(笑)。最近ゲームのお客様でも非常に多く使われているので、そういった事例ものちほどご紹介したいと思っております。

スポットインスタンスのデメリットとの付き合い方

では、その中断に対して、ゲームのワークロードでいかにうまく付き合うか。ここがポイントなんですが、そちらについてご紹介したいと思います。

まずはスポットの中断ですね。AWSが止めるというところに対して、止めることは回避できないので、それに対してどのようにハンドリングするのか、2つの軸がございます。

一番大事なところは、そのAWSがインスタンスを止めることによって、サービスに影響がでることを回避する必要があるということです。これが一番の大前提でございます。サービスへの影響を回避するために2つの軸がございます。

1つは、止めることに対する影響を局所化することです。スポットインスタンスは、アベイラビリティゾーンとインスタンスタイプの範囲でどんどん止まっていくというので、インスタンスタイプ、アベイラビリティゾーンをどんどん分けて1つのプールとして見ることで、サービスの影響を局所化できます。こちらはのちほどご説明します。

もう1つが、事象のハンドリングです。AWSはインスタンスを止める2分前に通知を行うんですが、その通知を受け取ったあとにどのように振る舞うかで、影響を回避する手段がございます。それぞれご説明させていただきます。

ですがその前に、スポットインスタンスを起動する4つの方法を、あとの説明のためにご説明させていただきます。

スポットインスタンスは現在4つの方法で立ち上げることができます。

1つはAWSのコンソールやAPIで、決まった台数をぽちっと立ち上げていただく方法です。

2番目はスポットフリートです。スポットインスタンスをまとめて立ち上げる機能がございます。こちらもあとでご説明いたします。

3番目がEC2フリートです。今回はこちらが重要です。先ほどスポットインスタンスが、アベイラビリティゾーンとインスタンスタイプで落ちるとお伝えしたと思うんですが、その落ちる確率があるインスタンスのタイプやアベイラビリティゾーンを定義して、1つのプールとして見せます。

そのプールの中で、例えばスポットインスタンス何割、オンデマンドインスタンス何割、というかたちであらかじめ設定しておけば、その台数をずっとキープしてよしなにやってくれます。

最後はEC2オートスケーリングという方法で、フリートをオートスケーリンググループと組み合わせたようなかたちですね。こちらもあとでご説明します。

適切に設定を行うことで、自動で調整

今回ご説明させていただきたいのは、こちらのEC2フリートです。

あらかじめオンデマンドとスポットインスタンスを組み合わせて定義しておいて、例えばスポットインスタンスをAWSが「落とします」と言ったときに、サービス全体が止まると困るので、オンデマンドインスタンスを代わりに立ち上げる設定ができるのが、EC2フリートという設定になります。

その設定の中にも、スポットインスタンスの中にもいろいろな種類を組み合わせ、1つのスポットインスタンスの種類が落ちたとしても、ほかのスポットインスタンスでサービスを稼働し続けるといったことがよしなにできます。

図にあるとおり、こちらはオンデマンドキャパシティ10、スポットキャパシティ5、といったように割合が決定できます。例えばサーバーが15台あったときに、その15台をどう立ち上げるかの設定ができます。そのうち10台がオンデマンドインスタンスで、そのうち5台がスポットインスタンスというかたちで立ち上げられます。

スポットインスタンスの内訳として、スポットインスタンスの中身を例えば「C5のlargeのアベイラビリティゾーン1」と、「C4、largeのアベイラビリティゾーンB」というかたちで、アベイラビリティゾーンを分けます。スポットインスタンスの片方が落ちても、もう1つのスポットインスタンスで動き続ける、ということが設定できます。

端的に言うと、これだけ設定してしまえば、スポットインスタンスが落ちたり上がったりをいちいち命令しなくてもいいという設定になります。こちらが今回のスポットインスタンスのキモになります。

こちらには何が書いてあるかというと、JSONのファイルです。実際、先ほどの1つのサーバーのグループの中で、オンデマンドインスタンスが何パーセント、スポットインスタンスが何パーセント、ということをこのようにJSONの形式で書いていただきます。APIを立ち上げて送ると、そのとおりにEC2のインスタンスが立ち上がっていきます。

現在、マネジメントコンソールからは立ち上げることができませんが、このようにファイルを作っていただく必要がございます。

わかりやすく説明をさせていただくと、オートスケーリンググループでサービスを組んでいただくお客様もけっこういらっしゃると思います。1つのWebサービスの中にたくさんのEC2インスタンスを入れていただいて、そのEC2インスタンス数がミニマム1台で、マックス10台で設定して、負荷が高くなったらマックスまで増える、という設定がオートスケーリンググループというものです。

その背後にあるサーバーを、このようにスポットインスタンスとオンデマンドインスタンスを組み合わせて設定することが昔からできました。スポットインスタンスが需要によって落ちたら、このオンデマンドインスタンスが立ち上がる、ということをAWSでいろいろなお客様が実施してきました。

こちらの例では「m4 large」と「m5 large」という2つのスポットインスタンスのグループがあって、もう1つ保険で「c4 large」のオンデマンドインスタンスを設定しています。その中で「m4 large」のスポットの在庫がなくなってきたら、次は「m5 large」を立ち上げます。その「m5 large」でも間に合わなかったらこのオンデマンドになる、という動きを過去もずっとしていました。

ここで課題となっていたのが、それぞれに対してオートスケーリンググループというか、サーバーを起動する設定をしなければいけませんでした。非常に設定が煩雑になったんですが、先ほどご説明したEC2フリートを使うと、1つのJSONの中に複数のタイプや台数が設定できます。

1つのJSONの中に「m4」のスポットと「m5」のスポットと、「c4」のオンデマンドということを設定できます。

これさえ設定してしまえば中身の割合を設定できるので、そこはよしなに、内訳を自動的に起動してくれます。

中断を検証する方法

こちらが、中断に対する影響を極小化するしくみです。このあたりで何かご質問はございますか?

(会場挙手)

質問者1:実際に検証するときって、どうすればいいのでしょうか?

吉田:あっ、いいご質問、ありがとうございます。スポットフリートという機能がありまして。スポットフリートというのは、先ほどご説明したEC2フリートはスポットインスタンスとオンデマンドインスタンスを組み合わせて定義ができるものでしたが、スポットフリートはスポットインスタンスしか定義ができないフリートの集まりです。

それを使って、例えばスポットフリートの台数をはじめは1台に設定しておいて、それを0台にすることでスポットインスタンスの割り込みをシミュレートできます。なので、こちらのスポットフリートを使っていただくのがいいのかなと思います。

例えばスポットインスタンス自体の振る舞いを検証したいといったときは、スポットインスタンス「1」で、フリートの設定で立ち上げていただきます。それをあとから0台でもう一度リクエストしていただくと、立っていた1台に対してスポットが落ちる、というかたちにするんですね。それでシミュレートができます。

質問者1:JSONで「0台」と記述することが、AWSでぱっと落とすのと同じになると。

吉田:はい、同じ挙動になると思います。

質問者1:ありがとうございました。

吉田:確かにそこのシミュレートが非常にポイントになってきますね。次にその、中断のハンドリングの話をさせていただければと思います。

中断のメッセージを受け取る2つの方法

今ご質問に回答した、中断についてです。中断をするときに、このようなフォーマットでメッセージを受け取ることができます。

メッセージを受け取る方法は2種類あるんですが、このフォーマットをいったん見ていただければと思います。

こういったJSONの情報で、detail-typeに「EC2 Spot Instance Interruption Warning」という文字列が入ってきています。その文字列をキャッチして「中断があります」というところでいろいろな処理をしていただくかたちになります。

フォーマットを受け取る手段は2種類ございます。

まず、通知はAWSから「スポットインスタンスを落としますよ」と言われる2分間前に受け取れます。2分間前にこちらの2つの方法で、先ほどのフォーマットのメッセージを受信することができます。

1つがインスタンスのメタデータです。AWSにはEC2自身のステータスをメタデータとして取得することができるんですが、こちらの「http://169.254.169.254...」というURLをローカルのEC2インスタンスから叩いていただくと、先ほどのJSONが来ます。

それをcronで、例えば5秒間隔で流しておいて、EC2インスタンスにWARNINGのメッセージがきたら処理をする、ということをやっていただく必要がございます。

もう1つの方法は、CloudWatch Eventsという機能です。現在、AWSのいろいろなイベントをプログラムと連携させるために、イベントというかたちで受け取ることができるようになっています。

CloudWatch Eventsもスポットインスタンスに対応していまして、先ほどのフォーマットを受信して、それをこちらの例ではLambdaをインポートして、そのあとにいろいろな処理をしていただくという例がございます。

どちらがいいかはもちろんユースケースによって使っていただければと思いますが、最近多いのはCloudWatch Eventsかなと思います。要するに処理自体を集中管理できるので、「そっちがいいかな」という声をいただいております。

メタデータでは、EC2インスタンスにいろいろプログラムを仕込んだりするのが大変なので、最近はCloudWatch Eventsを使う方が多いかなと思っております。

なので、2分前に「落ちますよ」というメッセージをこのように受け取って、それをどう処理するかが、ゲームでは非常に大切です。

ワークロードごとの対処法

こちらにゲームのワークロードをまとめてみました。

いろいろなゲームのワークロードがある中で、どのように割り込み処理、中断処理をハンドリングするかを、少し書かせていただいております。

ゲームの種類としては、MMORPGを想定しています。要はプレイヤーのセッションが1つのゲームに対してずっとコネクションを貼りっぱなしで、その中でプレイヤーさんのポジションや、イベントをリレーしていくゲームを想定しております。

ロールプレイングなので、ユーザーさんのステートの永続化自体はサーバー以外のところでできているということですね。では、このようなゲームに対してどのようにスポットインスタンスを使うか。もちろん割り込みが発生すると、接続されているプレイヤーさん自身が全部落ちてしまいます。それを落ちないようにすることはできないので、いったんゲームでは「落ちる」ということを前提に作っていただくのが大事です。

もし絶対に落ちてはいけないとなると、スポットインスタンスは使えません。その場合はリザーブドインスタンスなどほかのインスタンスの購入をしていただく必要があります。スポットインスタンスを使う前提で考えると、いったん接続は全部落ちます。

ただ、ステート自体は外部に永続化されているので、その永続化されているデータからロードしてくれば、セッション自体はすぐ復活します。いったんEC2インスタンスはスポットで落ちるものの、ほかのEC2で立ち上げれば復旧できるということさえ許容できれば、MMOにもスポットインスタンスをお使いいただけるのではないかと思います。実際、このようにRPGで使っていただいているお客様も多くいらっしゃいます。

FPSでスポットインスタンスを使う

あとはFPSですね。こちらも最近多いと思います。プレイヤーのポジションやイベントをゲームサーバーで管理していて、ゲームのステート自体はサーバー自身のメモリやディスクに永続化され……永続化ではありませんが、一時的に保存をしています。

セッションの長さは、例えば1ラウンド何分というように時間が決まっていますので、ロールプレイングと比較すると短いほうが多くなっています。

では、そちらに対してスポットインスタンスをどう使うかというと、こちらもRPGのようにステートフルなので、落ちたときの影響は非常に大きいです。こちらはセッションのリストア自体がサーバー自身に残っているので、セッションをリストアすることが非常に難しいです。

ここでは何がポイントになるかというと、2分前に通知を受け取ったときに、データをいかにサルベージするか、というです。そちらでメッセージを受け取って、例えばログを退避したり、プレイヤーの非常に重要な情報を永続化できるところに移すというところをやっていただく必要があります。

接続自体は切断されてしまいますが、例えばゲーム中で「切断します」といったメッセージを出したりしていただくといいのかもしれません。

あるFPSではそれ自体をイベントにしてしまって、例えばなにか大きいモンスターが来たからそのルームは全員死亡、みたいな立て付けでやったりもしています。

こうした制約のもと、FPSでゲームサーバーにスポットインスタンスを使っていただくというケースも非常に多くなっています。

モバイルゲームでの活用法

最後におすすめしたいのは、モバイルゲームです。APIを中心に行っているゲームもけっこうあると思いますが、こちらで使っていただければと思います。

ポイントはステートレスであることなので、サーバーが1台落ちたとしても、ほかのサーバーでサービスを継続することができます。非常に中断の影響度が低いという観点で、こちらをお使いいただきたいなと考えております。

ドレイニング処理などを安全に行うケースが多いので、スポットインスタンスの利用におけるユースケースとしては、こちらが多いです。なのでスポットインスタンスを使うと決められたときには、ステートレスなところでスポットインスタンスのノウハウを獲得していただいて、そのあとほかのゲームにも広げていくと良いのではないかと思います。

例えばMMOやFPSであっても、APIのコンポーネントはあると思います。そちらでスポットインスタンスを試していただいて、そのあとに本体のゲームサーバーの部分にどんどん広げていただくのが良いと思います。

これは事例なんですが、スポットインスタンスとコンテナは非常に相性が良いです。EC2のリソースに応じてコンテナをスケジューリング方法はAWSも含め洗練された方法がいくつもあるため、コンテナが稼働するインスタンスタイプに様々なタイプがばらばらに含まれていたとしても適切にスケジューリングしてくれるため、コンテナと非常に相性がいいです。

コンテナ自体は、例えばEC2のインスタンスタイプが大きかったり小さかったりしても、デプロイでコンテナの数を変えれば、全体のマネジメントがしやすいので、このようにお使いいただくケースが多いです。下にあるように、kubernetesのPodが立ち上がるインスタンスを全部EC2のスポットインスタンスで構成する、という例が非常に多いと思います。

ステートレスなサーバーはすべてスポットインスタンスに

最後に、事例をご紹介したいと思います。先日のAWS Summitで発表していただいた内容なんですが、現在、ディー・エヌ・エーさんはクラウドへの移行を行っているのですが、その中の1つの施策として、コストを下げるために、大部門の中でスポットインスタンスを活用していただいています。

その効果は非常に大きく、ステートレスなサーバーの費用は、全体で60パーセントの削減を実現しました。かつ、それに対するサービス影響はゼロになっております。最近ではmemchachedなどのステートフルなサーバーに対してもスポットインスタンスの導入を広げていて、非常にチャレンジングなことをやっていただいているお客様の1つになります。こちらの事例もご参考いただければと思います。

あとは、EC2 Spot Instances Workshopというものがございまして、こちらを試していただくと、どういうものなのかが網羅できるようになっています。ぜひお試しいただければと思います。

こちらはハンズオン形式になっておりまして、ご自分のAWSアカウントで手順に沿ってどんどんスポットインスタンスを立ち上げてみることができます。

以上がスポットインスタンスの説明です。