First to Try, First to Fail, First to Recover
「誰ガ為のアルケミスト」では、サーバーサイド言語としてNode.jsが採用されている。Node.jsはサーバーサイドで動くJavaScript環境だ。シングルスレッド、ノンブロッキングI/Oによるデータ送受信、イベントループによる動作などの特徴を持つ。
「今から3年ほど前、gumiにおけるNode.jsでの開発実績はゼロでした。当社のサーバーサイドのコア言語はもともとPythonだったんです。ではなぜNode.jsが採用されたかというと、『Node.jsはイケてそうな言語だから』『話題になっているから取り入れてみよう』といった安直な理由でした(笑)」
こうした理由でも導入できたのは、同社の行動指針である「First to Try, First to Fail, First to Recover(誰よりも早く挑戦し、失敗し、そして復活する)」に起因している。つまり、新しい分野にチャレンジすることや、その経験から何かを学び取る姿勢が重要視されるということだ。
「とはいえ初期の頃は、Node.jsを用いて適切な開発ができていたとは言い難い状況でした。実装について振り返ると、まずデータベース周りについてはモデル化されていませんでした。ORMがなかったんです。また、XAトランザクション(分散トランザクション)も、マイグレーション関係の機能も未実装でした。当時のスクリプトを見ると、頑張ってALTER TABLE文を書いていた形跡がたくさん残っています」
さらに、サーバー周りについても当時はまだまだ多くの課題があったという。
「デプロイはファイルをSCP転送して、手動でプロセスをリスタートしていました。さらにNode.jsのデーモン化もできておらず、もしもプロセスが落ちたらそのまま死にっぱなし。Logに関しても、収集方法が実装されていませんでした」
こうした数多くの課題を、3年間の歩みのなかで改善し続けてきたのだという。この経験をもとに、的野氏は大規模システム開発における教訓を語った。
「たとえ最初はエンジニアの人数が少なかったとしても、開発が長期間になるにつれてどんどん増えていきます。コードの品質を安定化するため、早めにコーディング規約などを定めておいた方がいいでしょう。また、賛否両論はあるかもしれませんが、ORMを導入しておいて損はないと思います」
また、負荷分散について考えておくことは重要だという。当然ながら、アクセス量が多くなると1つのデータベースでは絶対に耐えられない。最初からスケールアウトやトランザクション整合性などを考慮したつくりにしておくべきだ。
「長期にわたって運用し続けることを念頭に置き、デプロイやマイグレーションの方法についても最適化しておきましょう」
大規模システムの運用においては、負荷試験が極めて重要になる
では、ゲームのリリース後からは、いったいどのような課題に直面してきたのだろうか。
まずリリース時の第一関門として、「DLCが遅い」という事態に見舞われた。DLCを動的に作成して配信するAssetSeverが高負荷になってしまったのだ。生成すべきコンテンツの組み合わせの種類が開発チームの想定以上となってしまい、CDNによるキャッシュヒットの効率が悪くなってしまったという。
「当然ながらサービスを維持できず、メンテナンスに突入しました。事象を解決するため、いくつかの対応をとりました」
まずAssetServerを増強し、400台まで増やした。キャッシュヒットの効率が悪い問題についても、想定される組み合わせのリクエストをあらかじめ投げておき、キャッシュを積んでおくことで解決。そして再リリースを行い、問題なくDLCが配信されるようになった。かかったメンテナンス時間は9時間半ほどになったという。
この経験をもとに、的野氏は2つ目の教訓を語った。「負荷試験をする際に専任の担当者をつけること」そして、「テストケースの検討を複数名で行うこと」だ。その工程を経て洗い出されたテストパターンや実施された負荷試験の結果は、リリース時に必要なリソースの参考値として信用に足るものになる。
次の大きな試練は、「誰ガ為のアルケミスト」が1周年を迎えたタイミングで訪れた。ゲームの大規模な改修が行われたのだ。負荷試験を実施し、AppServerもスケールアウトして準備は万端と思われたが、そうはならなかった。リリース後、徐々にアクセスができなくなっていく障害が発生したのだ。
原因はAppServerのスケールアウトの仕方にあった。サーバーを増やしすぎたため、RDSへのコネクション数の上限に達してしまい、それ以上接続できなくなってしまったのだ。これは、Node.jsの持つ特性に起因している。Node.jsはノンブロッキングI/Oの仕組みを用いているため、後続サーバーの受信可否にかかわらずリクエストを投げすぎてしまうのだ。
この事象を解決するため、「スケールアウトしたAppServerの台数を減らす」「RDS応答速度を上げるためAttributeを指定する」「リクエストピーク時のBatch処理を抑止する」などの対応をとり、障害を収束させた。
この経験をもとに、的野氏は3つ目の教訓を語った。
「大規模な改修があった場合は、必ず負荷試験をしましょう。そして、その結果を信じましょう」
また、本番環境においてどれくらいのレコード件数をデータベースから取得しているのか調べることも重要だ。2年目ともなると、ユーザー数も多くなり、アイテム数なども増加してくる。本番環境と同等のデータ量で負荷試験をしておかなければ、発生し得る問題を検出できなくなってしまう。
「そして、データ取得の際にはAttributeを指定して不要な項目を取得しないこと、キャッシュを有効活用してI/O負荷を減らしていくことなどを心がけてください」
「誰ガ為のアルケミスト」の3年の歩みにおいて、開発チームはいくつもの失敗を経験してきた。そして、その過程で数多くのノウハウを学びながら、運用を改善し続けてきたのだ。彼らの姿勢はまさに、「First to Try, First to Fail, First to Recover(誰よりも早く挑戦し、失敗し、そして復活する)」という同社の行動指針を体現していた。
お問い合わせ
株式会社gumi