SlideShare une entreprise Scribd logo
1  sur  123
Télécharger pour lire hors ligne
©Happy Elements K.K 1
はじめに
©Happy Elements K.K 2
本セッションについて
本セッションは「写真撮影」「SNS拡散」OKです!
©Happy Elements K.K 3
セッション概要
今年7周年を迎えた『メルクストーリア – 癒術士と鐘の音色 –』において、
2021年3月にリアルタイム通信技術を用いた新機能をリリースしました!
リアルタイム通信技術を用いた新機能の開発にあたり、
.NET(MagicOnion / gRPC)を用いたサーバーサイドC#をはじめ、
KubernetesやAgonesと言ったコンテナ技術も採用し、
社内でも初の試みとなる挑戦的な開発に取り組んできました。
今回は、メルクストーリアにおけるリアルタイム通信環境の開発や運用で
得られた知見について、導入事例のひとつとしてご紹介させていただきます!
©Happy Elements K.K 4
受講スキル / 得られる知見
●受講スキル
- ゲーム開発におけるリアルタイム通信技術に興味のある方。
- ゲーム開発におけるKubernetesやAgonesの利用に興味のある方。
- Unityと.NETを用いたC#でのゲーム開発に興味のある方。
●得られる知見
- 運用中タイトルにリアルタイム通信技術を追加導入する知見。
- MagicOnion、Kubernetes、Agonesなどの開発や運用に関する知見。
©Happy Elements K.K 5
セッション目次
1. 自己紹介 / 会社紹介 / タイトル紹介
2. リアルタイム通信環境の導入経緯について
3. 採用技術について
4. 全体のアーキテクチャについて
5. 負荷試験やパフォーマンス改善について
6. ビルドやデプロイ、オートスケールについて
7. リリース当日の様子やリリース後の課題について
8. まとめ
©Happy Elements K.K 6
お詫び
CEDEC公式サイトなどのセッションのご案内にて、
「既存サーバー(Ruby on Rails/オンプレミス)」という表記がございますが、
このオンプレミス環境は、現在クラウド環境への移行が完了しております。
本セッションでは、オンプレミス運用時の紹介も一部ご用意しておりますが、
最新の「既存サーバー(クラウド)」と「新規リアルタイムサーバー(クラウド)」を
ベースにご紹介させていただきます。
予めご了承くださいますよう、お願い致します。
©Happy Elements K.K 7
自己紹介
©Happy Elements K.K 8
自己紹介
Happy Elements株式会社
メルクストーリアグループ エンジニア
岸本 直也 / Naoya Kishimoto
2019年にHappy Elements株式会社に入社。
メルクストーリアグループにてクライアントやサーバーの開発・運用を
担当しつつ、社内ライブラリの開発などの横断的な業務も行っています。
©Happy Elements K.K 9
自己紹介
Happy Elements株式会社
社長室 インフラチーム サブリーダー
長谷川 一輝 / Kazuki Hasegawa
2020年にHappy Elements株式会社に入社。
リアルタイム通信機能向けインフラ設計/構築/運用をAWSを利用して担当。
現在はインフラチームのサブリーダーとして、全タイトル横断的な業務も
行っています。
©Happy Elements K.K 10
会社紹介
©Happy Elements K.K 11
会社紹介
Happy Elements株式会社
MAKE THE WORLD HAPPY!
北京を拠点にアジア圏でゲームサービスを展開する
Happy Elementsグループの日本子会社です。
『熱狂的に愛されるコンテンツをつくる』ことを
ビジョンとし、京都のカカリアスタジオを拠点に
オリジナルゲームの開発・運営を行っています。
©Happy Elements K.K 12
提供タイトル
©Happy Elements K.K 13
メルクストーリア
– 癒術士と鐘の音色 –
©Happy Elements K.K 14
メルクストーリア – 癒術士と鐘の音色 –
メフテルハーネという世界を舞台に
無気力少年と瓶詰め少女がモンスターを癒やす
ラインストラテジーRPG
2021年1月に7周年を迎え、
1800を超える個性豊かなキャラクターと
涙を誘うものから熱血・ラブコメまで
心揺さぶる多彩なストーリーを楽しむことができます!
©Happy Elements K.K 15
メルクストーリア – 癒術士と鐘の音色 –
ストーリーを楽しみながら遊べるラインストラテジーを中心に、
ギルドバトルをはじめ、協力して遊べるマルチプレイなど、
幅広いコンテンツを楽しむことができます!
©Happy Elements K.K 16
タイトルの課題
©Happy Elements K.K 17
タイトルの課題
ゲーム内チャット機能やイベントマップ上のキャラクター位置など、
ユーザー間のデータ同期はすべてポーリングで実現していて、
若干のタイムラグもあるためユーザー体験の低下に繋がっていました…。
ユーザー体験の改善に加えて、新しいコンテンツも追加したいし、
リアルタイム通信技術を活用することはできないか…?
©Happy Elements K.K 18
タイトルの課題
- ポーリングにも限界があり、もう少し体験を良くしたい…。
- オンプレミス(当時)は、これ以上の拡張が困難…。
- 各種バージョンアップができておらず、技術的負債も…。
現在は、オンプレミスからクラウドへの移行も完了しましたが、
計画当時の環境へのリアルタイム通信対応は難しいと判断しました。
また、社内の注目技術のひとつにgRPCが挙がっていたこともあり、
技術研究も含めて、新しくリアルタイム通信環境を構築できないか、
考えることになりました。
©Happy Elements K.K 19
タイトルのアップデート要件
- ギルド内でのコミュニケーション機能として、チャットやスタンプに加えて、
マップ上のキャラクター位置をリアルタイムで同期したい。
- 将来的にバトル(クエスト)を用いたリアルタイムレイドなどの
機能追加も考えている。
©Happy Elements K.K 20
技術的解決方法の模索
©Happy Elements K.K 21
技術選定
リアルタイム通信環境を構築する場合、WebSocketを利用したり、
Photonなどのサービスを利用する方法が考えられます。
一方で、社内の注目技術のひとつとしてgRPCが挙がっており、
技術研究としてgRPCを用いた開発ができないか考えました。
また、リアルタイム通信のデータ共有部分の設計として、
ステートレスな構成を選ぶかステートフルな構成を選ぶかも、
大きな問題となってきます。
©Happy Elements K.K 22
社内のリアルタイム通信事例【参考】
社内にはPhoton Cloudを用いたリアルタイム通信の実績がすでにあったり、
また、今回の開発と並行してNode.js(WebSocket)とRedis Streamsを活用した
リアルタイム通信の導入を計画しているタイトルもありました。
Redis Streamsを用いたステートレスなリアルタイム通信環境は、
シンプルに構成することができて、スケーリングもしやすい一方で、
パフォーマンス面や料金コスト面で気にしないといけないこともあります。
©Happy Elements K.K 23
ステートレス?ステートフル?
今回はステートフルなリアルタイム通信環境を目指しました。
©Happy Elements K.K 24
ステートフルな理由
なぜステートフルなリアルタイム通信環境を目指したのか?
まずはコミュニケーション機能での利用を目的としていますが、
将来的にリアルタイムレイドなどでの利用も予定しているため、
メルクストーリアのバトル(クエスト)を考えた場合、
インメモリでデータ共有することで、パフォーマンスも出しやすく、
同期部分の実装もシンプルにできるメリットがあると考えました。
©Happy Elements K.K 25
採用技術
©Happy Elements K.K 26
用語解説
本セッションでは、4種類のサーバーが登場します。
●リアルタイムサーバー (.NET / C#)
リアルタイム通信を担当するサーバー。
●サービスディスカバリー (.NET / C#)
クライアントとリアルタイムサーバーを仲介するサーバー。
●メインサーバー (Ruby on Rails / Ruby)
ゲーム用にメインで使用している既存のAPIサーバー。
●管理画面 (.NET / C#)
リアルタイム通信環境で内部的に使用できる管理用サーバー。
©Happy Elements K.K 27
チーム担当範囲
今回の開発は、チーム担当を決めて開発しました。
今回の開発では、インフラと深く関係するKubernetesが登場します。
開発チームとインフラチームで以下ような担当範囲を決めて開発しました。
●開発チーム (メルクストーリアグループ)
Kubernetesより上のレイヤーでタイトル要件に関連するものを担当
●インフラチーム
Kubernetesより下のレイヤーでクラウド環境に関連するものを担当
©Happy Elements K.K 28
採用技術 (リアルタイムサーバー / サービスディスカバリー / 管理画面)
フレームワーク .NET 5.0 / C# 9.0
gRPC MagicOnion, Grpc.Core, Grpc.Net.Client など
シリアライザー MessagePack for C#
MySQL (Micro-ORM) Dapper
Redis StackExchange.Redis
Kubernetes KubernetesClient
Telemetry prometheus-net, OpenTelemetry.Exporter.Zipkin
その他 ZLogger, System.Reactive など
©Happy Elements K.K 29
採用技術 (クライアント)
フレームワーク Unity 2018.4 / C# 7.3
gRPC MagicOnion, Grpc.Core など
シリアライザー MessagePack for C#
その他 UniTask など
©Happy Elements K.K 30
採用技術 (インフラ)
Amazon Web Services
Amazon Elastic Kubernetes Service (EKS)
Amazon Elastic Compute Cloud (EC2)
AWS Fargate
Amazon Aurora (MySQL互換)
Amazon ElastiCache (Redis)
Amazon Elastic Container Registry (ECR)
AWS CodePipeline
AWS CodeBuild
Amazon CloudWatch
AWS Secrets Manager
AWS WAF
モニタリング
Datadog
その他
Terraform
©Happy Elements K.K 31
採用技術 (メインサーバー) 【参考】
フレームワーク
Ruby on Rails 6.0 / Ruby 2.7
Amazon Web Services
Amazon Elastic Container Service (ECS)
Amazon Elastic Compute Cloud (EC2)
Amazon Aurora (MySQL互換)
Amazon ElastiCache (Redis / Memcached)
Amazon Elastic Container Registry (ECR)
AWS CodePipeline, AWS CodeBuild, AWS CodeDeploy
Amazon CloudWatch
AWS WAF
©Happy Elements K.K 32
MagicOnion
通信フレームワークにMagicOnionを採用しました!
©Happy Elements K.K 33
MagicOnion
なぜMagicOnionを採用したのか?
クライアントがUnity(C#)なことに加え、通信プロトコルにgRPCを選択した場合、
MagicOnionを採用することで、C#のみで完結できることに注目しました。
クライアント・サーバー間でのコード共有やIDE統一などが可能で、
それぞれが異なる言語での開発に比べて、多くのメリットがあると考えたため、
gRPCの通信フレームワークにMagicOnionを採用し、クライアントもサーバーも
C#を用いたリアルタイム通信環境の実現を目指しました。
クライアントもサーバーもC#で大統一!
©Happy Elements K.K 34
Kubernetes + Agones
KubernetesとAgonesを採用しました!
©Happy Elements K.K 35
Agones
なぜAgonesを採用したのか?
ステートフルなリアルタイム通信環境を自前で構築した場合、
サーバー管理やスケーリングなどで多くの課題を解決する必要があるため、
解決方法としてAgonesに注目しました。
Kubernetes自体は、ステートレスなサービス向けのシステムですが、
Agonesは、Kubernetesでゲーム用のステートフルなリアルタイム通信環境の
実現を目的に開発されており、KubernetesとAgonesを組み合わせることで、
今回の要件にマッチした環境が構築できると考え、採用しました。
©Happy Elements K.K 36
全体アーキテクチャ
©Happy Elements K.K 37
全体構成
AWSを利用して環境構築しました。
©Happy Elements K.K 38
サービスディスカバリー
クライアントとリアルタイムサーバーを仲介するステートレスなサーバーです。
一般的なAPIサーバーと同じ扱いのため、ALBを経由しての接続となり、
ロードバランスしています。
©Happy Elements K.K 39
リアルタイムサーバー
リアルタイム通信用の双方向通信をサポートするステートフルなサーバーです。
Agonesを利用することで、クライアントとサーバーを直結しています。
©Happy Elements K.K 40
環境間通信 【参考】
オンプレミス環境などでAPIサーバーを運用していて、リアルタイム通信を
追加で別環境に構築したい場合、データ共有などで環境間通信の必要があり、
メルクストーリアでは、VPCを跨いでAuroraに接続することで解決しています。
オンプレミス環境で運用していたときは、インターネットを介した環境間通信で
実現していましたが、ある程度のレイテンシが発生するため、注意が必要です。
©Happy Elements K.K 41
MagicOnionで実現できること
©Happy Elements K.K 42
MagicOnionで実現できること
単発と双方向のgRPC通信をサポートしています。
gRPCのUnaryCallに相当するServiceと、
gRPCのDuplexStreamingCallに相当するStreamingHubの2種類を使用できます。
©Happy Elements K.K 43
MagicOnionで実現できること
©Happy Elements K.K 44
Gitリポジトリとコード共有
今回は、クライアントとリアルタイム通信環境でGitリポジトリを分割しました。
クライアントとサーバーで共通利用するコードは、サーバー側をマスターとし、
MagicOnionやMessagePackのコード生成も含めて、Unityエディタ拡張で
クライアント側のリポジトリにコード共有しています。
©Happy Elements K.K 45
MagicOnionでステートフルなリアルタイム通信
StreamingHubでは、Groupを用いることでチャットルームのような単位で
グルーピングして、クライアントにブロードキャストすることができます。
データの管理・共有は、共通インスタンスを作成し、インメモリで処理します。
また、ステートレスな構成向けにMagicOnion.Redisを用いることで、
Redis Pub/Subを使ったデータ共有にも対応できます。
©Happy Elements K.K 46
メルクストーリアにおけるサービスディスカバリー
MagicOnionのServiceを利用して実装しています。
ASP.NET Core標準のWebサーバーであるKestrelを複数起動することで、
公開用と内部用のホストを分割しています。
©Happy Elements K.K 47
メルクストーリアにおけるリアルタイムサーバー
MagicOnionのStreamingHubとServiceを利用して実装しています。
ASP.NET Core標準のWebサーバーであるKestrelを複数起動することで、
公開用と内部用のホストを分割しています。
©Happy Elements K.K 48
Agonesで実現できること
©Happy Elements K.K 49
Agonesで実現できること
KubernetesのPodを直接公開できる!
通常のKubernetesであれば、PodはService経由での公開となりますが、
AgonesではPodを直接インターネットに公開できます。
©Happy Elements K.K 50
Agonesで実現できること
KubernetesのAPIでサーバー管理ができる!
Podとしてリアルタイムサーバーを扱うことができるため、
KubernetesのAPIサーバーを介してサーバー管理ができます。
©Happy Elements K.K 51
Agonesで実現できること
オートスケールできる!
FleetAutoscalerを使用して、オートスケールも対応できます。
©Happy Elements K.K 52
Agones NodeExternalDNS (Alpha)
メルクストーリアのリアルタイム通信では、IPv6ネイティブ対応していませんが、
iOSアプリケーションは、NAT64/DNS64環境下でのIPv6動作が求められるため、
これに対応する必要がありました。
Amazon EC2にはインスタンス毎にドメインを割り当てる機能があり、
これを利用したいと考えました。
(VPC DNSサポート/パブリックDNSホスト名機能)
一方で、リアルタイムサーバーの接続先アドレスをAgonesから取得した場合、
EC2(Node)のIPアドレスだけしか取得できず、
EC2のインスタンスドメインを直接取得できる振る舞いではありませんでした…。
©Happy Elements K.K 53
Agones NodeExternalDNS (Alpha)
そこで、AgonesにNodeExternalDNSを実装しました!
従来は、AgonesからPod(GameServer)の情報を取得したときに、
ExtrenalIPのみが取得でき、NodeのExternalDNSの取得はできませんでした。
そこで、Agones側でExternalDNSを優先して取得するような機能追加とし、
NodeExternalDNSを実装しました!
現在Alpha版のため、FeatureGatesのNodeExternalDNSを有効化することで、
使用できるようになります。
https://github.com/googleforgames/agones/issues/1921
©Happy Elements K.K 54
Agonesだけでは実現できないこと
©Happy Elements K.K 55
Agonesだけでは実現できないこと
無制限に接続はできないので、ソフトリミットが必要です。
クライアントの接続に対して「コスト」の概念を導入して、
サーバー1台あたりのソフトリミットを管理しています。
(AgonesのFeatureGatesのPlayerTracking(Alpha)で同様のことができます。)
ただし、一概に何人繋げるというわけではないので、ユースケースに応じた
負荷試験などで見極めが必要になります。
©Happy Elements K.K 56
Agonesだけでは実現できないこと
接続中のサーバーを停止できないので、注意が必要です。
Agonesは、KubernetesのライフサイクルからPodの保護をしてくれますが、
以下のような部分は作り込みが必要になります。
- デプロイなどをノーメンテナンスで実施する際は、
ユースケースに応じて対応が必要になります。
- チャットルームのような利用時間が不定の場合は、
複数のサーバーに接続が分散しがちで、リソースの効率的に利用した場合は、
定期的にデフラグやドレイニングなどの工夫が必要になります。
©Happy Elements K.K 57
Agonesだけでは実現できないこと
Agonesを用いたリアルタイムサーバーは、直接インターネットに公開するため、
SSL通信を利用する場合、サーバーに対してSSL証明書の設定が必要になります。
今回は、AWS SecretsManagerでSSL証明書を管理し、
Kubernetes SecretでSSL証明書をPod(サーバー)にマウントすることで、
サーバー・クライアント間のSSL通信に対応しています。
©Happy Elements K.K 58
Agonesだけでは実現できないこと
AWS SecretsManagerなどのクラウドサービスを活用することで、
Gitなどから機微情報を排除し、シークレットを安全に扱うことができます。
ただし、Kubernetes Secretを用いて実行環境にマウントする際は、
AWS SecretsManagerとKubernetes Secretの連携が必要となります。
今回は、環境構築バッチや管理画面から更新できるような仕組みを作り、
AWS SecretsManagerのAPIからシークレットを取得し、
Kubernetes Secretに変換することで対応しています。
今回利用していませんが、
Kubernetes SecretProviderClass(Aplha)を利用することで、
クラウドサービスとKubernetes Secretの連携も可能になっています。
©Happy Elements K.K 59
Kubernetes
©Happy Elements K.K 60
Kubernetes
Amazon EKSを採用しました!
KubernetesのマネージドサービスであるAmazon EKSを利用することで、
Kubernetesのコントロールプレーンの管理をしなくても良いことに加え、
他のAWSサービスとの連携や、EKS-Optimized AMIが公式から提供されている
ことなど、マネージドサービスならではの多数の恩恵を受けています。
EKSの利用にあたり、ノード構成として以下の戦略を取りました。
- アプリケーションのPodは、EC2タイプのノードに配置する。
- クリティカルなPodは、Fargateタイプのノードに配置する。
©Happy Elements K.K 61
EKS EC2
サービスディスカバリーやリアルタイムサーバーなど、
リソースを大きく消費することが想定されるPodについては、
コスト効率に優れるEC2タイプをノードに配置しています。
また、EC2タイプのノードを採用した理由として、
社内にEC2運用のナレッジが存在している点も理由として挙げられました。
ただし、リアルタイムサーバーのようなステートフルなサーバーを扱う場合、
EC2のスポットインスタンスは回収されるリスクが存在するため、
EKSで利用しているEC2はすべてオンデマンド起動タイプを利用しています。
©Happy Elements K.K 62
EKS Fargate
Agonesコントローラーのような、
クラスタ内でひとつしか起動できないクリティカルなPodで、
ほとんどリソースを消費しないPodについては、Fargateタイプのノードに
配置しています。
Fargateに対するリソース要求として、0.25 vCPU / 0.5GB Memoryのような
下限値の設定であっても、Agonesのコントローラー等で利用する分には、
十分なリソース設定であるため、料金コストも抑えられるメリットがあります。
©Happy Elements K.K 63
EKS EC2 + Fargate
EC2タイプのノードにはまれにメンテナンスの必要があります。
- 脆弱性への対応のため、AMIを更新する必要があります。
- Datadog Agentなどのコンテナの外側で動作するアプリケーションを
更新する必要があります。
これらはすべて、AMIを再作成した後、
ノードのローリングアップデートを伴うオペレーションが発生します。
そこで、AgonesコントローラーのようなクリティカルなPodは、
Fargateタイプのノードに配置することで、EC2のメンテナンスから解放し、
EC2のメンテナンス時は、自分たちのアプリケーションのPodの都合だけを
考えればいいようにしています。
©Happy Elements K.K 64
ローカル開発環境
©Happy Elements K.K 65
ローカル開発環境
ローカル開発環境は、Minikubeを利用しています。
VM上で動作するMinikubeを利用することで、
クラウド環境に近いKubernetes環境を構築して、開発しています。
また、ローカルで稼働しているメインサーバーとの共存もできています。
©Happy Elements K.K 66
Telepresence
Telepresenceを利用し、デバッグ実行しています。
VM内のMinikube環境に対して、Telepresenceを利用することで、
ローカルでのデバッグ実行ができるようにしています。
ただし、Deploymentのみ対応可能で、AgonesのFleetは非対応のため、
Fleetで管理しているリアルタイムサーバーをDeploymentでも起動できるように、
Telepresence動作時のみ、Agones関連の処理を差し替えています。
©Happy Elements K.K 67
KubernetesのYAML管理
©Happy Elements K.K 68
KubernetesのYAML管理
Kustomizeを利用し、環境毎に差分管理しています。
全環境共通となるベース定義を基に、環境毎にディレクトリを構成し、
差分でYAML管理しています。
©Happy Elements K.K 69
KubernetesのYAML管理
- Kustomizeを利用することで、環境別にYAMLを管理するよりは、
共通化しやすいですが、データベースの接続先など環境差分も必ずあるため、
思っているより共通化はむずかしいです。
- Agonesは、YAML(install.yaml)でのインストールも可能ですが、
Helmでのインストールが推奨となっています。
→今後Helmでのインストールに切り替え予定です。
- KustomizeやHelmなど、KubernetesのYAML管理方法はいくつかあるので、
プロジェクト規模や用途に応じて、扱いやすいものを選択すると良いです。
©Happy Elements K.K 70
direnvとkubeconfig
direnvを利用し、環境毎のkubeconfigの切り替えています。
環境毎にクラスタ接続先となるkubeconfigの切り替えが必要になるため、
direnvを利用して、環境毎に切り替えています。
環境毎にディレクトリを構成するKustomizeとも相性が良く、
kubeconfigの切り替えを意識することなく、スムーズに作業ができています。
©Happy Elements K.K 71
ビルド
©Happy Elements K.K 72
ビルド
CodeBuildでビルドし、ECRにイメージを保存しています。
.NETのベースイメージを基に、メルクストーリア専用のベースイメージを作成し、
サーバー単位でコンテナイメージをビルドしています。
開発環境は更新頻度が高いため、GitHubと連携して自動ビルドしています。
©Happy Elements K.K 73
専用ベースイメージについて
専用のベースイメージを作成している理由として、サービスディスカバリー、
リアルタイムサーバー、管理画面、バッチなど、複数のコンテナイメージを
ビルドしますが、NuGetパッケージの復元に時間がかかるので、
.NETのベースイメージ上に必要なNuGetパッケージも含めたイメージを用意し、
それを基にアプリケーション用のコンテナイメージをビルドしています。
特にMinikubeでは、ビルド時間短縮の効果を発揮しています。
©Happy Elements K.K 74
デプロイ
©Happy Elements K.K 75
デプロイ (サービスディスカバリー)
Deploymentを更新して、ローリングアップデートしています。
管理画面からECRのイメージの選択とデプロイバッチを起動することで、
Deploymentのimageのバージョンタグを更新し、アップデートしています。
©Happy Elements K.K 76
デプロイ (サービスディスカバリー)
- ステートレスなサーバーなので、Deploymentのローリングアップデートを
利用して、Kubernetesの標準的なデプロイをしています。
- ただし、Kubernetes ServiceやAWS ALBなどのロードバランサーからの
切り離しは非同期となり、切り離し完了までトラフィックが流れるため、
PreStopにフックしたグレースフルシャットダウンを実行することで、
切り離し完了を待機しています。
©Happy Elements K.K 77
デプロイ (リアルタイムサーバー)
Fleetを更新して、ローリングアップデートしています。
管理画面からECRのイメージの選択とデプロイバッチを起動することで、
Fleetのimageのバージョンタグを更新し、アップデートしています。
©Happy Elements K.K 78
デプロイバッチのフロー (リアルタイムサーバー)
1. Fleetのimageをパッチする。
旧バージョンでReadyなPodのローリングアップデートがはじまります。
AgonesのFeatureGatesのRollingUpdateOnReadyも利用できます。
2. 新バージョンのPodが1台以上起動するまで待機します。
3. 割当可能なリアルタイムサーバーのバージョン情報を更新します。
このタイミングで旧バージョンへの新規の接続割当を停止します。
4. 旧バージョンでAllocatedなPodを1台ずつグレースフルシャットダウンし、
接続中のユーザーのドレイニングしてから、サーバーを停止します。
©Happy Elements K.K 79
割当可能なリアルタイムサーバーのバージョン管理
サービスディスカバリーから接続割当先となるリアルタイムサーバーは、
デプロイでバージョンが変わるため、デプロイなどで新旧2バージョンの
リアルタイムサーバーが共存するタイミングでは、
旧バージョンに新規の接続割当ができないように制御する必要があります。
今回は、割当可能なリアルタイムサーバーのバージョンは、
Redisに保持するようにし、デプロイバッチの中で更新して切り替えています。
サービスディスカバリーからの割当要求時に、
リアルタイムサーバー側で自身のバージョンとRedis保持のバージョンを比較し、
バージョン不一致の場合は、割当要求を拒否するようにしています。
©Happy Elements K.K 80
PreStopを用いたグレースフルシャットダウン
Kubernetesのライフサイクル(PreStop)にフックすることで、
グレースフルシャットダウンの処理を実行しています。
サービスディスカバリーやリアルタイムサーバーにgRPC(MagicOnion)で
PreStop用のインターフェイスを実装し、gRPC通信のできる簡単なコンソール
アプリケーションを経由することで、PreStop-execでフックしています。
©Happy Elements K.K 81
グレースフルシャットダウンのフロー (サービスディスカバリー)
1. 内部的なサーバーステータスをStoppingに変更します。
2. ALB(TargetGroup)から切り離しを待機します。
3. gRPCホスト(Kestrel)を停止して、アプリケーションを終了します。
ステートレスなサーバーなので、アプリケーション的に特別な処理は不要ですが、
Kubernetes ServiceやAWS ALBからの切り離しを待機する必要があるため、
PreStopにフックしたグレースフルシャットダウンを実施しています。
©Happy Elements K.K 82
グレースフルシャットダウンのフロー (リアルタイムサーバー)
1. 内部的なサーバーステータスをStoppingに変更します。
このタイミングで、新規の接続割当を停止します。
2. 接続中のユーザーをドレイニングしていきます。
3. AgonesのShutdownを呼び出します。
4. gRPCホスト(Kestrel)を停止して、アプリケーションを終了します。
ステートフルなサーバーなので、新規の接続割当を停止したり、
接続中ユーザーのドレイニングが必要になるため、
PreStopにフックしたグレースフルシャットダウンを実施しています。
©Happy Elements K.K 83
デプロイまとめ
- 今回は、AWSのAPIを活用したりKubernetesのAPIを活用して、
管理画面やデプロイバッチを作り込むことで、
通常のアップデートであれば、管理画面とデプロイバッチでお手軽に
デプロイできるようにしています。
- ただし、GitHubで管理しているDeploymentやFleetのimageと
実環境のimageは差分が出るので要注意です。
- DeploymentやFleetのimage以外を更新するアップデートは、
ケースバイケースの対応になるので、kubectlで手作業しています。
- PreStopにフックして、グレースフルシャットダウンしています。
©Happy Elements K.K 84
オートスケール
©Happy Elements K.K 85
オートスケール (サービスディスカバリー)
HorizontalPodAutoscalerを採用しました。
CPU負荷に応じて設定台数内でスケールするようにしています。
©Happy Elements K.K 86
オートスケール (リアルタイムサーバー)
FleetAutoscalerを採用しました。
Agonesのステータス(ReadyやAllocatedなど)に応じて設定台数内で
スケールするようにしています。
©Happy Elements K.K 87
リアルタイムサーバー(Fleet)のオートスケール戦略
AgonesのFleetAutoscalerでは、Agonesのステータスである
「未接続(Ready)」や「接続中(Allocated)」に応じてオートスケールします。
サーバー台数のみのオートスケールになるため、サーバー負荷に関しては、
コスト(ソフトリミット)で管理しています。
今回、ひとつのリアルタイムサーバーにコスト上限まで詰め込むようにしたため、
あえてサーバーを分散させずに、極力集中させることで、少ないサーバー台数に
収まるように工夫しています。
©Happy Elements K.K 88
デフラグ
©Happy Elements K.K 89
リアルタイムサーバーのデフラグ
チャットルームのような利用時間が不定の場合、
極力サーバーを集中させるように工夫しても、時間経過につれて、
サーバー全体に接続が分散しがちで、リソース的な無駄が発生しがちです…。
Agonesは、数分〜数時間程度の短時間利用で使い捨てていく思想ですが、
長時間利用したり、ひとつのサーバーに詰め込むようなユースケースだと、
このあたりはいい感じにできません…。
©Happy Elements K.K 90
リアルタイムサーバーのデフラグ
接続の減る時間帯を利用して、日次バッチにてデフラグを実施しています。
デプロイと同じ要領で、稼働中のサーバーに対してドレイニングを実施し、
最低限の台数に収まるように、サーバーの再割当をしています。
©Happy Elements K.K 91
リアルタイムサーバーのデフラグまとめ
- チャットルームのような利用時間が不定の場合、
接続のデフラグ機構を用意しておくことで、スケールインしやすく、
料金コストも抑えることができます。
- KubernetesのCronJobとしてバッチ運用することができます。
- インフラ作業などで明示的にドレイニングしたいときも利用できます。
©Happy Elements K.K 92
負荷試験
©Happy Elements K.K 93
負荷試験
負荷試験クライアントは、.NET(C#)で作成しました。
©Happy Elements K.K 94
負荷試験
社内標準の負荷試験クライアントは、Locust(Python)を使用していますが、
MagicOnionの特徴として、C#であればコード共有ができるため、
負荷試験クライアントも.NETのコンソールアプリケーションとして開発し、
負荷試験を実施しました。
(ただし、詳細な性能情報を取るには、別途APMが必要となります。)
負荷試験クライアントもKubernetesにPodとしてデプロイし、
負荷試験を実施しています。
©Happy Elements K.K 95
負荷試験シナリオ (最大同時接続数の確認)
リアルタイムサーバー1台あたりの最大同時接続数を確認。
1RPS/ユーザーの負荷がかかるシナリオを作成し、
少しずつユーザー数(接続)を増やして、CPU負荷に対しての最大同時接続数を
確認しました。
この試験結果を基に、1ユーザー=コスト1とし、
リアルタイムサーバーのコスト上限(ソフトリミット)を確定しました。
©Happy Elements K.K 96
負荷試験シナリオ (シナリオテスト)
実際のユースケースに近い状況を確認。
1RPS/ユーザーの負荷に加えて、ギルド内のメンバーが段階的に接続・切断する
ようなシナリオを作成し、実際のユースケースに近い状況の確認をしました。
また、コスト上限(ソフトリミット)に達したときの挙動確認や、
オートスケールの様子なども確認しました。
©Happy Elements K.K 97
負荷試験シナリオ (長時間稼働の確認)
長時間稼働時の状況を確認。
接続・切断を繰り返すようなシナリオを作成し、
24時間程度の長時間負荷を掛け続け、メモリなどのサーバーリソースが、
本番運用に耐えられることを確認しました。
©Happy Elements K.K 98
負荷試験で判明した問題点
©Happy Elements K.K 99
KubernetesのAPIサーバーの負荷問題
サービスディスカバリーからリアルタイムサーバーに接続する際に、
KubernetesのAPIサーバーに対して、Get(kubectl get pods相当)の通信を、
毎回リクエストしていましたが、負荷試験の接続数が増加するに比例して
パフォーマンスが劣化しはじめました…。
毎回リクエストするのではなく、Watch(kubectl get pods -w相当)を利用し、
Kubernetesとリアルタイムに同期することで、解決しました。
KubernetesClientのWatcher<T>を活用することで、
様々なKubernetesオブジェクトを簡単にWatchできるようになりますが、
Watchは切断することがあるので、エラー時など必要に応じて、
自動再接続できるように対策しています。
©Happy Elements K.K 100
gRPCのChannelのリーク問題
サービスディスカバリーからリアルタイムサーバーのgRPC通信は、
Channelを再利用できるように内部でキャッシュしていましたが、
単純なコーディングミスでリークしていました…。
単純にコード修正することで解決しました。
©Happy Elements K.K 101
トレース(Zipkin)によるメモリ消費
トレース(Zipkin)を有効にしたまま負荷試験を実施した結果、
ストリーミング通信中の通信もすべてトレース対象となるため、
通信が終了するまでトレースが蓄積していき、メモリを消費していました…。
単純にトレースを無効にすることで解決しました。
©Happy Elements K.K 102
リリース当日の様子
©Happy Elements K.K 103
リリース当日
3月8日15時にリリースしました!
新バージョンのクライアントからのみ新機能に接続
できるようにしていたため、
メインサーバー含めてノーメンテナンスでリリースし、
トラブルもなく無事にリリースできました!
ノーメンテナンス! ノートラブル!
©Happy Elements K.K 104
アクセス状況 (サービスディスカバリー ALBリクエスト数)
ギルド関連の画面でリアルタイム通信環境に接続するため、
リリース直後から徐々に接続が増え始め、
18時30分のギルドバトル開始時に一度リクエストが増加しています。
22時30分のギルドバトル終了時にピークを迎えました。
©Happy Elements K.K 105
負荷状況 (CPU使用率)
ギルドバトル時間帯は接続数も増えるため、CPU負荷も比例して増加しますが、
想定負荷に収まっており、問題ありませんでした。
©Happy Elements K.K 106
負荷状況 (メモリ使用量)
サービスディスカバリーは、ほぼ一定値で推移しています。
リアルタイムサーバーは、接続数の増加に比例して、
メモリ使用量も増加していますが、想定負荷に収まっており、
問題ありませんでした。
©Happy Elements K.K 107
パフォーマンス状況 (サービスディスカバリー 平均レスポンスタイム)
平均20〜60ms程度でレスポンスできています。
リアルタイムサーバーとのサーバー間通信を行っていますが、
再接続時はキャッシュを活用することで、アクセスが集中する時間帯も
パフォーマンス劣化なくレスポンスできています。
©Happy Elements K.K 108
パフォーマンス状況 (リアルタイムサーバー 平均レスポンスタイム)
平均0〜4ms程度でレスポンスできています。
初回接続時の通信などは、Redisへのアクセスもあるため、
数ms程度のレイテンシが発生していますが、
リアルタイム通信の要であるデータ共有の通信は、インメモリで完結するため、
ほぼゼロタイムでレスポンスできています。
©Happy Elements K.K 109
リリース後の課題
©Happy Elements K.K 110
課題1 (リアルタイムサーバーのコスト上限の調整)
負荷試験結果から設定していたコスト上限(ソフトリミット)に対して、
実際の負荷だとサーバーリソースに十分に余裕のある状況になりました。
元々過剰な負荷をかけた負荷試験結果を基準とした設定であったため、
実運用の負荷を踏まえて、コスト上限を再調整することで、
サーバーリソースを効率的に使えるように、フィッティングしました。
コスト上限の調整は、管理画面から動的に設定変更できるようにしています。
©Happy Elements K.K 111
課題2 (メトリクスの可視化)
リアルタイムサーバー1台あたりの接続数やメソッド別レスポンスタイムなど、
APM標準では確認できないメトリクスを可視化しました。
.NETのアプリケーションサーバーからPrometheus形式でデータを出力し、
Datadogに統合しました。
©Happy Elements K.K 112
課題3 (外形監視の強化)
Kubernetesのコントロールプレーンに障害が発生し、
外形監視やヘルスチェックに対してアプリケーションサーバーとしては、
応答できる状態でしたが、内部的には、Kubernetesのコントロールプレーンに
アクセスができない状態だったため、サービス不能になりました。
(外形監視やヘルスチェックは、Healthyでした…。)
小規模なマイクロサービスとはいえ、サービス間の依存関係が多いため、
依存サービスとの疎通もチェックすることで、
外形監視やヘルスチェックでの障害監視を強化しました。
©Happy Elements K.K 113
Kubernetesバージョンアップ
(今後の予定)
©Happy Elements K.K 114
Kubernetesバージョンアップ
Kubernetesバージョンアップは、クラスタ切替で対応します。
©Happy Elements K.K 115
Kubernetesバージョンアップ
- ALBのTargetGroupの切替でクラスタレベルのブルーグリーンデプロイと
なるため、メンテナンスやダウンタイムなしでバージョンアップできます。
- ただし、新旧2バージョンのクラスタが必要なので、一時的に料金コストが
2倍になる点や、切替後でも旧バージョンのリアルタイムサーバーに接続が
残っているので、切替後にドレイニングなどの作業は必要になります。
- 内部確認用に新旧バージョン別のドメインを用意して、
明示的に新旧のそれぞれにアクセスできるようにしておくと便利です。
- Kubernetesはバージョンアップ頻度が高くEOLも短めのプロダクトのため、
バージョンアップと付き合っていく必要があり、一度走り出すと
止まれない点は注意が必要です。(塩漬けはできない!)
©Happy Elements K.K 116
まとめ
©Happy Elements K.K 117
開発を振り返って
MagicOnionに加え、KubernetesやAgonesも活用することで、計画通りに
ステートフルなリアルタイム通信環境を構築でき、ユーザー体験の改善や遊びの
幅を広げることができました。
メルクストーリアのように部分的な利用であれば、既存のAPIサーバーとの
共存も現実的で、すでに運用中のタイトルでも追加導入しやすいと思います。
インメモリのデータ共有でハイパフォーマンスなことに加え、非常に少ない
サーバー台数で運用できており、ローコストな運用ができています。
ただし、まだあまり枯れていない技術が多かったため、内部実装を確認したり、
バグを踏むこともあり、泥臭い苦労も多かったです…。
©Happy Elements K.K 118
MagicOnion
社内初の.NETを用いたサーバーサイドC#の開発でしたが、Unity(C#)とも
相性が良く、言語の違いを意識することなく、クライアントとサーバーの
通信部分を非常にスムーズに開発を進めることができました。
現在開発中のリアルタイムレイドは、クライアントとサーバーでコアロジックの
コードを共有する方向で開発を進めていて、非常に恩恵を感じています。
リアルタイム通信が不要なケースでも、MagicOnionのServiceを用いることで、
gRPCなAPIサーバーとして活用することができますし、
リアルタイム通信が必要なケースでも、KubernetesやAgonesを利用しない
ステートレスなリアルタイムサーバーの開発もサポートしているので、
通信プロトコルにgRPCを選択する場合、非常に強力な選択肢になると思います。
©Happy Elements K.K 119
MagicOnion
MagicOnionは、.NET標準のgRPCの拡張(いい感じのラッパー)なので、
MagicOnion特有の学習コストも低めでした。
言語的にもUnity(C#)と同じような感じでサーバーサイドを実装できる反面、
スレッドセーフな実装を心がける必要があります。
1から新しい言語やフレームワークを学習して開発するよりは、
Unity(C#)での言語的なテクニックや知見も活かしやすいと思いますが、
クライアントエンジニアがそのままサーバーサイドにシフトするには、
一般的なサーバーサイドの知識なども必要になるので、注意が必要かと思います。
©Happy Elements K.K 120
KubernetesやAgones
社内初のKubernetesを用いた開発でしたが、ステートフルなリアルタイム通信
環境を構築したい場合、Agonesも活用することで十分に恩恵を得られました。
1から自前でステートフルな環境を構築するより楽に開発できますが、
インフラチームのみでなく、開発チームもKubernetesやAgonesを含めた
インフラ関連の知識が必要になってくるので、学習コストは高めでした。
すべてを解決できる銀の弾丸ではないので、プロジェクトの要件や仕様に応じて、
どうしても泥臭く作り込みが必要になります。
©Happy Elements K.K 121
さいごに
運用7周年という長寿タイトルに対して、
リアルタイム通信環境を追加導入し、既存のサーバーとの
共存を目指した稀少な事例だと思いますが、
本セッションの情報・知見が、
皆様の今後のゲーム制作の一助となれば幸いです!
また、今回利用させていただいた数々の素晴らしいOSSの
発展に繋がれば幸いです!
[CEDEC 2021] 運用中タイトルでも怖くない! 『メルクストーリア』におけるハイパフォーマンス・ローコストなリアルタイム通信技術の導入事例

Contenu connexe

Tendances

世界でいちばんわかりやすいドメイン駆動設計
世界でいちばんわかりやすいドメイン駆動設計世界でいちばんわかりやすいドメイン駆動設計
世界でいちばんわかりやすいドメイン駆動設計増田 亨
 
Kubernetesのしくみ やさしく学ぶ 内部構造とアーキテクチャー
Kubernetesのしくみ やさしく学ぶ 内部構造とアーキテクチャーKubernetesのしくみ やさしく学ぶ 内部構造とアーキテクチャー
Kubernetesのしくみ やさしく学ぶ 内部構造とアーキテクチャーToru Makabe
 
Kubernetes環境に対する性能試験(Kubernetes Novice Tokyo #2 発表資料)
Kubernetes環境に対する性能試験(Kubernetes Novice Tokyo #2 発表資料)Kubernetes環境に対する性能試験(Kubernetes Novice Tokyo #2 発表資料)
Kubernetes環境に対する性能試験(Kubernetes Novice Tokyo #2 発表資料)NTT DATA Technology & Innovation
 
Dockerからcontainerdへの移行
Dockerからcontainerdへの移行Dockerからcontainerdへの移行
Dockerからcontainerdへの移行Kohei Tokunaga
 
「黒騎士と白の魔王」gRPCによるHTTP/2 - API, Streamingの実践
「黒騎士と白の魔王」gRPCによるHTTP/2 - API, Streamingの実践「黒騎士と白の魔王」gRPCによるHTTP/2 - API, Streamingの実践
「黒騎士と白の魔王」gRPCによるHTTP/2 - API, Streamingの実践Yoshifumi Kawai
 
AWSではじめるMLOps
AWSではじめるMLOpsAWSではじめるMLOps
AWSではじめるMLOpsMariOhbuchi
 
Building the Game Server both API and Realtime via c#
Building the Game Server both API and Realtime via c#Building the Game Server both API and Realtime via c#
Building the Game Server both API and Realtime via c#Yoshifumi Kawai
 
イベント・ソーシングを知る
イベント・ソーシングを知るイベント・ソーシングを知る
イベント・ソーシングを知るShuhei Fujita
 
BuildKitによる高速でセキュアなイメージビルド
BuildKitによる高速でセキュアなイメージビルドBuildKitによる高速でセキュアなイメージビルド
BuildKitによる高速でセキュアなイメージビルドAkihiro Suda
 
Azure API Management 俺的マニュアル
Azure API Management 俺的マニュアルAzure API Management 俺的マニュアル
Azure API Management 俺的マニュアル貴志 上坂
 
Google Cloud Game Servers 徹底入門 | 第 10 回 Google Cloud INSIDE Games & Apps Online
Google Cloud Game Servers 徹底入門 | 第 10 回 Google Cloud INSIDE Games & Apps OnlineGoogle Cloud Game Servers 徹底入門 | 第 10 回 Google Cloud INSIDE Games & Apps Online
Google Cloud Game Servers 徹底入門 | 第 10 回 Google Cloud INSIDE Games & Apps OnlineGoogle Cloud Platform - Japan
 
CEDEC2019 大規模モバイルゲーム運用におけるマスタデータ管理事例
CEDEC2019 大規模モバイルゲーム運用におけるマスタデータ管理事例CEDEC2019 大規模モバイルゲーム運用におけるマスタデータ管理事例
CEDEC2019 大規模モバイルゲーム運用におけるマスタデータ管理事例sairoutine
 
モノリスからマイクロサービスへの移行 ~ストラングラーパターンの検証~(Spring Fest 2020講演資料)
モノリスからマイクロサービスへの移行 ~ストラングラーパターンの検証~(Spring Fest 2020講演資料)モノリスからマイクロサービスへの移行 ~ストラングラーパターンの検証~(Spring Fest 2020講演資料)
モノリスからマイクロサービスへの移行 ~ストラングラーパターンの検証~(Spring Fest 2020講演資料)NTT DATA Technology & Innovation
 
コンテナ未経験新人が学ぶコンテナ技術入門
コンテナ未経験新人が学ぶコンテナ技術入門コンテナ未経験新人が学ぶコンテナ技術入門
コンテナ未経験新人が学ぶコンテナ技術入門Kohei Tokunaga
 
開発速度が速い #とは(LayerX社内資料)
開発速度が速い #とは(LayerX社内資料)開発速度が速い #とは(LayerX社内資料)
開発速度が速い #とは(LayerX社内資料)mosa siru
 
Dapr × Kubernetes ではじめるポータブルなマイクロサービス(CloudNative Days Tokyo 2020講演資料)
Dapr × Kubernetes ではじめるポータブルなマイクロサービス(CloudNative Days Tokyo 2020講演資料)Dapr × Kubernetes ではじめるポータブルなマイクロサービス(CloudNative Days Tokyo 2020講演資料)
Dapr × Kubernetes ではじめるポータブルなマイクロサービス(CloudNative Days Tokyo 2020講演資料)NTT DATA Technology & Innovation
 

Tendances (20)

At least onceってぶっちゃけ問題の先送りだったよね #kafkajp
At least onceってぶっちゃけ問題の先送りだったよね #kafkajpAt least onceってぶっちゃけ問題の先送りだったよね #kafkajp
At least onceってぶっちゃけ問題の先送りだったよね #kafkajp
 
世界でいちばんわかりやすいドメイン駆動設計
世界でいちばんわかりやすいドメイン駆動設計世界でいちばんわかりやすいドメイン駆動設計
世界でいちばんわかりやすいドメイン駆動設計
 
Kubernetesのしくみ やさしく学ぶ 内部構造とアーキテクチャー
Kubernetesのしくみ やさしく学ぶ 内部構造とアーキテクチャーKubernetesのしくみ やさしく学ぶ 内部構造とアーキテクチャー
Kubernetesのしくみ やさしく学ぶ 内部構造とアーキテクチャー
 
Kubernetes環境に対する性能試験(Kubernetes Novice Tokyo #2 発表資料)
Kubernetes環境に対する性能試験(Kubernetes Novice Tokyo #2 発表資料)Kubernetes環境に対する性能試験(Kubernetes Novice Tokyo #2 発表資料)
Kubernetes環境に対する性能試験(Kubernetes Novice Tokyo #2 発表資料)
 
分散トレーシング技術について(Open tracingやjaeger)
分散トレーシング技術について(Open tracingやjaeger)分散トレーシング技術について(Open tracingやjaeger)
分散トレーシング技術について(Open tracingやjaeger)
 
Google Cloud で実践する SRE
Google Cloud で実践する SRE  Google Cloud で実践する SRE
Google Cloud で実践する SRE
 
Dockerからcontainerdへの移行
Dockerからcontainerdへの移行Dockerからcontainerdへの移行
Dockerからcontainerdへの移行
 
「黒騎士と白の魔王」gRPCによるHTTP/2 - API, Streamingの実践
「黒騎士と白の魔王」gRPCによるHTTP/2 - API, Streamingの実践「黒騎士と白の魔王」gRPCによるHTTP/2 - API, Streamingの実践
「黒騎士と白の魔王」gRPCによるHTTP/2 - API, Streamingの実践
 
AWSではじめるMLOps
AWSではじめるMLOpsAWSではじめるMLOps
AWSではじめるMLOps
 
Building the Game Server both API and Realtime via c#
Building the Game Server both API and Realtime via c#Building the Game Server both API and Realtime via c#
Building the Game Server both API and Realtime via c#
 
イベント・ソーシングを知る
イベント・ソーシングを知るイベント・ソーシングを知る
イベント・ソーシングを知る
 
BuildKitによる高速でセキュアなイメージビルド
BuildKitによる高速でセキュアなイメージビルドBuildKitによる高速でセキュアなイメージビルド
BuildKitによる高速でセキュアなイメージビルド
 
Azure API Management 俺的マニュアル
Azure API Management 俺的マニュアルAzure API Management 俺的マニュアル
Azure API Management 俺的マニュアル
 
Google Cloud Game Servers 徹底入門 | 第 10 回 Google Cloud INSIDE Games & Apps Online
Google Cloud Game Servers 徹底入門 | 第 10 回 Google Cloud INSIDE Games & Apps OnlineGoogle Cloud Game Servers 徹底入門 | 第 10 回 Google Cloud INSIDE Games & Apps Online
Google Cloud Game Servers 徹底入門 | 第 10 回 Google Cloud INSIDE Games & Apps Online
 
CEDEC2019 大規模モバイルゲーム運用におけるマスタデータ管理事例
CEDEC2019 大規模モバイルゲーム運用におけるマスタデータ管理事例CEDEC2019 大規模モバイルゲーム運用におけるマスタデータ管理事例
CEDEC2019 大規模モバイルゲーム運用におけるマスタデータ管理事例
 
モノリスからマイクロサービスへの移行 ~ストラングラーパターンの検証~(Spring Fest 2020講演資料)
モノリスからマイクロサービスへの移行 ~ストラングラーパターンの検証~(Spring Fest 2020講演資料)モノリスからマイクロサービスへの移行 ~ストラングラーパターンの検証~(Spring Fest 2020講演資料)
モノリスからマイクロサービスへの移行 ~ストラングラーパターンの検証~(Spring Fest 2020講演資料)
 
コンテナ未経験新人が学ぶコンテナ技術入門
コンテナ未経験新人が学ぶコンテナ技術入門コンテナ未経験新人が学ぶコンテナ技術入門
コンテナ未経験新人が学ぶコンテナ技術入門
 
開発速度が速い #とは(LayerX社内資料)
開発速度が速い #とは(LayerX社内資料)開発速度が速い #とは(LayerX社内資料)
開発速度が速い #とは(LayerX社内資料)
 
Dapr × Kubernetes ではじめるポータブルなマイクロサービス(CloudNative Days Tokyo 2020講演資料)
Dapr × Kubernetes ではじめるポータブルなマイクロサービス(CloudNative Days Tokyo 2020講演資料)Dapr × Kubernetes ではじめるポータブルなマイクロサービス(CloudNative Days Tokyo 2020講演資料)
Dapr × Kubernetes ではじめるポータブルなマイクロサービス(CloudNative Days Tokyo 2020講演資料)
 
Docker Tokyo
Docker TokyoDocker Tokyo
Docker Tokyo
 

Similaire à [CEDEC 2021] 運用中タイトルでも怖くない! 『メルクストーリア』におけるハイパフォーマンス・ローコストなリアルタイム通信技術の導入事例

[OracleCodeTokyo2019] Kubernetesで実現する運用自動化の新しいアプローチとは
[OracleCodeTokyo2019] Kubernetesで実現する運用自動化の新しいアプローチとは[OracleCodeTokyo2019] Kubernetesで実現する運用自動化の新しいアプローチとは
[OracleCodeTokyo2019] Kubernetesで実現する運用自動化の新しいアプローチとはKoto Shigeru
 
5G時代のアプリケーションとは 〜 5G+MECを活用した低遅延アプリの実現へ 〜
5G時代のアプリケーションとは 〜 5G+MECを活用した低遅延アプリの実現へ 〜5G時代のアプリケーションとは 〜 5G+MECを活用した低遅延アプリの実現へ 〜
5G時代のアプリケーションとは 〜 5G+MECを活用した低遅延アプリの実現へ 〜VirtualTech Japan Inc.
 
AWS re:Inforce2019 re:Cap LT
AWS re:Inforce2019 re:Cap LTAWS re:Inforce2019 re:Cap LT
AWS re:Inforce2019 re:Cap LTHibino Hisashi
 
20180313 Amazon Container Services アップデート
20180313 Amazon Container Services アップデート20180313 Amazon Container Services アップデート
20180313 Amazon Container Services アップデートAmazon Web Services Japan
 
同じサービスを ECSとOpsWorksで 運用してみた
同じサービスをECSとOpsWorksで運用してみた同じサービスをECSとOpsWorksで運用してみた
同じサービスを ECSとOpsWorksで 運用してみたJun Ichikawa
 
Running Java Apps with Amazon EC2, AWS Elastic Beanstalk or Serverless
Running Java Apps with Amazon EC2, AWS Elastic Beanstalk or ServerlessRunning Java Apps with Amazon EC2, AWS Elastic Beanstalk or Serverless
Running Java Apps with Amazon EC2, AWS Elastic Beanstalk or ServerlessKeisuke Nishitani
 
Migrating tocloudnativeapplicationwithusingelasticapm
Migrating tocloudnativeapplicationwithusingelasticapmMigrating tocloudnativeapplicationwithusingelasticapm
Migrating tocloudnativeapplicationwithusingelasticapmShotaro Suzuki
 
OCP Meetup Tokyo #05 ECK on OCP
OCP Meetup Tokyo #05 ECK on OCPOCP Meetup Tokyo #05 ECK on OCP
OCP Meetup Tokyo #05 ECK on OCPTetsuya Sodo
 
Infra: Kubernetes and GKE, Network
Infra: Kubernetes and GKE, NetworkInfra: Kubernetes and GKE, Network
Infra: Kubernetes and GKE, NetworkKuma Arakawa
 
20210415 amazonelastickubernetesservice devops_game_development
20210415 amazonelastickubernetesservice devops_game_development20210415 amazonelastickubernetesservice devops_game_development
20210415 amazonelastickubernetesservice devops_game_developmentAmazon Web Services Japan
 
~ Cloud First から Cloud Optimized へ ~ .NET on Cloud が描くモダナイゼーション
~ Cloud First から Cloud Optimized へ ~ .NET on Cloud が描くモダナイゼーション~ Cloud First から Cloud Optimized へ ~ .NET on Cloud が描くモダナイゼーション
~ Cloud First から Cloud Optimized へ ~ .NET on Cloud が描くモダナイゼーションAkira Inoue
 
仮想通貨取引所 bitbank の IaC の導入と実践
仮想通貨取引所 bitbank の IaC の導入と実践 仮想通貨取引所 bitbank の IaC の導入と実践
仮想通貨取引所 bitbank の IaC の導入と実践 bitbank, Inc. Tokyo, Japan
 
ASP.NET 新時代に向けて ~ ASP.NET 5 / Visual Studio 2015 基礎解説
ASP.NET 新時代に向けて ~ ASP.NET 5 / Visual Studio 2015 基礎解説ASP.NET 新時代に向けて ~ ASP.NET 5 / Visual Studio 2015 基礎解説
ASP.NET 新時代に向けて ~ ASP.NET 5 / Visual Studio 2015 基礎解説Akira Inoue
 
[DevSumi2019]Cloud Native アプリケーションに最適!Oracle Cloud Infrastructureの魅力!
[DevSumi2019]Cloud Native アプリケーションに最適!Oracle Cloud Infrastructureの魅力![DevSumi2019]Cloud Native アプリケーションに最適!Oracle Cloud Infrastructureの魅力!
[DevSumi2019]Cloud Native アプリケーションに最適!Oracle Cloud Infrastructureの魅力!オラクルエンジニア通信
 
[Cloud OnAir] Anthos で実現する ハイブリッドクラウド 〜 Cloud Service Mesh 編 〜 2019年9月5日 放送
[Cloud OnAir] Anthos で実現する ハイブリッドクラウド 〜 Cloud Service Mesh 編 〜 2019年9月5日 放送[Cloud OnAir] Anthos で実現する ハイブリッドクラウド 〜 Cloud Service Mesh 編 〜 2019年9月5日 放送
[Cloud OnAir] Anthos で実現する ハイブリッドクラウド 〜 Cloud Service Mesh 編 〜 2019年9月5日 放送Google Cloud Platform - Japan
 
CI/CD Pipeline を考える 〜KubeCon 2017 + CyberAgent の最大公倍数〜
CI/CD Pipeline を考える 〜KubeCon 2017 + CyberAgent の最大公倍数〜CI/CD Pipeline を考える 〜KubeCon 2017 + CyberAgent の最大公倍数〜
CI/CD Pipeline を考える 〜KubeCon 2017 + CyberAgent の最大公倍数〜Masaya Aoyama
 
JCBの Payment as a Service 実現にむけたゼロベースの組織変革とテクニカル・イネーブラー(NTTデータ テクノロジーカンファレンス ...
JCBの Payment as a Service 実現にむけたゼロベースの組織変革とテクニカル・イネーブラー(NTTデータ テクノロジーカンファレンス ...JCBの Payment as a Service 実現にむけたゼロベースの組織変革とテクニカル・イネーブラー(NTTデータ テクノロジーカンファレンス ...
JCBの Payment as a Service 実現にむけたゼロベースの組織変革とテクニカル・イネーブラー(NTTデータ テクノロジーカンファレンス ...NTT DATA Technology & Innovation
 
Oracle Container Engine for Kubernetes (OKE) ご紹介 [2021年5月版]
Oracle Container Engine for Kubernetes (OKE) ご紹介 [2021年5月版]Oracle Container Engine for Kubernetes (OKE) ご紹介 [2021年5月版]
Oracle Container Engine for Kubernetes (OKE) ご紹介 [2021年5月版]オラクルエンジニア通信
 
"NAZE? NANI? CloudStack" on OSC Sendai 2011 / May 21 2011
"NAZE? NANI? CloudStack" on OSC Sendai 2011 / May 21 2011"NAZE? NANI? CloudStack" on OSC Sendai 2011 / May 21 2011
"NAZE? NANI? CloudStack" on OSC Sendai 2011 / May 21 2011Masahito Zembutsu
 

Similaire à [CEDEC 2021] 運用中タイトルでも怖くない! 『メルクストーリア』におけるハイパフォーマンス・ローコストなリアルタイム通信技術の導入事例 (20)

[OracleCodeTokyo2019] Kubernetesで実現する運用自動化の新しいアプローチとは
[OracleCodeTokyo2019] Kubernetesで実現する運用自動化の新しいアプローチとは[OracleCodeTokyo2019] Kubernetesで実現する運用自動化の新しいアプローチとは
[OracleCodeTokyo2019] Kubernetesで実現する運用自動化の新しいアプローチとは
 
5G時代のアプリケーションとは 〜 5G+MECを活用した低遅延アプリの実現へ 〜
5G時代のアプリケーションとは 〜 5G+MECを活用した低遅延アプリの実現へ 〜5G時代のアプリケーションとは 〜 5G+MECを活用した低遅延アプリの実現へ 〜
5G時代のアプリケーションとは 〜 5G+MECを活用した低遅延アプリの実現へ 〜
 
AWS re:Inforce2019 re:Cap LT
AWS re:Inforce2019 re:Cap LTAWS re:Inforce2019 re:Cap LT
AWS re:Inforce2019 re:Cap LT
 
20180313 Amazon Container Services アップデート
20180313 Amazon Container Services アップデート20180313 Amazon Container Services アップデート
20180313 Amazon Container Services アップデート
 
同じサービスを ECSとOpsWorksで 運用してみた
同じサービスをECSとOpsWorksで運用してみた同じサービスをECSとOpsWorksで運用してみた
同じサービスを ECSとOpsWorksで 運用してみた
 
Running Java Apps with Amazon EC2, AWS Elastic Beanstalk or Serverless
Running Java Apps with Amazon EC2, AWS Elastic Beanstalk or ServerlessRunning Java Apps with Amazon EC2, AWS Elastic Beanstalk or Serverless
Running Java Apps with Amazon EC2, AWS Elastic Beanstalk or Serverless
 
Migrating tocloudnativeapplicationwithusingelasticapm
Migrating tocloudnativeapplicationwithusingelasticapmMigrating tocloudnativeapplicationwithusingelasticapm
Migrating tocloudnativeapplicationwithusingelasticapm
 
OCP Meetup Tokyo #05 ECK on OCP
OCP Meetup Tokyo #05 ECK on OCPOCP Meetup Tokyo #05 ECK on OCP
OCP Meetup Tokyo #05 ECK on OCP
 
Amazon EC2 Container Service Deep dive
Amazon EC2 Container Service Deep diveAmazon EC2 Container Service Deep dive
Amazon EC2 Container Service Deep dive
 
Infra: Kubernetes and GKE, Network
Infra: Kubernetes and GKE, NetworkInfra: Kubernetes and GKE, Network
Infra: Kubernetes and GKE, Network
 
20210415 amazonelastickubernetesservice devops_game_development
20210415 amazonelastickubernetesservice devops_game_development20210415 amazonelastickubernetesservice devops_game_development
20210415 amazonelastickubernetesservice devops_game_development
 
~ Cloud First から Cloud Optimized へ ~ .NET on Cloud が描くモダナイゼーション
~ Cloud First から Cloud Optimized へ ~ .NET on Cloud が描くモダナイゼーション~ Cloud First から Cloud Optimized へ ~ .NET on Cloud が描くモダナイゼーション
~ Cloud First から Cloud Optimized へ ~ .NET on Cloud が描くモダナイゼーション
 
仮想通貨取引所 bitbank の IaC の導入と実践
仮想通貨取引所 bitbank の IaC の導入と実践 仮想通貨取引所 bitbank の IaC の導入と実践
仮想通貨取引所 bitbank の IaC の導入と実践
 
ASP.NET 新時代に向けて ~ ASP.NET 5 / Visual Studio 2015 基礎解説
ASP.NET 新時代に向けて ~ ASP.NET 5 / Visual Studio 2015 基礎解説ASP.NET 新時代に向けて ~ ASP.NET 5 / Visual Studio 2015 基礎解説
ASP.NET 新時代に向けて ~ ASP.NET 5 / Visual Studio 2015 基礎解説
 
[DevSumi2019]Cloud Native アプリケーションに最適!Oracle Cloud Infrastructureの魅力!
[DevSumi2019]Cloud Native アプリケーションに最適!Oracle Cloud Infrastructureの魅力![DevSumi2019]Cloud Native アプリケーションに最適!Oracle Cloud Infrastructureの魅力!
[DevSumi2019]Cloud Native アプリケーションに最適!Oracle Cloud Infrastructureの魅力!
 
[Cloud OnAir] Anthos で実現する ハイブリッドクラウド 〜 Cloud Service Mesh 編 〜 2019年9月5日 放送
[Cloud OnAir] Anthos で実現する ハイブリッドクラウド 〜 Cloud Service Mesh 編 〜 2019年9月5日 放送[Cloud OnAir] Anthos で実現する ハイブリッドクラウド 〜 Cloud Service Mesh 編 〜 2019年9月5日 放送
[Cloud OnAir] Anthos で実現する ハイブリッドクラウド 〜 Cloud Service Mesh 編 〜 2019年9月5日 放送
 
CI/CD Pipeline を考える 〜KubeCon 2017 + CyberAgent の最大公倍数〜
CI/CD Pipeline を考える 〜KubeCon 2017 + CyberAgent の最大公倍数〜CI/CD Pipeline を考える 〜KubeCon 2017 + CyberAgent の最大公倍数〜
CI/CD Pipeline を考える 〜KubeCon 2017 + CyberAgent の最大公倍数〜
 
JCBの Payment as a Service 実現にむけたゼロベースの組織変革とテクニカル・イネーブラー(NTTデータ テクノロジーカンファレンス ...
JCBの Payment as a Service 実現にむけたゼロベースの組織変革とテクニカル・イネーブラー(NTTデータ テクノロジーカンファレンス ...JCBの Payment as a Service 実現にむけたゼロベースの組織変革とテクニカル・イネーブラー(NTTデータ テクノロジーカンファレンス ...
JCBの Payment as a Service 実現にむけたゼロベースの組織変革とテクニカル・イネーブラー(NTTデータ テクノロジーカンファレンス ...
 
Oracle Container Engine for Kubernetes (OKE) ご紹介 [2021年5月版]
Oracle Container Engine for Kubernetes (OKE) ご紹介 [2021年5月版]Oracle Container Engine for Kubernetes (OKE) ご紹介 [2021年5月版]
Oracle Container Engine for Kubernetes (OKE) ご紹介 [2021年5月版]
 
"NAZE? NANI? CloudStack" on OSC Sendai 2011 / May 21 2011
"NAZE? NANI? CloudStack" on OSC Sendai 2011 / May 21 2011"NAZE? NANI? CloudStack" on OSC Sendai 2011 / May 21 2011
"NAZE? NANI? CloudStack" on OSC Sendai 2011 / May 21 2011
 

[CEDEC 2021] 運用中タイトルでも怖くない! 『メルクストーリア』におけるハイパフォーマンス・ローコストなリアルタイム通信技術の導入事例

  • 1.
  • 2. ©Happy Elements K.K 1 はじめに
  • 3. ©Happy Elements K.K 2 本セッションについて 本セッションは「写真撮影」「SNS拡散」OKです!
  • 4. ©Happy Elements K.K 3 セッション概要 今年7周年を迎えた『メルクストーリア – 癒術士と鐘の音色 –』において、 2021年3月にリアルタイム通信技術を用いた新機能をリリースしました! リアルタイム通信技術を用いた新機能の開発にあたり、 .NET(MagicOnion / gRPC)を用いたサーバーサイドC#をはじめ、 KubernetesやAgonesと言ったコンテナ技術も採用し、 社内でも初の試みとなる挑戦的な開発に取り組んできました。 今回は、メルクストーリアにおけるリアルタイム通信環境の開発や運用で 得られた知見について、導入事例のひとつとしてご紹介させていただきます!
  • 5. ©Happy Elements K.K 4 受講スキル / 得られる知見 ●受講スキル - ゲーム開発におけるリアルタイム通信技術に興味のある方。 - ゲーム開発におけるKubernetesやAgonesの利用に興味のある方。 - Unityと.NETを用いたC#でのゲーム開発に興味のある方。 ●得られる知見 - 運用中タイトルにリアルタイム通信技術を追加導入する知見。 - MagicOnion、Kubernetes、Agonesなどの開発や運用に関する知見。
  • 6. ©Happy Elements K.K 5 セッション目次 1. 自己紹介 / 会社紹介 / タイトル紹介 2. リアルタイム通信環境の導入経緯について 3. 採用技術について 4. 全体のアーキテクチャについて 5. 負荷試験やパフォーマンス改善について 6. ビルドやデプロイ、オートスケールについて 7. リリース当日の様子やリリース後の課題について 8. まとめ
  • 7. ©Happy Elements K.K 6 お詫び CEDEC公式サイトなどのセッションのご案内にて、 「既存サーバー(Ruby on Rails/オンプレミス)」という表記がございますが、 このオンプレミス環境は、現在クラウド環境への移行が完了しております。 本セッションでは、オンプレミス運用時の紹介も一部ご用意しておりますが、 最新の「既存サーバー(クラウド)」と「新規リアルタイムサーバー(クラウド)」を ベースにご紹介させていただきます。 予めご了承くださいますよう、お願い致します。
  • 8. ©Happy Elements K.K 7 自己紹介
  • 9. ©Happy Elements K.K 8 自己紹介 Happy Elements株式会社 メルクストーリアグループ エンジニア 岸本 直也 / Naoya Kishimoto 2019年にHappy Elements株式会社に入社。 メルクストーリアグループにてクライアントやサーバーの開発・運用を 担当しつつ、社内ライブラリの開発などの横断的な業務も行っています。
  • 10. ©Happy Elements K.K 9 自己紹介 Happy Elements株式会社 社長室 インフラチーム サブリーダー 長谷川 一輝 / Kazuki Hasegawa 2020年にHappy Elements株式会社に入社。 リアルタイム通信機能向けインフラ設計/構築/運用をAWSを利用して担当。 現在はインフラチームのサブリーダーとして、全タイトル横断的な業務も 行っています。
  • 11. ©Happy Elements K.K 10 会社紹介
  • 12. ©Happy Elements K.K 11 会社紹介 Happy Elements株式会社 MAKE THE WORLD HAPPY! 北京を拠点にアジア圏でゲームサービスを展開する Happy Elementsグループの日本子会社です。 『熱狂的に愛されるコンテンツをつくる』ことを ビジョンとし、京都のカカリアスタジオを拠点に オリジナルゲームの開発・運営を行っています。
  • 13. ©Happy Elements K.K 12 提供タイトル
  • 14. ©Happy Elements K.K 13 メルクストーリア – 癒術士と鐘の音色 –
  • 15. ©Happy Elements K.K 14 メルクストーリア – 癒術士と鐘の音色 – メフテルハーネという世界を舞台に 無気力少年と瓶詰め少女がモンスターを癒やす ラインストラテジーRPG 2021年1月に7周年を迎え、 1800を超える個性豊かなキャラクターと 涙を誘うものから熱血・ラブコメまで 心揺さぶる多彩なストーリーを楽しむことができます!
  • 16. ©Happy Elements K.K 15 メルクストーリア – 癒術士と鐘の音色 – ストーリーを楽しみながら遊べるラインストラテジーを中心に、 ギルドバトルをはじめ、協力して遊べるマルチプレイなど、 幅広いコンテンツを楽しむことができます!
  • 17. ©Happy Elements K.K 16 タイトルの課題
  • 18. ©Happy Elements K.K 17 タイトルの課題 ゲーム内チャット機能やイベントマップ上のキャラクター位置など、 ユーザー間のデータ同期はすべてポーリングで実現していて、 若干のタイムラグもあるためユーザー体験の低下に繋がっていました…。 ユーザー体験の改善に加えて、新しいコンテンツも追加したいし、 リアルタイム通信技術を活用することはできないか…?
  • 19. ©Happy Elements K.K 18 タイトルの課題 - ポーリングにも限界があり、もう少し体験を良くしたい…。 - オンプレミス(当時)は、これ以上の拡張が困難…。 - 各種バージョンアップができておらず、技術的負債も…。 現在は、オンプレミスからクラウドへの移行も完了しましたが、 計画当時の環境へのリアルタイム通信対応は難しいと判断しました。 また、社内の注目技術のひとつにgRPCが挙がっていたこともあり、 技術研究も含めて、新しくリアルタイム通信環境を構築できないか、 考えることになりました。
  • 20. ©Happy Elements K.K 19 タイトルのアップデート要件 - ギルド内でのコミュニケーション機能として、チャットやスタンプに加えて、 マップ上のキャラクター位置をリアルタイムで同期したい。 - 将来的にバトル(クエスト)を用いたリアルタイムレイドなどの 機能追加も考えている。
  • 21. ©Happy Elements K.K 20 技術的解決方法の模索
  • 22. ©Happy Elements K.K 21 技術選定 リアルタイム通信環境を構築する場合、WebSocketを利用したり、 Photonなどのサービスを利用する方法が考えられます。 一方で、社内の注目技術のひとつとしてgRPCが挙がっており、 技術研究としてgRPCを用いた開発ができないか考えました。 また、リアルタイム通信のデータ共有部分の設計として、 ステートレスな構成を選ぶかステートフルな構成を選ぶかも、 大きな問題となってきます。
  • 23. ©Happy Elements K.K 22 社内のリアルタイム通信事例【参考】 社内にはPhoton Cloudを用いたリアルタイム通信の実績がすでにあったり、 また、今回の開発と並行してNode.js(WebSocket)とRedis Streamsを活用した リアルタイム通信の導入を計画しているタイトルもありました。 Redis Streamsを用いたステートレスなリアルタイム通信環境は、 シンプルに構成することができて、スケーリングもしやすい一方で、 パフォーマンス面や料金コスト面で気にしないといけないこともあります。
  • 24. ©Happy Elements K.K 23 ステートレス?ステートフル? 今回はステートフルなリアルタイム通信環境を目指しました。
  • 25. ©Happy Elements K.K 24 ステートフルな理由 なぜステートフルなリアルタイム通信環境を目指したのか? まずはコミュニケーション機能での利用を目的としていますが、 将来的にリアルタイムレイドなどでの利用も予定しているため、 メルクストーリアのバトル(クエスト)を考えた場合、 インメモリでデータ共有することで、パフォーマンスも出しやすく、 同期部分の実装もシンプルにできるメリットがあると考えました。
  • 26. ©Happy Elements K.K 25 採用技術
  • 27. ©Happy Elements K.K 26 用語解説 本セッションでは、4種類のサーバーが登場します。 ●リアルタイムサーバー (.NET / C#) リアルタイム通信を担当するサーバー。 ●サービスディスカバリー (.NET / C#) クライアントとリアルタイムサーバーを仲介するサーバー。 ●メインサーバー (Ruby on Rails / Ruby) ゲーム用にメインで使用している既存のAPIサーバー。 ●管理画面 (.NET / C#) リアルタイム通信環境で内部的に使用できる管理用サーバー。
  • 28. ©Happy Elements K.K 27 チーム担当範囲 今回の開発は、チーム担当を決めて開発しました。 今回の開発では、インフラと深く関係するKubernetesが登場します。 開発チームとインフラチームで以下ような担当範囲を決めて開発しました。 ●開発チーム (メルクストーリアグループ) Kubernetesより上のレイヤーでタイトル要件に関連するものを担当 ●インフラチーム Kubernetesより下のレイヤーでクラウド環境に関連するものを担当
  • 29. ©Happy Elements K.K 28 採用技術 (リアルタイムサーバー / サービスディスカバリー / 管理画面) フレームワーク .NET 5.0 / C# 9.0 gRPC MagicOnion, Grpc.Core, Grpc.Net.Client など シリアライザー MessagePack for C# MySQL (Micro-ORM) Dapper Redis StackExchange.Redis Kubernetes KubernetesClient Telemetry prometheus-net, OpenTelemetry.Exporter.Zipkin その他 ZLogger, System.Reactive など
  • 30. ©Happy Elements K.K 29 採用技術 (クライアント) フレームワーク Unity 2018.4 / C# 7.3 gRPC MagicOnion, Grpc.Core など シリアライザー MessagePack for C# その他 UniTask など
  • 31. ©Happy Elements K.K 30 採用技術 (インフラ) Amazon Web Services Amazon Elastic Kubernetes Service (EKS) Amazon Elastic Compute Cloud (EC2) AWS Fargate Amazon Aurora (MySQL互換) Amazon ElastiCache (Redis) Amazon Elastic Container Registry (ECR) AWS CodePipeline AWS CodeBuild Amazon CloudWatch AWS Secrets Manager AWS WAF モニタリング Datadog その他 Terraform
  • 32. ©Happy Elements K.K 31 採用技術 (メインサーバー) 【参考】 フレームワーク Ruby on Rails 6.0 / Ruby 2.7 Amazon Web Services Amazon Elastic Container Service (ECS) Amazon Elastic Compute Cloud (EC2) Amazon Aurora (MySQL互換) Amazon ElastiCache (Redis / Memcached) Amazon Elastic Container Registry (ECR) AWS CodePipeline, AWS CodeBuild, AWS CodeDeploy Amazon CloudWatch AWS WAF
  • 33. ©Happy Elements K.K 32 MagicOnion 通信フレームワークにMagicOnionを採用しました!
  • 34. ©Happy Elements K.K 33 MagicOnion なぜMagicOnionを採用したのか? クライアントがUnity(C#)なことに加え、通信プロトコルにgRPCを選択した場合、 MagicOnionを採用することで、C#のみで完結できることに注目しました。 クライアント・サーバー間でのコード共有やIDE統一などが可能で、 それぞれが異なる言語での開発に比べて、多くのメリットがあると考えたため、 gRPCの通信フレームワークにMagicOnionを採用し、クライアントもサーバーも C#を用いたリアルタイム通信環境の実現を目指しました。 クライアントもサーバーもC#で大統一!
  • 35. ©Happy Elements K.K 34 Kubernetes + Agones KubernetesとAgonesを採用しました!
  • 36. ©Happy Elements K.K 35 Agones なぜAgonesを採用したのか? ステートフルなリアルタイム通信環境を自前で構築した場合、 サーバー管理やスケーリングなどで多くの課題を解決する必要があるため、 解決方法としてAgonesに注目しました。 Kubernetes自体は、ステートレスなサービス向けのシステムですが、 Agonesは、Kubernetesでゲーム用のステートフルなリアルタイム通信環境の 実現を目的に開発されており、KubernetesとAgonesを組み合わせることで、 今回の要件にマッチした環境が構築できると考え、採用しました。
  • 37. ©Happy Elements K.K 36 全体アーキテクチャ
  • 38. ©Happy Elements K.K 37 全体構成 AWSを利用して環境構築しました。
  • 39. ©Happy Elements K.K 38 サービスディスカバリー クライアントとリアルタイムサーバーを仲介するステートレスなサーバーです。 一般的なAPIサーバーと同じ扱いのため、ALBを経由しての接続となり、 ロードバランスしています。
  • 40. ©Happy Elements K.K 39 リアルタイムサーバー リアルタイム通信用の双方向通信をサポートするステートフルなサーバーです。 Agonesを利用することで、クライアントとサーバーを直結しています。
  • 41. ©Happy Elements K.K 40 環境間通信 【参考】 オンプレミス環境などでAPIサーバーを運用していて、リアルタイム通信を 追加で別環境に構築したい場合、データ共有などで環境間通信の必要があり、 メルクストーリアでは、VPCを跨いでAuroraに接続することで解決しています。 オンプレミス環境で運用していたときは、インターネットを介した環境間通信で 実現していましたが、ある程度のレイテンシが発生するため、注意が必要です。
  • 42. ©Happy Elements K.K 41 MagicOnionで実現できること
  • 43. ©Happy Elements K.K 42 MagicOnionで実現できること 単発と双方向のgRPC通信をサポートしています。 gRPCのUnaryCallに相当するServiceと、 gRPCのDuplexStreamingCallに相当するStreamingHubの2種類を使用できます。
  • 44. ©Happy Elements K.K 43 MagicOnionで実現できること
  • 45. ©Happy Elements K.K 44 Gitリポジトリとコード共有 今回は、クライアントとリアルタイム通信環境でGitリポジトリを分割しました。 クライアントとサーバーで共通利用するコードは、サーバー側をマスターとし、 MagicOnionやMessagePackのコード生成も含めて、Unityエディタ拡張で クライアント側のリポジトリにコード共有しています。
  • 46. ©Happy Elements K.K 45 MagicOnionでステートフルなリアルタイム通信 StreamingHubでは、Groupを用いることでチャットルームのような単位で グルーピングして、クライアントにブロードキャストすることができます。 データの管理・共有は、共通インスタンスを作成し、インメモリで処理します。 また、ステートレスな構成向けにMagicOnion.Redisを用いることで、 Redis Pub/Subを使ったデータ共有にも対応できます。
  • 47. ©Happy Elements K.K 46 メルクストーリアにおけるサービスディスカバリー MagicOnionのServiceを利用して実装しています。 ASP.NET Core標準のWebサーバーであるKestrelを複数起動することで、 公開用と内部用のホストを分割しています。
  • 48. ©Happy Elements K.K 47 メルクストーリアにおけるリアルタイムサーバー MagicOnionのStreamingHubとServiceを利用して実装しています。 ASP.NET Core標準のWebサーバーであるKestrelを複数起動することで、 公開用と内部用のホストを分割しています。
  • 49. ©Happy Elements K.K 48 Agonesで実現できること
  • 50. ©Happy Elements K.K 49 Agonesで実現できること KubernetesのPodを直接公開できる! 通常のKubernetesであれば、PodはService経由での公開となりますが、 AgonesではPodを直接インターネットに公開できます。
  • 51. ©Happy Elements K.K 50 Agonesで実現できること KubernetesのAPIでサーバー管理ができる! Podとしてリアルタイムサーバーを扱うことができるため、 KubernetesのAPIサーバーを介してサーバー管理ができます。
  • 52. ©Happy Elements K.K 51 Agonesで実現できること オートスケールできる! FleetAutoscalerを使用して、オートスケールも対応できます。
  • 53. ©Happy Elements K.K 52 Agones NodeExternalDNS (Alpha) メルクストーリアのリアルタイム通信では、IPv6ネイティブ対応していませんが、 iOSアプリケーションは、NAT64/DNS64環境下でのIPv6動作が求められるため、 これに対応する必要がありました。 Amazon EC2にはインスタンス毎にドメインを割り当てる機能があり、 これを利用したいと考えました。 (VPC DNSサポート/パブリックDNSホスト名機能) 一方で、リアルタイムサーバーの接続先アドレスをAgonesから取得した場合、 EC2(Node)のIPアドレスだけしか取得できず、 EC2のインスタンスドメインを直接取得できる振る舞いではありませんでした…。
  • 54. ©Happy Elements K.K 53 Agones NodeExternalDNS (Alpha) そこで、AgonesにNodeExternalDNSを実装しました! 従来は、AgonesからPod(GameServer)の情報を取得したときに、 ExtrenalIPのみが取得でき、NodeのExternalDNSの取得はできませんでした。 そこで、Agones側でExternalDNSを優先して取得するような機能追加とし、 NodeExternalDNSを実装しました! 現在Alpha版のため、FeatureGatesのNodeExternalDNSを有効化することで、 使用できるようになります。 https://github.com/googleforgames/agones/issues/1921
  • 55. ©Happy Elements K.K 54 Agonesだけでは実現できないこと
  • 56. ©Happy Elements K.K 55 Agonesだけでは実現できないこと 無制限に接続はできないので、ソフトリミットが必要です。 クライアントの接続に対して「コスト」の概念を導入して、 サーバー1台あたりのソフトリミットを管理しています。 (AgonesのFeatureGatesのPlayerTracking(Alpha)で同様のことができます。) ただし、一概に何人繋げるというわけではないので、ユースケースに応じた 負荷試験などで見極めが必要になります。
  • 57. ©Happy Elements K.K 56 Agonesだけでは実現できないこと 接続中のサーバーを停止できないので、注意が必要です。 Agonesは、KubernetesのライフサイクルからPodの保護をしてくれますが、 以下のような部分は作り込みが必要になります。 - デプロイなどをノーメンテナンスで実施する際は、 ユースケースに応じて対応が必要になります。 - チャットルームのような利用時間が不定の場合は、 複数のサーバーに接続が分散しがちで、リソースの効率的に利用した場合は、 定期的にデフラグやドレイニングなどの工夫が必要になります。
  • 58. ©Happy Elements K.K 57 Agonesだけでは実現できないこと Agonesを用いたリアルタイムサーバーは、直接インターネットに公開するため、 SSL通信を利用する場合、サーバーに対してSSL証明書の設定が必要になります。 今回は、AWS SecretsManagerでSSL証明書を管理し、 Kubernetes SecretでSSL証明書をPod(サーバー)にマウントすることで、 サーバー・クライアント間のSSL通信に対応しています。
  • 59. ©Happy Elements K.K 58 Agonesだけでは実現できないこと AWS SecretsManagerなどのクラウドサービスを活用することで、 Gitなどから機微情報を排除し、シークレットを安全に扱うことができます。 ただし、Kubernetes Secretを用いて実行環境にマウントする際は、 AWS SecretsManagerとKubernetes Secretの連携が必要となります。 今回は、環境構築バッチや管理画面から更新できるような仕組みを作り、 AWS SecretsManagerのAPIからシークレットを取得し、 Kubernetes Secretに変換することで対応しています。 今回利用していませんが、 Kubernetes SecretProviderClass(Aplha)を利用することで、 クラウドサービスとKubernetes Secretの連携も可能になっています。
  • 60. ©Happy Elements K.K 59 Kubernetes
  • 61. ©Happy Elements K.K 60 Kubernetes Amazon EKSを採用しました! KubernetesのマネージドサービスであるAmazon EKSを利用することで、 Kubernetesのコントロールプレーンの管理をしなくても良いことに加え、 他のAWSサービスとの連携や、EKS-Optimized AMIが公式から提供されている ことなど、マネージドサービスならではの多数の恩恵を受けています。 EKSの利用にあたり、ノード構成として以下の戦略を取りました。 - アプリケーションのPodは、EC2タイプのノードに配置する。 - クリティカルなPodは、Fargateタイプのノードに配置する。
  • 62. ©Happy Elements K.K 61 EKS EC2 サービスディスカバリーやリアルタイムサーバーなど、 リソースを大きく消費することが想定されるPodについては、 コスト効率に優れるEC2タイプをノードに配置しています。 また、EC2タイプのノードを採用した理由として、 社内にEC2運用のナレッジが存在している点も理由として挙げられました。 ただし、リアルタイムサーバーのようなステートフルなサーバーを扱う場合、 EC2のスポットインスタンスは回収されるリスクが存在するため、 EKSで利用しているEC2はすべてオンデマンド起動タイプを利用しています。
  • 63. ©Happy Elements K.K 62 EKS Fargate Agonesコントローラーのような、 クラスタ内でひとつしか起動できないクリティカルなPodで、 ほとんどリソースを消費しないPodについては、Fargateタイプのノードに 配置しています。 Fargateに対するリソース要求として、0.25 vCPU / 0.5GB Memoryのような 下限値の設定であっても、Agonesのコントローラー等で利用する分には、 十分なリソース設定であるため、料金コストも抑えられるメリットがあります。
  • 64. ©Happy Elements K.K 63 EKS EC2 + Fargate EC2タイプのノードにはまれにメンテナンスの必要があります。 - 脆弱性への対応のため、AMIを更新する必要があります。 - Datadog Agentなどのコンテナの外側で動作するアプリケーションを 更新する必要があります。 これらはすべて、AMIを再作成した後、 ノードのローリングアップデートを伴うオペレーションが発生します。 そこで、AgonesコントローラーのようなクリティカルなPodは、 Fargateタイプのノードに配置することで、EC2のメンテナンスから解放し、 EC2のメンテナンス時は、自分たちのアプリケーションのPodの都合だけを 考えればいいようにしています。
  • 65. ©Happy Elements K.K 64 ローカル開発環境
  • 66. ©Happy Elements K.K 65 ローカル開発環境 ローカル開発環境は、Minikubeを利用しています。 VM上で動作するMinikubeを利用することで、 クラウド環境に近いKubernetes環境を構築して、開発しています。 また、ローカルで稼働しているメインサーバーとの共存もできています。
  • 67. ©Happy Elements K.K 66 Telepresence Telepresenceを利用し、デバッグ実行しています。 VM内のMinikube環境に対して、Telepresenceを利用することで、 ローカルでのデバッグ実行ができるようにしています。 ただし、Deploymentのみ対応可能で、AgonesのFleetは非対応のため、 Fleetで管理しているリアルタイムサーバーをDeploymentでも起動できるように、 Telepresence動作時のみ、Agones関連の処理を差し替えています。
  • 68. ©Happy Elements K.K 67 KubernetesのYAML管理
  • 69. ©Happy Elements K.K 68 KubernetesのYAML管理 Kustomizeを利用し、環境毎に差分管理しています。 全環境共通となるベース定義を基に、環境毎にディレクトリを構成し、 差分でYAML管理しています。
  • 70. ©Happy Elements K.K 69 KubernetesのYAML管理 - Kustomizeを利用することで、環境別にYAMLを管理するよりは、 共通化しやすいですが、データベースの接続先など環境差分も必ずあるため、 思っているより共通化はむずかしいです。 - Agonesは、YAML(install.yaml)でのインストールも可能ですが、 Helmでのインストールが推奨となっています。 →今後Helmでのインストールに切り替え予定です。 - KustomizeやHelmなど、KubernetesのYAML管理方法はいくつかあるので、 プロジェクト規模や用途に応じて、扱いやすいものを選択すると良いです。
  • 71. ©Happy Elements K.K 70 direnvとkubeconfig direnvを利用し、環境毎のkubeconfigの切り替えています。 環境毎にクラスタ接続先となるkubeconfigの切り替えが必要になるため、 direnvを利用して、環境毎に切り替えています。 環境毎にディレクトリを構成するKustomizeとも相性が良く、 kubeconfigの切り替えを意識することなく、スムーズに作業ができています。
  • 72. ©Happy Elements K.K 71 ビルド
  • 73. ©Happy Elements K.K 72 ビルド CodeBuildでビルドし、ECRにイメージを保存しています。 .NETのベースイメージを基に、メルクストーリア専用のベースイメージを作成し、 サーバー単位でコンテナイメージをビルドしています。 開発環境は更新頻度が高いため、GitHubと連携して自動ビルドしています。
  • 74. ©Happy Elements K.K 73 専用ベースイメージについて 専用のベースイメージを作成している理由として、サービスディスカバリー、 リアルタイムサーバー、管理画面、バッチなど、複数のコンテナイメージを ビルドしますが、NuGetパッケージの復元に時間がかかるので、 .NETのベースイメージ上に必要なNuGetパッケージも含めたイメージを用意し、 それを基にアプリケーション用のコンテナイメージをビルドしています。 特にMinikubeでは、ビルド時間短縮の効果を発揮しています。
  • 75. ©Happy Elements K.K 74 デプロイ
  • 76. ©Happy Elements K.K 75 デプロイ (サービスディスカバリー) Deploymentを更新して、ローリングアップデートしています。 管理画面からECRのイメージの選択とデプロイバッチを起動することで、 Deploymentのimageのバージョンタグを更新し、アップデートしています。
  • 77. ©Happy Elements K.K 76 デプロイ (サービスディスカバリー) - ステートレスなサーバーなので、Deploymentのローリングアップデートを 利用して、Kubernetesの標準的なデプロイをしています。 - ただし、Kubernetes ServiceやAWS ALBなどのロードバランサーからの 切り離しは非同期となり、切り離し完了までトラフィックが流れるため、 PreStopにフックしたグレースフルシャットダウンを実行することで、 切り離し完了を待機しています。
  • 78. ©Happy Elements K.K 77 デプロイ (リアルタイムサーバー) Fleetを更新して、ローリングアップデートしています。 管理画面からECRのイメージの選択とデプロイバッチを起動することで、 Fleetのimageのバージョンタグを更新し、アップデートしています。
  • 79. ©Happy Elements K.K 78 デプロイバッチのフロー (リアルタイムサーバー) 1. Fleetのimageをパッチする。 旧バージョンでReadyなPodのローリングアップデートがはじまります。 AgonesのFeatureGatesのRollingUpdateOnReadyも利用できます。 2. 新バージョンのPodが1台以上起動するまで待機します。 3. 割当可能なリアルタイムサーバーのバージョン情報を更新します。 このタイミングで旧バージョンへの新規の接続割当を停止します。 4. 旧バージョンでAllocatedなPodを1台ずつグレースフルシャットダウンし、 接続中のユーザーのドレイニングしてから、サーバーを停止します。
  • 80. ©Happy Elements K.K 79 割当可能なリアルタイムサーバーのバージョン管理 サービスディスカバリーから接続割当先となるリアルタイムサーバーは、 デプロイでバージョンが変わるため、デプロイなどで新旧2バージョンの リアルタイムサーバーが共存するタイミングでは、 旧バージョンに新規の接続割当ができないように制御する必要があります。 今回は、割当可能なリアルタイムサーバーのバージョンは、 Redisに保持するようにし、デプロイバッチの中で更新して切り替えています。 サービスディスカバリーからの割当要求時に、 リアルタイムサーバー側で自身のバージョンとRedis保持のバージョンを比較し、 バージョン不一致の場合は、割当要求を拒否するようにしています。
  • 81. ©Happy Elements K.K 80 PreStopを用いたグレースフルシャットダウン Kubernetesのライフサイクル(PreStop)にフックすることで、 グレースフルシャットダウンの処理を実行しています。 サービスディスカバリーやリアルタイムサーバーにgRPC(MagicOnion)で PreStop用のインターフェイスを実装し、gRPC通信のできる簡単なコンソール アプリケーションを経由することで、PreStop-execでフックしています。
  • 82. ©Happy Elements K.K 81 グレースフルシャットダウンのフロー (サービスディスカバリー) 1. 内部的なサーバーステータスをStoppingに変更します。 2. ALB(TargetGroup)から切り離しを待機します。 3. gRPCホスト(Kestrel)を停止して、アプリケーションを終了します。 ステートレスなサーバーなので、アプリケーション的に特別な処理は不要ですが、 Kubernetes ServiceやAWS ALBからの切り離しを待機する必要があるため、 PreStopにフックしたグレースフルシャットダウンを実施しています。
  • 83. ©Happy Elements K.K 82 グレースフルシャットダウンのフロー (リアルタイムサーバー) 1. 内部的なサーバーステータスをStoppingに変更します。 このタイミングで、新規の接続割当を停止します。 2. 接続中のユーザーをドレイニングしていきます。 3. AgonesのShutdownを呼び出します。 4. gRPCホスト(Kestrel)を停止して、アプリケーションを終了します。 ステートフルなサーバーなので、新規の接続割当を停止したり、 接続中ユーザーのドレイニングが必要になるため、 PreStopにフックしたグレースフルシャットダウンを実施しています。
  • 84. ©Happy Elements K.K 83 デプロイまとめ - 今回は、AWSのAPIを活用したりKubernetesのAPIを活用して、 管理画面やデプロイバッチを作り込むことで、 通常のアップデートであれば、管理画面とデプロイバッチでお手軽に デプロイできるようにしています。 - ただし、GitHubで管理しているDeploymentやFleetのimageと 実環境のimageは差分が出るので要注意です。 - DeploymentやFleetのimage以外を更新するアップデートは、 ケースバイケースの対応になるので、kubectlで手作業しています。 - PreStopにフックして、グレースフルシャットダウンしています。
  • 85. ©Happy Elements K.K 84 オートスケール
  • 86. ©Happy Elements K.K 85 オートスケール (サービスディスカバリー) HorizontalPodAutoscalerを採用しました。 CPU負荷に応じて設定台数内でスケールするようにしています。
  • 87. ©Happy Elements K.K 86 オートスケール (リアルタイムサーバー) FleetAutoscalerを採用しました。 Agonesのステータス(ReadyやAllocatedなど)に応じて設定台数内で スケールするようにしています。
  • 88. ©Happy Elements K.K 87 リアルタイムサーバー(Fleet)のオートスケール戦略 AgonesのFleetAutoscalerでは、Agonesのステータスである 「未接続(Ready)」や「接続中(Allocated)」に応じてオートスケールします。 サーバー台数のみのオートスケールになるため、サーバー負荷に関しては、 コスト(ソフトリミット)で管理しています。 今回、ひとつのリアルタイムサーバーにコスト上限まで詰め込むようにしたため、 あえてサーバーを分散させずに、極力集中させることで、少ないサーバー台数に 収まるように工夫しています。
  • 89. ©Happy Elements K.K 88 デフラグ
  • 90. ©Happy Elements K.K 89 リアルタイムサーバーのデフラグ チャットルームのような利用時間が不定の場合、 極力サーバーを集中させるように工夫しても、時間経過につれて、 サーバー全体に接続が分散しがちで、リソース的な無駄が発生しがちです…。 Agonesは、数分〜数時間程度の短時間利用で使い捨てていく思想ですが、 長時間利用したり、ひとつのサーバーに詰め込むようなユースケースだと、 このあたりはいい感じにできません…。
  • 91. ©Happy Elements K.K 90 リアルタイムサーバーのデフラグ 接続の減る時間帯を利用して、日次バッチにてデフラグを実施しています。 デプロイと同じ要領で、稼働中のサーバーに対してドレイニングを実施し、 最低限の台数に収まるように、サーバーの再割当をしています。
  • 92. ©Happy Elements K.K 91 リアルタイムサーバーのデフラグまとめ - チャットルームのような利用時間が不定の場合、 接続のデフラグ機構を用意しておくことで、スケールインしやすく、 料金コストも抑えることができます。 - KubernetesのCronJobとしてバッチ運用することができます。 - インフラ作業などで明示的にドレイニングしたいときも利用できます。
  • 93. ©Happy Elements K.K 92 負荷試験
  • 94. ©Happy Elements K.K 93 負荷試験 負荷試験クライアントは、.NET(C#)で作成しました。
  • 95. ©Happy Elements K.K 94 負荷試験 社内標準の負荷試験クライアントは、Locust(Python)を使用していますが、 MagicOnionの特徴として、C#であればコード共有ができるため、 負荷試験クライアントも.NETのコンソールアプリケーションとして開発し、 負荷試験を実施しました。 (ただし、詳細な性能情報を取るには、別途APMが必要となります。) 負荷試験クライアントもKubernetesにPodとしてデプロイし、 負荷試験を実施しています。
  • 96. ©Happy Elements K.K 95 負荷試験シナリオ (最大同時接続数の確認) リアルタイムサーバー1台あたりの最大同時接続数を確認。 1RPS/ユーザーの負荷がかかるシナリオを作成し、 少しずつユーザー数(接続)を増やして、CPU負荷に対しての最大同時接続数を 確認しました。 この試験結果を基に、1ユーザー=コスト1とし、 リアルタイムサーバーのコスト上限(ソフトリミット)を確定しました。
  • 97. ©Happy Elements K.K 96 負荷試験シナリオ (シナリオテスト) 実際のユースケースに近い状況を確認。 1RPS/ユーザーの負荷に加えて、ギルド内のメンバーが段階的に接続・切断する ようなシナリオを作成し、実際のユースケースに近い状況の確認をしました。 また、コスト上限(ソフトリミット)に達したときの挙動確認や、 オートスケールの様子なども確認しました。
  • 98. ©Happy Elements K.K 97 負荷試験シナリオ (長時間稼働の確認) 長時間稼働時の状況を確認。 接続・切断を繰り返すようなシナリオを作成し、 24時間程度の長時間負荷を掛け続け、メモリなどのサーバーリソースが、 本番運用に耐えられることを確認しました。
  • 99. ©Happy Elements K.K 98 負荷試験で判明した問題点
  • 100. ©Happy Elements K.K 99 KubernetesのAPIサーバーの負荷問題 サービスディスカバリーからリアルタイムサーバーに接続する際に、 KubernetesのAPIサーバーに対して、Get(kubectl get pods相当)の通信を、 毎回リクエストしていましたが、負荷試験の接続数が増加するに比例して パフォーマンスが劣化しはじめました…。 毎回リクエストするのではなく、Watch(kubectl get pods -w相当)を利用し、 Kubernetesとリアルタイムに同期することで、解決しました。 KubernetesClientのWatcher<T>を活用することで、 様々なKubernetesオブジェクトを簡単にWatchできるようになりますが、 Watchは切断することがあるので、エラー時など必要に応じて、 自動再接続できるように対策しています。
  • 101. ©Happy Elements K.K 100 gRPCのChannelのリーク問題 サービスディスカバリーからリアルタイムサーバーのgRPC通信は、 Channelを再利用できるように内部でキャッシュしていましたが、 単純なコーディングミスでリークしていました…。 単純にコード修正することで解決しました。
  • 102. ©Happy Elements K.K 101 トレース(Zipkin)によるメモリ消費 トレース(Zipkin)を有効にしたまま負荷試験を実施した結果、 ストリーミング通信中の通信もすべてトレース対象となるため、 通信が終了するまでトレースが蓄積していき、メモリを消費していました…。 単純にトレースを無効にすることで解決しました。
  • 103. ©Happy Elements K.K 102 リリース当日の様子
  • 104. ©Happy Elements K.K 103 リリース当日 3月8日15時にリリースしました! 新バージョンのクライアントからのみ新機能に接続 できるようにしていたため、 メインサーバー含めてノーメンテナンスでリリースし、 トラブルもなく無事にリリースできました! ノーメンテナンス! ノートラブル!
  • 105. ©Happy Elements K.K 104 アクセス状況 (サービスディスカバリー ALBリクエスト数) ギルド関連の画面でリアルタイム通信環境に接続するため、 リリース直後から徐々に接続が増え始め、 18時30分のギルドバトル開始時に一度リクエストが増加しています。 22時30分のギルドバトル終了時にピークを迎えました。
  • 106. ©Happy Elements K.K 105 負荷状況 (CPU使用率) ギルドバトル時間帯は接続数も増えるため、CPU負荷も比例して増加しますが、 想定負荷に収まっており、問題ありませんでした。
  • 107. ©Happy Elements K.K 106 負荷状況 (メモリ使用量) サービスディスカバリーは、ほぼ一定値で推移しています。 リアルタイムサーバーは、接続数の増加に比例して、 メモリ使用量も増加していますが、想定負荷に収まっており、 問題ありませんでした。
  • 108. ©Happy Elements K.K 107 パフォーマンス状況 (サービスディスカバリー 平均レスポンスタイム) 平均20〜60ms程度でレスポンスできています。 リアルタイムサーバーとのサーバー間通信を行っていますが、 再接続時はキャッシュを活用することで、アクセスが集中する時間帯も パフォーマンス劣化なくレスポンスできています。
  • 109. ©Happy Elements K.K 108 パフォーマンス状況 (リアルタイムサーバー 平均レスポンスタイム) 平均0〜4ms程度でレスポンスできています。 初回接続時の通信などは、Redisへのアクセスもあるため、 数ms程度のレイテンシが発生していますが、 リアルタイム通信の要であるデータ共有の通信は、インメモリで完結するため、 ほぼゼロタイムでレスポンスできています。
  • 110. ©Happy Elements K.K 109 リリース後の課題
  • 111. ©Happy Elements K.K 110 課題1 (リアルタイムサーバーのコスト上限の調整) 負荷試験結果から設定していたコスト上限(ソフトリミット)に対して、 実際の負荷だとサーバーリソースに十分に余裕のある状況になりました。 元々過剰な負荷をかけた負荷試験結果を基準とした設定であったため、 実運用の負荷を踏まえて、コスト上限を再調整することで、 サーバーリソースを効率的に使えるように、フィッティングしました。 コスト上限の調整は、管理画面から動的に設定変更できるようにしています。
  • 112. ©Happy Elements K.K 111 課題2 (メトリクスの可視化) リアルタイムサーバー1台あたりの接続数やメソッド別レスポンスタイムなど、 APM標準では確認できないメトリクスを可視化しました。 .NETのアプリケーションサーバーからPrometheus形式でデータを出力し、 Datadogに統合しました。
  • 113. ©Happy Elements K.K 112 課題3 (外形監視の強化) Kubernetesのコントロールプレーンに障害が発生し、 外形監視やヘルスチェックに対してアプリケーションサーバーとしては、 応答できる状態でしたが、内部的には、Kubernetesのコントロールプレーンに アクセスができない状態だったため、サービス不能になりました。 (外形監視やヘルスチェックは、Healthyでした…。) 小規模なマイクロサービスとはいえ、サービス間の依存関係が多いため、 依存サービスとの疎通もチェックすることで、 外形監視やヘルスチェックでの障害監視を強化しました。
  • 114. ©Happy Elements K.K 113 Kubernetesバージョンアップ (今後の予定)
  • 115. ©Happy Elements K.K 114 Kubernetesバージョンアップ Kubernetesバージョンアップは、クラスタ切替で対応します。
  • 116. ©Happy Elements K.K 115 Kubernetesバージョンアップ - ALBのTargetGroupの切替でクラスタレベルのブルーグリーンデプロイと なるため、メンテナンスやダウンタイムなしでバージョンアップできます。 - ただし、新旧2バージョンのクラスタが必要なので、一時的に料金コストが 2倍になる点や、切替後でも旧バージョンのリアルタイムサーバーに接続が 残っているので、切替後にドレイニングなどの作業は必要になります。 - 内部確認用に新旧バージョン別のドメインを用意して、 明示的に新旧のそれぞれにアクセスできるようにしておくと便利です。 - Kubernetesはバージョンアップ頻度が高くEOLも短めのプロダクトのため、 バージョンアップと付き合っていく必要があり、一度走り出すと 止まれない点は注意が必要です。(塩漬けはできない!)
  • 117. ©Happy Elements K.K 116 まとめ
  • 118. ©Happy Elements K.K 117 開発を振り返って MagicOnionに加え、KubernetesやAgonesも活用することで、計画通りに ステートフルなリアルタイム通信環境を構築でき、ユーザー体験の改善や遊びの 幅を広げることができました。 メルクストーリアのように部分的な利用であれば、既存のAPIサーバーとの 共存も現実的で、すでに運用中のタイトルでも追加導入しやすいと思います。 インメモリのデータ共有でハイパフォーマンスなことに加え、非常に少ない サーバー台数で運用できており、ローコストな運用ができています。 ただし、まだあまり枯れていない技術が多かったため、内部実装を確認したり、 バグを踏むこともあり、泥臭い苦労も多かったです…。
  • 119. ©Happy Elements K.K 118 MagicOnion 社内初の.NETを用いたサーバーサイドC#の開発でしたが、Unity(C#)とも 相性が良く、言語の違いを意識することなく、クライアントとサーバーの 通信部分を非常にスムーズに開発を進めることができました。 現在開発中のリアルタイムレイドは、クライアントとサーバーでコアロジックの コードを共有する方向で開発を進めていて、非常に恩恵を感じています。 リアルタイム通信が不要なケースでも、MagicOnionのServiceを用いることで、 gRPCなAPIサーバーとして活用することができますし、 リアルタイム通信が必要なケースでも、KubernetesやAgonesを利用しない ステートレスなリアルタイムサーバーの開発もサポートしているので、 通信プロトコルにgRPCを選択する場合、非常に強力な選択肢になると思います。
  • 120. ©Happy Elements K.K 119 MagicOnion MagicOnionは、.NET標準のgRPCの拡張(いい感じのラッパー)なので、 MagicOnion特有の学習コストも低めでした。 言語的にもUnity(C#)と同じような感じでサーバーサイドを実装できる反面、 スレッドセーフな実装を心がける必要があります。 1から新しい言語やフレームワークを学習して開発するよりは、 Unity(C#)での言語的なテクニックや知見も活かしやすいと思いますが、 クライアントエンジニアがそのままサーバーサイドにシフトするには、 一般的なサーバーサイドの知識なども必要になるので、注意が必要かと思います。
  • 121. ©Happy Elements K.K 120 KubernetesやAgones 社内初のKubernetesを用いた開発でしたが、ステートフルなリアルタイム通信 環境を構築したい場合、Agonesも活用することで十分に恩恵を得られました。 1から自前でステートフルな環境を構築するより楽に開発できますが、 インフラチームのみでなく、開発チームもKubernetesやAgonesを含めた インフラ関連の知識が必要になってくるので、学習コストは高めでした。 すべてを解決できる銀の弾丸ではないので、プロジェクトの要件や仕様に応じて、 どうしても泥臭く作り込みが必要になります。
  • 122. ©Happy Elements K.K 121 さいごに 運用7周年という長寿タイトルに対して、 リアルタイム通信環境を追加導入し、既存のサーバーとの 共存を目指した稀少な事例だと思いますが、 本セッションの情報・知見が、 皆様の今後のゲーム制作の一助となれば幸いです! また、今回利用させていただいた数々の素晴らしいOSSの 発展に繋がれば幸いです!