王者栄耀のバックエンド最適化：Proxy篇


テンセントゲーミングクラウドソリューションアーキテクトNelsonです。
王者栄耀は世界で最も人気のあるスマホゲームの一つであり、DAUは1億を超えている。膨大な数のプレイヤーをどのように捌くかは、王者栄耀のバックエンドアーキテクチャにとって大きな課題である。また、王者栄耀のPvPモードはルームやサーバに分割されていない。接続したサーバ、使用しているデバイス、そしてOSがiOSかアンドロイドかを問わず、PvPモードでマッチングされることが可能だ。バックエンドはロビーサーバとPvPサーバに分かれている。PvPサーバはCGIの呼び出しと似た運用になっており、リソースをその都度割り当て、使い終わったら回収し、ほかのタスクを担当することはない。必要なものはロビーサーバから受け取り、使い終わったらロビーサーバに返し、ロビーサーバがDBにライトバックすることになる。このような構成の場合、ロビーとPvPサーバの間でデータの中継が必要となり、そのための設備を王者栄耀では「Proxy」と呼んでいる。これはプロキシサーバに相当するものであり、多くのバックエンドプロセスのディテールをブロックすることができる。
このような構成のメリットは、ロビーサーバがバックエンドにどれだけのルームサーバがあるかを把握する必要がなく、アクセス可能なルームサーバがあることさえわかっていればよいという点だ。割り当てをどうするのか、ワークロードのバランスの取り方、バックエンドで生じたエラーをどのようにブロックするのかは、すべてProxyのルーティング機能が担当する。
しかし、プレイヤー数の急増により、マッチングのルールが複雑になり、Proxyのルーティング機能もそれだけ複雑になった。Proxy自体の信頼性と性能が、王者栄耀のバックエンドにとって非常に重要となってきたのである。そこで、本稿では王者栄耀が業務量の急拡大によって直面した課題と最適化に関する考え方を説明する。

王者栄耀のバックエンドアーキテクチャ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2096510/593768de-0b43-2d52-6b0e-9acd388d0129.png)
 
王者栄耀のバックエンドの特徴：
1.	運営上はプレイルームやサーバを分けているように見えるが、実際はすべてのルームとサーバ間の接続が可能。フレンド、チームメイトなどはすべて論理ボリューム間でデータ連携した形で運営され、gamesvr、roommatchとrelaysvrはリソースプールの形で運営される。
2.	物理サーバ間でのマッチングが可能。（例：スマホ版QQから登録したアンドロイドユーザーはiOSデバイスのフレンドと一緒にプレイできる）
3.	各サービスモジュールはグループとして存在し、オンラインでのスムーズな拡張が可能で、プロセス間のハートビート保守により、故障したノードを自動的にブロックする。
DAUとPCU（最大同時接続プレイヤー数）の増加に伴い、拡張を繰り返し行っている。PCUの上限を増やす際は、通常増加率に合わせてgamesvr（ロビーサーバのすべてのロジックを担当）とrelaysvr（フレーム同期バトルサービス）の機器を増設すればよく、論理ボリュームを増やす際も、それに対応したworldlogicsvr(論理ボリュームでの登録の制限などボリューム内のロジックを担当)とguildsvr（チームサービス）を増設すれば十分だった。このような拡張作業は長期に渡り安定していたが、ついに問題が起きるようになった。
ProxyのCPU問題と最適化
背景：
今年5月中旬の金曜日午後5時過ぎから、スマホ版QQアンドロイドエリアのProxyのCPU負荷が、90%強〜100%になる状況が発生した。
応急措置：
当該サーバのProxyの拡張を行った
応急処置の効果：
Proxyプロセスの1秒間のパケット量が処置前の3w+/sから2w8/sに減少したが、CPU負荷に顕著な軽減はなく、依然として90%以上の状態が続いた。

原因の分析：
 Perfの結果、Proxyの主な負荷がtbus_peek_msgにあることがわかった。これについてapollo担当の同僚に確認したところ、以下のことが判明した。tbusのメッセージ読み取りはchannelごとにポーリング方式で行われるが、王者栄耀のスマホQQアンドロイドエリアには850台以上のマシンがあり、SSメッセージハブとしてのProxyは、ほかのすべてのタイプのプロセスとメッセージ・チャネルを確立する必要があった。そのため、ピーク時の膨大なメッセージ量と大量のループによって、CPUの負荷が高騰した。

Proxyの最適化案：
主要な問題はメッセージ読み取り時に時間がかかりすぎることにあった。そこで、Proxyがスタート時に自身のスペックに合わせて、若干数の読み取りのみを行う子プロセスをforkで呼び出し、その後メインプロセスが書き込み転送のみを行うよう変更した。読み取りプロセスはtbusのchannelを均等に分割し、自分が担当するchannelのみを読み取る。読み取りプロセスと書き込みプロセス間の通信は共有メモリが実装したロックフリーキューを介して行う。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2096510/41588d23-9ad7-e586-e3a9-a90119a784d5.png)

 
Proxy最適化の効果：
対策後のCPU状況のスクリーンショット：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2096510/7c190833-4214-9fbd-348b-0fd729fb12ca.png)
 
現在使用中のProxyは6コアのサーバで、そのなかから読み取りプロセス4つを指定している。4つの読み取りプロセスのCPU負荷は10%前後、書き込みプロセスの負荷は5%前後である。
ProxyのCPU負荷問題は解決されたが、新たな問題が生じた。
Proxyメモリの最適化
Proxyの新たな問題
維持管理チームからProxyサーバのメモリ増設ができなくなり、今後スマホQQアンドロイドエリアが拡張不可との連絡が入った。
原因
Proxyはその他すべてのプロセスとメッセージ・チャネルを確立させる必要があり、gamesvrとrelaysvrを拡張することはtbusメモリの拡大につながる。しかし、Proxyのメモリはすでに40Gに近い。

当座をしのいでから最適化
現在のtbusチャネル容量をモニタリングした後、tbusチャネルのサイズを20Mから10Mに下げ、ひとまず拡張できる状態を確保した。

Proxyの構成の変更
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2096510/0896f1b7-3daf-fe0d-f085-71e424608846.png)

Proxyのボトルネックはメモリにあり、解決法はProxyをグループ分けすることだった。それぞれのグループがgamesvr、relaysvr及びその他すべてのプロセスの一部を担当する。Proxy同士で通信を行い、ターゲットのアドレスが自グループ内になければ、それを受け持つProxyグループに転送する。王者栄耀の現在の状況は、1グループに4台のProxyがあり、110台のgamesvrと250台のrelaysvrマシンを担当するというものだ。Proxyマシン1台あたりのメモリ使用は約32Gとなっている。拡張する際、グループ内のマシンに余裕があればまずグループ内で拡張し、余裕がなければグループを増やすことで対応する。この方法によりメモリ不足の問題も解決した。

Proxy最適化の総括
1.	今回のProxy最適化作業は、大量のプレイヤーへサービスを提供していく上で、「当座をしのいでから最適化する」という方針を体現したものである。
2.	ネットワークの現在の性能をモニタリングすることが重要である。そのことにより、問題点を早期に発見し、当座をしのぐ措置と最適化のための時間を確保することができる。