マスタデータ同期と運用効率化を実現する『真 戦国炎舞データベース』のバックエンド設計

alt_text

はじめに

こんにちは、株式会社サムザップで SRE を担当している友利です。

先日、『真 戦国炎舞データベース』をリリースしました。

本記事では、『真 戦国炎舞データベース』の開発背景や全体のアーキテクチャ、運用の効率化を実現するためのアプローチについてバックエンドの側面から紹介します。

サービス紹介

『真 戦国炎舞データベース』は、サムザップが運営するスマートフォン向けゲーム『真 戦国炎舞 -KIZNA-』(以下、戦国炎舞)のカードやスキル・奥義などの情報を横断的に検索、閲覧できる Web データベースです。

キーワードによるカード(大将、武将・智将)およびスキル・奥義の検索、複合条件によるフィルタリング、カードの基本情報や所有スキル、スキル詳細などを調べることができ、プレイヤーがより戦略的にゲームを楽しむための情報を提供しています。

サンプル画像01 サンプル画像02

サービス要件と前提

プロジェクト開始後に段階的に合意した要件や前提のうち、公開可能な範囲を抜粋して紹介します。

※ 記事向けの概要として、詳細は省略しています。

機能要件

  • 従前の公開サイト、ゲーム内検索機能で提供されていた検索条件と同等の体験を提供する
    • カードのキーワード検索や複合条件によるフィルタリング
    • スキルやスキル説明文のキーワード検索や複合条件によるフィルタリング
    • カード ↔ スキルの相互参照
  • 大将のキーワード検索や複合条件によるフィルタリングができる
  • カードの基本情報や所有スキル、スキル詳細などを閲覧できる
  • 運営側で定めたトピックスを掲載できる
  • 戦国炎舞のマスタデータの特定バージョンを一貫して反映し、そのバージョンに基づく検索結果を提供する

非機能要件

  • コスト:月次のインフラ費用に上限を設定(具体額は割愛)
  • 運用性:非エンジニア主導でデータの更新反映が完結する

前提 / 制約

  • 体制:小規模かつ兼務メンバーによる開発(実装者はフロントエンド1人、バックエンド1人の2人体制)
  • 更新頻度:戦国炎舞のマスタデータ更新は月に数回程度
  • データ:ユーザーデータは扱わない / マスタデータは CSV ファイルであり、戦国炎舞のサーバーリポジトリで管理

全体アーキテクチャ

こちらがサービス全体の構成図です。

全体アーキテクチャ

アプリケーションへの経路は CloudFront (VPC Origins) → internal ALB → ECS on Fargate となっており、画像や Web アセットファイルは CloudFront → S3 で配信しています。

データストアには SQLite を使用し、デプロイとマスタデータの同期は GitHub Actions ワークフローで自動化しています。

マスタデータの同期については後述します。

要件へのアプローチ

プロジェクトの立ち上げ当初から、次の2点が特に重視されていました。

  • 運用にかかるインフラ費用を抑えること
  • リリース後は非エンジニア主導で運用できること

この2点に対するアプローチを紹介します。

コストを抑えるための SQLite 採用

本サービスは読み取り特化・月数回のマスタデータ更新・マスタデータは数十のCSVファイルから成るという性質があり、非機能要件として月次のインフラ費用を一定の金額以内に収める方針がありました。

検索機能では全文検索や複合条件でのフィルタ、リレーションを扱いますが、書き込み操作は想定していません。

当初はマネージド RDB(RDS等)を含めて検討しましたが、固定費と運用の複雑さが要件に対して過剰と判断。参照中心・小規模・定期更新という前提に最も適合する選択として、単一ファイルで配布できる SQLite を採用しました。

代表クエリに効くカラムへ必要最低限のインデックスを付与することで、要求する検索性能を満たしています。

本サービスはユーザーからの書き込みがなく、運営の管理下のデータに対する読み込みのみを想定したサービスであるため、各タスクがローカルに独立した SQLite データベースファイルを持つ設計にしました。

これにより、ネットワーク越しの共有ストレージに対する I/O やロック競合を避けつつ、ランタイムの DB 固定費を実質ゼロに抑えることを実現しています。

各タスクが保有する SQLite データベースファイルをどのように戦国炎舞のマスタデータと同期させているのかは、後述の「ゲーム側のマスタデータと同期させる仕組み」で説明します。

ゲーム側のマスタデータと同期させる仕組み

『真 戦国炎舞データベース』は、次の理由から戦国炎舞のマスタデータを同期するための仕組みを新たに構築する必要がありました。

  • 戦国炎舞とは独立したサービスのため、ゲーム側のマスタデータを流用する既存の仕組みが無かった
  • 戦国炎舞のマスタデータ管理は RDB ベースではなく Key-Value 管理であり、既存リソースの流用だけでは要件を満たすことが困難だった

以下、① 生成と配布、② 参照(読み込み)の2ブロックにわけて説明します。

① SQLite データベースファイルの生成と配布

戦国炎舞のサーバーリポジトリで管理される複数の CSV ファイルをもとに、リリース版ごとの SQLite データベースファイルを生成し配布します。

  1. 戦国炎舞のサーバーリポジトリをクローンする(特定バージョンを指定)
  2. 対象 CSV ファイルのみ取り込む(Webで使うマスタをシンボリックリンク等で束ねる)
  3. DDL 適用でテーブル作成(空文字 / NULL の扱いを統一)
  4. CSV ファイルを読み込み、対応テーブルへ INSERT(型はテーブルスキーマ準拠)
  5. 生成した SQLite データベースファイルを S3 へアップロード( master/<version>/master.db など、リリース版を prefix 化)
  6. SSM Parameter Store の deploy_version を更新

こちらの処理は Go プログラム、シェルスクリプト で実装し、GitHub Actions ワークフローで環境と同期バージョンを指定して実行しています。

もともとは戦国炎舞サーバーのデプロイワークフローに組み込み、完全に自動化する想定でしたが、調整の結果、戦国炎舞のリリース手順に "『真 戦国炎舞データベース』のマスタデータ同期” の項目を追加し、手動でトリガーする運用に着地しました。

② SQLite データベースファイルの参照(ECS タスクでの読み込み)

API 用の ECS タスクは 2コンテナ構成(Init / API)で定義しています。

  • Init コンテナ
    1. 起動直後に SSM deploy_version を取得
    2. 対象版の SQLite データベースファイルを S3 からダウンロード
    3. タスクボリューム(ephemeral storage) に配置
  • API コンテナ
    1. 依存関係により Init 完了 → API 起動
    2. マウント済みパス(例:/data/master.db )から SQLite データベースファイルを開き、マスタデータをロード

この方式では、各タスクがローカルの SQLite データベースファイルを独立保持するため、共有ストレージ由来の I/O ボトルネックやロック競合を回避できます。

タスクの図を以下に示します。

前述した処理や構成を踏まえて、GitHub Actions ワークフローでは、SQLite データベースファイルの生成と配布、および ECS サービスのリフレッシュを実行し、イメージの再ビルドなしにマスタデータの更新ができるようになっています。

おわりに

本記事では、『真 戦国炎舞データベース』の開発背景、全体アーキテクチャ、運用の効率化を実現するためのアプローチをバックエンドの観点で紹介しました。

読み取り特化という前提のもと、SQLite の採用とマスタデータ同期システムにより、固定費と運用負荷を抑えつつ必要な機能を提供する構成を実現できました。

リリース後は、読み込みの短さや公式サイトならではの高解像度イラストを評価する声が寄せられており、開発チームとしても励みになっています。

今後も利用状況とニーズに応じて、機能追加や運用改善を継続します。


author
友利 拓誠

株式会社サイバーエージェント 2023年度新卒入社
株式会社サムザップ SRE
『呪術廻戦 ファントムパレード』『真 戦国炎舞データベース』などの開発・運用に従事