C++幼女先輩

プログラミング成分多め

2年前に開発したC++のリアルタイムゲームサーバ

はじめに

2年半ほどまえに、リアルタイム対戦ゲームの ソーシャルサーバとリアルタイムサーバの作成案件をもらった ソーシャルサーバは何度か作ったし余裕 リアルタイムサーバは、いわゆるMO的なゲームでロビーサーバを作ったり、レートでマッチングしたり、プレイヤーが落ちた時、復帰 と、考えることがいっぱいあったので 悩んだが 私なら何でも出来ると請けた

ソーシャルサーバはJavaPlayframeworkを使って問題なく設計したが リアルタイムサーバは C++で! という要望だった C++のりゆうは 速度が速い事と、運用会社が得意だからと

Windowsソケットとマルチスレッドを使った マルチスレッドパターンのライブラリをもらい 自由に使ってください との依頼だった

会社の資産をもらえ、それに沿って作れば簡単だし、責任もなすりつけられるので それでいこうと思ったが やはり 大量接続を考えると 非同期で行うほうが効率は良い それに もらったライブラリは、当然ながらデータアクセス部がMutexで同期をとり、明らかなボトルネックがあった そのため、ライブラリの提供は丁寧にお断りし Boost.ASIOで1から作る事にした

非同期I/Oを使うため、Mutexも不要。 明らかに高速で動く

現在の状況

半年ほどで私は開発を終わり、その後少し機能追加はしたものの、ゲーム側の不具合だらけで サーバを先にリリースして抜けた その後2年の歳月がながれ、いよいよクライアントの不具合も解消され リリースされた iphone無料ゲーム 最高20位と好調な滑り出しで そこそこアクセスがきているが ソーシャルサーバは Javaだけに速く、ほとんどスケールアウトもせず 安定稼働 リアルタイムサーバは なんと あまりにも速すぎて、MAXのピークがきても 負荷が0.0のままで変わらず 非常に安定しているとのこと

やはり C++で作ってよかった。予想では nodeで作った場合の100倍以上。PHPの5000倍ぐらいはパフォーマンス出ると思う

正直いうと、元から速かったので、最終的なチューニングも行ってないので、チューニングすれば3割以上は速くなると思うし 今作ると チューニングなしで3割速く作れると思う

設計

設計は リアルタイムサーバは余裕だった。 問題点は事前調査しきれないので、トライ&エラーだ ソーシャルサーバのほうはDB構成などあまり得意じゃないので 友達に作ってもらい、それを修正した

C10K問題というのがバズってたので、あくまで 非同期I/Oで処理することを考えた

非同期にはboost.asioを使用し、File I/Oや Redis その他のI/Oも非同期にした また、勉強もかねて C++11やboostを積極的に取り入れた

ルームへの復帰も簡単にできるよう、ルームの検索も高速になるよう、ルームリストとユーザーリスト作ってキャッシュさせる もちろん お互いの参照もあるのでWeakPtr使いつつ

非同期処理はコールバック地獄になるので、coroutineを使い簡略化した

当時 Earlangも気になっていたので、例外が起きたら例外を処理せず死ぬように作ったため、例外はシンプルになる もちろん 死ぬ前にルーム退出やAIへ自動的に変わるなど 後処理はあるけど 基本的に 何かエラーがあれば、コルーチンが死ぬという簡単な作りにした

その他、関数型言語ならい、参照透過性を意識して作った

苦労ポイント

ルーム

一番開発時に不具合が出た・・ 理由は shared_ptrを使い管理していたのだが 参照カウントが残ることが多かった プログラムのミスなんだけど、高速化のための List等に残っていたり・・ 逆にいえば Listからの消し忘れなどが shared_ptrを使っているために、簡単に発見できたといえる もし生ポインタ使っていれば、Listに無効なポインタが残って メモリリークをしていたかもしれない

タイムアウト

ASIOのタイムアウト処理が面倒だし、油断すると 無限に待ったりする タイムアウトの簡略化が課題

ほかプレイヤーの同期

例えば ゲームの開始など、全プレイヤーのOKの帰りを待つ必要があるが、そのあたりのSyncが難しい それに 麻雀ゲームという性質上、牌を切るごとに 全員の反応を待つ Syncが入る ので、それをライブラリ化したら 楽になった ただし 上記のタイムアウトと併用するので ややこしく・・ だが、このプロジェクトで最も頭を悩ませた問題だった・・・ 2週間ほど この部分で悩み、リアルに血を吐きかけた 逆に言えば ここをクリアしたらあとは力で勝負できたので楽だった

C#コードの移植

お客さんのC#コードの移植という作業があった が、お客さんのコードが Staticおじさんで、そのままでは複数プレイヤーに対応できないとか コードがあまりにも原始的だったり C#C++の違いだったり いろいろと苦労はしたけど 基本的には力業だった 逆に もっと苦労すると思っていたのだが、C++STLが予想以上に 高性能で、移植は楽だった

さいごに

WebサーバもC++で作ったし、C++は慣れた人が書くと、JavaC#で書くのと何も変わらない それでいて速度が100倍とか差が出るので 高速サーバには絶対おすすめ!

金額でいうとサーバコストが数十倍の単位で違ってくる