DeNAエンジニアが語るGo言語活用事例

中島清貴氏:「新ゲームサーバ基盤TakashoでのGo言語活用事例の紹介」というタイトルで発表させていただきます。よろしくお願いします。

(会場拍手)

まず自己紹介から。中島清貴と申します。2016年にDeNAに新卒入社して、新卒4年目となります。入社1年目はキュレーション事業部でRailsを使ってライター管理ツールなどを作っていました。その翌年にゲーム事業部の共通基盤系の部署に異動して、Sakashoというゲームサーバ基盤の開発・運用をやっていました。

そして、今年の3月から、今回お話しするTakashoチームへとジョインしました。これまではずっとRubyを触っていたので、Go歴は4ヶ月ほどです。なのでお手柔らかにお願いします。

こちらが今日のアジェンダです。まず、Takashoについてお話しする前に、弊社DeNAのネイティブアプリゲームの開発事情について説明させていただきます。

弊社では複数のネイティブアプリゲームをリリースしていて、ここにある『逆転オセロニア』だったり『メギド72』以外にも、たくさんのゲームを運用中です。運用中のタイトルだけではなく新規のタイトルもたくさん開発中で、今後の成長戦略として、大型IPを活用したゲームを国内外にどんどん出していくということを掲げています。

Sakashoの仕組みと課題

現在運用中のタイトルの多くは、ちょうど今名前が挙がったSakashoというサーバ基盤システムの上で動いています。Sakashoは、ネイティブアプリゲームに必要なサーバ機能群を提供する共通ゲームサーバです。プレイヤーデータの管理機能や課金系機能、ログボ機能など、どのゲームでも必要な機能を提供しています。

複数のゲームタイトルが同一サーバに相乗りする構成になっていて、新規タイトルの新たなサーバが必要になったときに、簡単にサーバ環境を構築することができます。サーバの開発・運用は共通基盤チームが行います。

普通のゲームの構成は1対1のサーバなので、こういった共通ゲームサーバの構成は少し特殊ですが、ゲームサーバで必要なことをSakashoが一括で受け持つことで、各タイトルチームはクライアント側のゲームのおもしろさの実装に集中できるようになっています。複数タイトルを効率的にリリースできていて、安定した運用もできているので、手前味噌でありますが、Sakashoは一定の成功を収めたと言えます。

そんなSakashoにも課題があります。まず、タイトルチーム視点での課題としては、制約が強く自由度が小さいことが挙げられます。複数のタイトルが同じサーバを使っていて、開発と運用は共通基盤チームが行っているので、タイトル独自のサーバ機能を追加することは簡単ではありません。

また、現在のアプリゲーム市場の競争が激しくて、生き残るには尖ったゲーム性が必要となるので、今のSakashoの提供する汎用機能だけではハードルが高い。また、例えばサーバ障害などのサーバに関することは共通基盤チームとコミュニケーションをとって進める必要があるので、意思決定がタイトルチーム内で完結しないという問題もあります。

共通基盤チーム視点での課題としては、どんな変更でも直接的に全体に影響を与えうるため、サーバへ変更を加えることのハードルが比較的高くなってしまいます。また、常に先手を取って全体最適となる意思決定が必要となり、これがまた難しいです。

新ゲームサーバ基盤「Takasho」が誕生

これらの課題を解決する今後のDeNAのゲーム開発を支える新ゲームサーバ基盤が必要となり、Takashoが生まれました。ちなみにTakashoというネーミングですが、Sの次はTだろうということで、ちょっと安直なんですけれども、この名前になりました。ただSakashoとは思想的なところがけっこう違っているんですけど、名前が似ているので、Takashoを理解してもらうときにSakashoみたいなものだろうと勘違いされてしまうことがあるので、ちょっとだけ後悔しています。

余談はここまでにして、Takashoがどのようなものなのかについて説明させていただきます。Takashoは、ステートレスなAPIサーバを開発・運用するためのWebサーバフレームワークです。フレームワークというとRailsのようなフルスタックのものを想像されるかもしれませんが、かなり薄めのフレームワークで、どちらかというとライブラリ群というイメージをしていただいたほうがいいと思います。

各ゲームはTakasho Frameworkを取り込んで、各自サーバの開発・運用を行います。Sakashoは共通サーバという構成でしたが、Takashoは1サーバ1クライアントというシンプルな構成になっています。Webサーバフレームワークという形式をとっているので、ゲーム独自機能の追加も容易にできるようになっています。

Takashoで提供しているものとしては、まずWebサーバフレームワークであるTakasho Framework。そのTakasho Frameworkで作ったゲームサーバと通信するためのクライアントSDKであるTakasho SDKを提供しています。あとは、ゲームの運用に必要な機能を揃えたOpeツールを提供していて、ゲームの設定データの登録・更新を行うためのCLIツールや、その設定されているデータやプレイヤーデータなどを参照できる管理画面なども提供しています。

また、TakashoはGCPの上で動作することを前提としているので、1コマンドでGCP上にTakashoのサーバ環境を構築するインフラ構築・運用ツールを提供しています。これにはTerraformを使っています。

ほかにも、Sakashoで提供していたようなプレイヤーデータ管理機能やログボ機能・ガチャ機能など、どのゲームのサーバにも必要であろう汎用機能群をCommon Featuresetという名前で提供しています。

シンプルなサーバ機能のみ必要とするタイトルでは、このCommon Featuresetだけ利用して、それ以上のサーバ実装にはコストを割かない。クライアントの機能実装に集中するという選択もできるようになっています。

開発言語は、クライアント側はC#、サーバ側はすべてGoで実装しています。Goを選定した理由は、少ない学習コストで高いパフォーマンスと安定性が得られるからです。高負荷がかかるゲームサーバには高いパフォーマンスと安定性が求められます。

単純にパフォーマンスと安定性を考えるとC++やC#などのほうがいいのですが、タイトルチームも使う言語となることが想定されるので、できるだけゼロから学んだとしても学習コストを低く抑えられるものを選択したいという考えもあって、総合的に考えた結果、すべてのバランスが良かったGoを選定しました。

こちらがTakashoの構成となります。Webアプリケーションが動作をする環境としてはGAEを選んでいます。GAEの選定理由としては、スピンアップが超高速で急激なスパイクにも耐えられること。あとは、フルマネージドなので管理コストも少なく済むからです。

あとは、データベースにはCloud Spannerを使っています。ゲームは扱うデータが膨大で、とくにプレイヤーデータなどをシャーディングしないといけないのですが、MySQLなどでやろうとするとかなり大変です。Cloud Spannerはそのあたりのシャーディングを自動でやってくれるので、かなりゲームのデータベースに向いていると思って採用しました。

Takasho Frameworkの活用事例

次に、Takasho FrameworkでのGoの活用事例について紹介させていただきます。Takasho Frameworkは先ほど説明したように、ステートレスなAPIを開発するためのWebサーバフレームワークです。

Goのバージョンは1.12.3を使っていて、パッケージ管理ツールにはdepを使用しています。ちなみに、現在ちょうどdepからGo Modulesへの移行作業を行っていて、それが終わったら今後はGo Modulesを使っていくつもりです。

Goパッケージとして拡張フレームワークを提供していて、利用者にはgo getして使ってもらいます。提供機能としては、RPCサーバやCloud Spannerを使うためのライブラリ、Stackdriver、もしくは標準出力にログを出力するためのloggerだったり、コードの自動生成ツールなどを提供しています。

RPCサーバはサーバ・クライアント間の通信に使います。net/httpパッケージベースのRPCサーバで、protobufをIDLとして使用しています。APIエンドポイントのインターフェースはprotoスキーマで定義して、そのprotoスキーマからコードを自動生成できるようになっています。

protobufはprotocコマンドでの自動生成機能を提供していますが、プラグインで拡張することもできて、それを使って拡張独自の自動生成も行えるようになっています。要はgRPCのようなものを独自実装しているかたちになります。本当は純正のgRPCを使いたかったのですが、GAEではgRPCをサポートしていなくて使えなかったため、このようなかたちになっています。

protobufの自動生成についてですが、protobufはシリアライゼーションツールでもあるので、protoスキーマのコードをもとにシリアライズしたデータをサーバ・クライアント間でやりとりすることになります。protocコマンドを使うといろいろな言語のシリアライズ/デシリアライズコードを自動生成することができます。こういうprotoスキーマからこういうGoのコードを自動生成することができます。

そのprotocコマンドにはプラグインによる拡張機構が提供されています。処理の途中で外部プログラムを呼び出せるので、protoスキーマをprotocに渡して、protocがそれを解析。その解析結果を外部プログラムに渡して、この外部プログラムで何かしらの処理を実行し、最終的な実行結果を出力します。

プラグインを使った自動生成

Takashoでは、この仕組みを利用して、protocプラグインを作って、protoスキーマからいろいろなコードを自動生成しています。もちろんプラグインの実装で使っている言語もGoです。

go templateでこういうコードテンプレートを作って、protobufのメッセージを、中括弧で括られているところなどに埋め込んで、Goのコードを自動生成する感じです。

RPCサーバ関連で自動生成しているコードとしては、先ほどもあったシリアライズ/デシリアライズコード。これはサーバ側で使うGoのコードとクライアント側で使うC#のコードをそれぞれ自動生成しています。

また、RPCサーバのエンドポイントのインターフェースやルーティングなど実際のロジック部分を除くサーバAPIコードや、クライアント側でAPIにリクエストを行うためのC#のコードや、APIドキュメントのhtmlなども自動生成できます。

これらのコードはすべて同一のprotoスキーマから自動生成されます。なので、新たな機能を足すときは、protoスキーマさえ作ればほとんどのコードは自動生成されて、あとはロジックを書くことに集中できる状態なので、実装者の負担はかなり減らせるようになっています。

また、DBスキーマからテーブル作成したりコードを自動生成したりするツールも提供しています。テーブルのスキーマをこういう感じのjsonで定義すると、Spannerへのテーブル作成を行ったり、各テーブルに対する薄めのORマッパーを自動生成したり、その自動生成コードのテストコードなども自動生成できたりします。

これらの自動生成を駆使してTakasho Frameworkをベースにして作った機能群はFeaturesetと呼称しています。Takashoの提供物の1つである汎用機能群Common Featuresetも、Takasho Frameworkをベースにして作られたFeaturesetです。

複数のFeaturesetを組み合わせて使うことができます。例えばCommon FeaturesetのほかにGacha Featuresetというものがあったとして、この2つのFeaturesetをGame Featuresetというかたちで扱うことができます。

実装としてはけっこう単純で、TakashoのRPCサーバのエンドポイントは単純な関数の配列なので、Featuresetを組み合わせるときは各Featuresetの関数の配列をマージして、RPCサーバのルーティングに登録することができます。この操作も自動生成できるようになっていて、組み合わせたいFeaturesetを、あんな感じで配列で羅列しておいて、これを自動生成時に読ませて、コードが自動生成時に取りに行きます。

以上がTakashoでのGo活用事例でした。

Takashoの今後の展望

今後の展望とまとめです。Takashoは現在も絶賛開発中で、Takashoを使ったゲームのリリースが今後予定されているので、それに備えた開発を進めています。

直近ではGAEからGKEへの移行を検討しています。2回目になりますが、GAEではgRPCがサポートされていません。gRPCを使いたいモチベーションはけっこうTakashoとしては高くて、いつかGAEでもサポートされるだろうと思って待っていましたが、来る気配がないので思い切ってGKEへ移行することを検討しています。ただGAEに比べるとやはり管理コストが上がってしまうので、その点でまだ踏み切れていないという状態です。

そのほかに、本番運用に向けてツールやドキュメントを整備したり負荷試験をしたりなど、まだまだやることはたくさんある状態です。

最後にまとめです。

DeNAのネイティブアプリゲーム開発ではサーバ基盤としてSakashoが使われてきましたが、競争の激しいゲーム市場で今後も勝ち残っていくためには新たなゲームサーバの基盤が必要となり、Takashoが生まれました。

TakashoはWebサーバフレームワークという形式を採ることで、従来の共通サーバ型で難しかったタイトル固有の機能追加が容易にできるようになりました。Takasho Frameworkではスキーマファイルをもとにさまざまなコードの自動生成ができ、新たな機能を追加するときの負担も減らしています。

まだまだやることはたくさんありますが、本番リリースに向けてがんばっていきたいと思います。発表は以上となります。ご清聴ありがとうございました。

(会場拍手)