サイトアイコン cocone engineering

【cocone TECH TALK VOL6・前編】 リアルタイム対戦xバックエンドアーキテクチャ

こんにちは、新卒のCです。
2023年4月25日に開催された「cocone Tech Talk vol.6」では、弊社の3人の開発者がバックエンドに関するテーマについて発表しましたが、その内容を前・中・後編に分けてまとめていきたいと思います。
今回は前編として、戸丸さんの「リアルタイム対戦xバックエンドアーキテクチャ」について紹介させていただきます。

概要

まずは、発表のあらましについてお話したいと思います。
 

戸丸さんは、「リアルタイム対戦」を開発する間に経た試行錯誤についてご紹介してくださいました。特に、採用した通信方式の変化に注目していただければ幸いです!
 

リアルタイム通信をどの技術で実現するか


リアルタイム通信は、双方向通信を行うためのSocketやUnityなどのゲームエンジンが支援するマルチプレイヤーゲーム対応のパッケージ・gRPCのBidirectional Streaming RPCなどで実現することができます。選択肢が様々ですので、「サービス・ゲームデザインとしてはどうか」・「運用保守の面でどうか」・「UXとしてどうか」などの要素を考慮して通信方式を選ぶと良いですね。
 

採用した技術

今回の通信方式としてはgRPCを採用しました。
他のAPIが既にgRPCで実装されているので、リアルタイム通信も同じ技術で実装すると運用が容易になりますね。
 

 
ここで、gRPCは4種の通信方式に大別されるため、どの方式を採用するかをまた考える必要があります。

gRPCの4種の通信方式

 

初期に採用したのは…


4種の通信方式の中で最初に採用したのはBidirectional Streaming RPCです。リアル対戦が求めている双方向通信をそのまま選択するとなんとなく上手くいきそうですね。
 
以下の画像は、Bidirectional Streaming RPCの特徴についてまとめているスライドです。
 

 
しかし、実装の過程で次のような問題が発生しました。
 

 

 
例えば、「増え続けるoneof」の場合はClientとServerのmessageにRequest(Say, Foo, Bar, Echo)とResponse(SayResult, FooResult, BarResult, EchoResult)を追加していく必要があるため、コードが長くて見辛くなる問題がありました。
 

最終的な着地点

上記のような問題を解決するため、コードを複雑化するBidirectional Streaming RPCの代わりに、UnaryとServer Streaming RPC通信方式を目的に合わせて適宜使うように修正しました。
相手の操作情報を含むサーバーからの通知はServer Streaming RPCを、それ以外は1リクエスト/1レスポンスのUnary RPCを採用しました。
 

 
以下は、修正後の通信の関係図です。
 

 
例えば、ClientAがエモートを出す場合はUnary RPCでサーバーとの通信を行います。この際、サーバーではClientAがエモートを持っているかどうか等の検証および検証結果に応じた処理が行われます。ClientAがエモートを出したことをClientBに通知をするときはServer Streaming RPCが利用されます。
 
また、Redis PubSubを使い、サーバー間でのイベントの共有が可能となるようにしました。Redis PubSubとは、リアルタイムメッセージングが可能な機能で、受信する側が特定のチャンネルを購読(サブスクライブ)すると、発信する側はそのチャンネルにメッセージを送ることで、購読した全員にパブリッシュすることができる仕組みです。
 

 
上図の例では、ApServerAとApServerBが同じチャンネルをサブスクライブしているため、ApServerAでパブリッシュしたイベントの情報はRedis PubSubよりApServerBにも反映され、サーバー間でのイベント共有が可能となります。
 

通信方式の変更の結果

通信方式をBidirectional Streaming RPCからUnary RPC + Server Streaming RPCへ変更した結果、よりわかりやすいコードになりました。
 

 

苦労したポイント

実装の過程で以下のようなことに悩まされました。
 

 
ここで、「PubSubに悩まされた」について詳述します。

go-redisのPubSubでは基本1回のサブスクライブで1つのAPとRedisとのコネクションが発生しますが、もしサブスクライブしているユーザが1万人接続していたら、1万個のコネクションが発生してAPとRedis両方に多大な負荷を与えることになります。このような問題を解決するために、コネクションを一定数維持するようにして、1つのコネクションで複数のサブスクライブができるように仕組みを変えました。また、goのchannelを利用してAP間で共有されているイベントを各ユーザに送信するようにしました。
 

まとめ

 

スライド


 

新卒の所感

何もかもが新鮮で未知の世界に飛び込んだ感覚ですね!gRPCの通信方式やエッジケース、PubSub等わからない概念が出てきたらまず調べてみて、自分の理解が間違ってるかどうかを戸丸さんに確認していただきました(大変お世話になりました)。個人的には、試行錯誤を経て最善に辿り着くストーリーから感銘を受けました。また、今回コードの複雑化のため除外となったBidirectional Streaming RPCはどの場面で活用できるのかも気になりました。
 


 
中・後編の記事は下記リンクからお読みいただけます!
【cocone TECH TALK VOL6・中編】 ココネグループのブロックチェーン MOOI Network とのバックエンド連携
【cocone TECH TALK VOL.6・後編】Kotlin バックエンドアーキテクチャ of アバターサービス

ココネエンジニアリングでは一緒に働く仲間を募集中です。

ご興味のある方は、ぜひこちらのエンジニア採用サイトをご覧ください。

→ココネエンジニアリング株式会社エンジニアの求人一覧
モバイルバージョンを終了