Liberent-Dev’s blog

株式会社リベル・エンタテインメントのテックブログです。

BigQueryとデータポータルでデータ加工・可視化をする方法

f:id:Liberent-Dev:20220325121021p:plain

こんにちわ。 システム開発部ネットワーク課のsupercontinueです。

はじめに

ゲームサービスをより良いものにしていくためには、ユーザーの行動分析が必要です。

分析するためには、データを収集・加工・可視化(≒集計)する必要があります。

http://takano-plantuml-server.herokuapp.com/svg/SoWkIImgAStDuU8gpixCAqWiIinLoCtFoq_EAChFJLKeAIfDvUBIUDhVzt9scwQ2hfs2njEk1K-tBzNaWZ4WWlthNooRzhHdcYQNGsfU2j100000

  1. 収集

  2. 加工

    • 上記のログを、「1日間」や「新規登録者」や「購入額」などのような分析に適した加工をします。
  3. 可視化

    • 加工されたデータを表やグラフを使い、分析に適した表現で可視化します。
    • 今回はGoogleのデータポータルを使います。

http://takano-plantuml-server.herokuapp.com/svg/SoWkIImgAStDuU8gpixCAqWiIinLoCtFoq_EAChFJLKeAIfDvUBIUDoqwN7pdiVD2nutRGKp9Zzksgcfe6kdeE6KcHvOcbfKgSc5O88b7ZUtWvGsxN_SF1V6MAt9vP2QbmAq3m00

そもそも、何のために・何を・どう分析するのかが重要ですが、それについてはここでは触れません。

以下では、加工・可視化の工程例を説明します。

加工・可視化の工程

基本的な工程は下記となります。

  1. BigQueryでデータセットを作成・選択、加工したデータの結果を格納するテーブルを作成します。

    • BigQueryのUIで作成できます。
  2. データを加工・格納するクエリーを作成します。

  3. デイリーでの集計などのため、必要に応じてクエリーをスケジュールします。

    • BigQueryでクエリーのスケジュールを作成できます。
  4. データポータルでデータを可視化します。

BigQueryでデータを加工するクエリーの例

  • 下記の構成で説明をします。

    • my_project プロジェクト名
    • my_dataset データセット
    • app_log ログのテーブル名
    • jsonPayload.kpitype ログの種類を示すカラム
  • クエリーはBigQueryのSQLワークスペースのものです。

    • BigQueryのSQLワークスペースではクエリパラメータが使えません。
    • クエリパラメータを使いたい場合は他のプラットフォームを利用する必要があります。

DAU

  • DAU(Daily Active Users)は、その日にプレイした人の一覧で、人数の合計値は一般的なKPIの一つです。
  • DAU一覧は各種の分析を行うにあたり、ソースの1つとすることが多いテーブルです。

DAU一覧

  • 集計テーブルは下記です。
フィールド名 種類 説明
date DATE 年月日
uid INTEGER ユーザーID
ostype INTEGER AndroidiOSなどOS種類を示す数値
  • 前日のDAUを集計するクエリーは下記のようになります。
  • 以下の例では、jsonPayload.kpitype = 23 が、プレイしたユーザーのその日最初のログです。
  • タイムゾーンに注意する必要があります。ここではAsia/Tokyoで集計を行なっています。
  • 再試行しやすくするために、集計する直前に結果を格納するレコードを削除しておきます。 
DELETE FROM`my_project.my_dataset.dau` WHERE date = DATE_SUB(CURRENT_DATE("Asia/Tokyo"), INTERVAL 1 DAY);

INSERT INTO `my_project.my_dataset.dau`
 SELECT 
  DATE_SUB(CURRENT_DATE("Asia/Tokyo"), INTERVAL 1 DAY) AS date,
  labels.uid AS uid,
  CAST(jsonPayload.ostype AS INT64) AS ostype

 FROM `my_project.my_dataset.app_log`
  WHERE jsonPayload.kpitype = 23
   AND  DATE_SUB(CURRENT_DATE("Asia/Tokyo"), INTERVAL 1 DAY) =  DATE(timestamp, "Asia/Tokyo");

DAU合計

  • DAU合計値は参照する機会が多いので、あらかじめ算出しておきます。
  • OSの種類ごとに合計値を出します。
  • 集計テーブルは下記です。
フィールド名 種類 説明
date DATE 年月日
total INTEGER DAUの合計ユーザー数
ostype INTEGER AndroidiOSなどOS種類を示す数値
  • 集計済みの dau テーブルから算出します。
  • クエリーは下記のようになります。
DELETE FROM`my_project.my_dataset.dau_sum` WHERE date = DATE_SUB(CURRENT_DATE("Asia/Tokyo"), INTERVAL 1 DAY);

INSERT INTO `my-project.my_dataset.dau_sum`
 SELECT 
  DATE_SUB(CURRENT_DATE("Asia/Tokyo"), INTERVAL 1 DAY) AS date,
  COUNT(DISTINCT uid) AS total,
  ostype AS ostype
 FROM `my_project.my_dataset.dau`
  WHERE date = DATE_SUB(CURRENT_DATE("Asia/Tokyo"), INTERVAL 1 DAY)
 GROUP BY ostype
 ORDER BY ostype;

データポータルでデータを可視化する方法

基本的な流れ

  1. データポータルで「レポート」を作成します。 f:id:Liberent-Dev:20220325113531p:plain

  2. データソースを追加します。

    • 「データの追加」で、BigQueryを選び、データソースを追加します。
      • プロジェクト、データセット、表を選びます。
    • トップメニューにある「データソースの追加」からも行えます。 f:id:Liberent-Dev:20220325113722p:plain f:id:Liberent-Dev:20220325113754p:plain
  3. 表やグラフを追加します。

    • 「挿入」からグラフの種類を選びます。 f:id:Liberent-Dev:20220325114719p:plain

    • 下記のようなグラフが選べます。
      f:id:Liberent-Dev:20220325114827p:plain

    • 「データソース」を指定します。

    • 「ディメンジョン」、「指標」などを指定します。 f:id:Liberent-Dev:20220325115131p:plain:h512

データソースの扱い方

データポータルではデータソースを使い、データの集計・結合・フィルタなどが可能です。

表現したい内容に応じて、下記のいずれかの方法でデータソースを扱います。

  • 1つのデータソースの内容をそのまま使う。

    • 単純な一覧表、そのテーブルだけで集計できる値、集計済みの値のみを表示する場合です。
    • 例えば、下記のような日付ごとに集計済みのKPIをグラフで表示したいケースです。
      f:id:Liberent-Dev:20220325115529p:plain
  • 複数のデータソースを結合して使う。

    • 複数のデータソースを結合して、新たなデータソースを定義することができます。
    • 1つのグラフに複数のデータを表示させたい場合。
      • 例えば、同じ日付で、別々のデータ(DAUと継続日数分布など)を表示させたいケースです。
    • 表示用の文字列があるマスターデータを使い、値を文字列へ変換して表示したい場合。

      • 例えば、データソースにはキャラクター番号が入ってるが、表示するときはキャラクター名を使いたい場合などです。 f:id:Liberent-Dev:20220325115632p:plain
    • クエリーを実行せずに、複数のデータソースを使ってアドホックな分析をしたい場合。

      • 例えば、DAU一覧とプレイ日数一覧と行動数一覧があり、結合して分析をしたいケースです。
    • ただし、なるべくBigQueryで結合や加工した集計済みのテーブルを用意する方が、データポータルだけで頑張るよりも効率的と感じます。

グラフの扱い方

  • グラフは非常に多岐に渡り、設定する情報も多いため、それぞれ必要な時にやりかたを調べるのがいいです。

  • グラフのスタイルの調整が、最も時間を食います。 最初は見栄えに拘らない方がいいと思います。

  • エクセルなどに比べ、安全にインタラクティブなレポートを作れるのが、データポータルの強みです。

    • フィルタ機能やソート機能をうまく使えるようになると、レポートを見る側の利便性が上がります。
  • 「期間」のフィルタは、データポータルで扱いやすくなっており、DATEの列があれば、勝手に設定してくれます。

    • 指標ごとに「期間」の範囲で値を、「合計」するのか「平均」するのかなどを設定する必要があります。たとえば、「新規ユーザー数」は「合計」が適切ですし、「DAU」は「平均」が適切な場合と「最大」のほうが適切な場合があるかもしれません。
  • 下記にデータポータルのサンプルのレポート画面をあげます。 見栄えには少々手間をかける必要はありますが、このようなレポートが作れます。

f:id:Liberent-Dev:20220325120010p:plain

f:id:Liberent-Dev:20220325120043p:plain

おわりに

  • BigQueryとデータポータルを使用して、開発コストを抑えて、ゲームのログデータの可視化を行えます。

  • エクセルなどと異なり、期間や項目などをインタラクティブに変更できるレポートが比較的簡単にできます。

  • KPIのようなルーティーンのレポート閲覧であれば、これで充分・コスパが良さそうです。

  • データポータルと同様のサービスであるLookerについても、確認した方が良いでしょう。


リベル・エンタテインメントでは、このような最新技術などの取り組みに興味のある方を募集しています。もしご興味を持たれましたら下記サイトにアクセスしてみてください。 https://liberent.co.jp/recruit/

AmazonGameLiftを試してみた

こんにちわ!
システム開発部のK.Mです。

今までの記事とは少し趣を変えて、ゲーム実装部分に関する内容を紹介していきます。

近年、様々な形でリアルタイム通信を使ったゲームが増えてきているように感じます。
モバイル向けのゲームに関しては今後5Gが普及していけば通信環境が今より良くなり、リアルタイム通信を使ったものが、ますます増えてくるのではと個人的に考えています。

しかし、リアルタイム通信を最初から実装するとなると非常に大変なものとなります。
その大変なリアルタイム通信の実装をサポートするサービスが色々と存在しています。
有名どころであればPhotonやモノビット、MagicOnion、最近だとdiarkis等があったりしますが、サービスによってどこまで担ってくれるかが微妙に異なっており、利用する場合はゲームの仕様の性質に応じて検討することをお勧めします。

今回は触る機会がありました、AWSが提供しているGameLiftというサービスを使い、 簡単な実装例を交えて紹介していきます。

GameLiftとは?

Amazonが提供しているAWS内の1サービスとなります。
GameLiftにはユーザー側で実装を全て行うカスタムサーバ機能と一部の実装だけを行うリアルタイムサーバ機能の2つが用意されています。
GameLift内に内包されている機能でFleetIQなどが独自して存在しておりますが、今回はGameLiftのリアルタイムサーバ機能の話にフォーカスしています。

また、今回後述するAmazonが用意している導入手順ではリアルタイムサーバ機能での手順のため、この記事内もリアルタイムサーバでの手順となります。

リアルタイムサーバ機能ですが、サーバ側の実装に必要な処理はJavaScriptで記載してサーバに配置する形となります。
Unity側の通信周りの実装はAWSにて用意されているSDKを使うことで実装出来ます。

今回対象外になるカスタムサーバ機能ですが、C#C++が使えるので複雑で高度なオンラインゲーム(MMOなど)であれば、
こちらを利用するのがベストです。

確認環境

  • MacOS 10.15.7
  • VisualStudio for Mac 8.10.7
  • Unity 2019.3.4f1

ローカルで動く対戦ゲームを作る

ここがメインの話では無いので詳しい説明は省きますが、まずはUnityで下記のようなゲームを作ります。
Unityだと当たり判定が簡単に出来るので楽ですね!

  • スペースキーを押してから離すと心ちゃんが前進
    • 必然的にボタンの連打が必要になり簡単なものだがゲームしてる感を出すようにしました
  • 同じようにエンターキーを押してから離すと桃助が前進
  • 上下移動しているカメロンパンに接触している間は前進不可
  • 画面左のクマ校長が居る場所まで移動したらゴール

f:id:Liberent-Dev:20220217162442g:plain 出来上がったものです。

続きを読む

Qwiklabsで学習しよう

Qwiklabsで学習しよう

はじめに

こんにちは。 システム開発部のこたつみかんと申します。

オンプレミスからクラウドへの移行が進むにつれ、サーバサイドの学習をどのように行うかについては皆さん悩みどころかと思います。

通常パブリッククラウドサービスの学習を行うためには実際にサービスを利用するのが最もわかりやすいとされ、そのような解説記事も多く出ています。

一方、コスト意識の高い企業が多い中で、操作をほんの少し間違えることで意図しない費用が発生してしまうリスクを考慮すると、新サービスを試しに使うことを躊躇してしまったことのある方は少なくないと思います。

本記事では、上記のような問題に対して低コスト、もしくは固定コストでクラウドサービスについて学習のできるQwiklabsについて紹介していきます。

Qwiklabs とは

Qwiklabsは実際の環境を使いながらクラウドについて学ぶことのできるeラーニングサービスです。

ここではGCPの導入的なクエストである「Google Cloud Essencials」を実行しながらサービスについて説明していきます。

まず、Qwiklabsのホーム画面に移動します。

f:id:Liberent-Dev:20220126114707p:plain
Qwiklabsのホーム画面

ここで「クエスト」と「ラボ」という用語が登場します。 これはQwiklabsのサービスの構成単位となります。

サービスの構成

  • ラボ
    • Qwiklabsでの最も細かい課題の単位になります
    • 無料のものと有料のものがあります。有料のものは規定のクレジットを支払うことで一回ラボを開始できます
    • ラボには目標が設定されています。ラボ内には目標を達成するためのチェックポイントがあり、いずれかの方法で達成できます
      • 択一の設問に正解する
      • ラボで開いたコンソール内で規定の機能を実行する
    • 制限時間が設定されていて、時間内にすべてのチェックポイントを達成するとラボを完了できます。
      • 制限時間はラボにとって異なります。概ね30分〜1時間です。
  • エス
    • 学習のためにいくつかのラボを組み合わせた一連の構成をクエストと呼びます
    • エスト内の一定のラボを達成することでクエストを完了できます
    • エストを完了するとバッジを入手できます

では「Google Cloud Essencials」を選びます。

f:id:Liberent-Dev:20220126114854p:plain
エストのトップページ
こちらは既にクエストをクリアしたもので、バッジが取得されています。
また、クリアしたラボにはチェックマークが入っています。
試しに一番初めのラボを選んでみます。
f:id:Liberent-Dev:20220126115037p:plain
ラボの画面
こちらがラボの画面になります。
左上の「ラボを開始」を選ぶと開始します。
このラボは無料なので早速押してみましょう。
f:id:Liberent-Dev:20220126115255p:plain
ラボを開始した画面
ボタンの色が変わってタイマーが動き始めたのがわかります。
また、必要であれば「Google Consoleを開く」を選ぶことで本物のGCP環境にアクセスできます。
利用するためのアカウント情報はその下に表示されています。
このアカウント情報はワンタイムのものになっています。

また、表示されている画面は目標の最後にある「理解度チェック」になります。
設問に正解することで次の目標に移り、最後まで進めることでラボをクリアできます。

ここで選んだラボは無料でしたが、その次のラボには「クレジット:1」と書いてありました。
このラボを進めるためにはクレジットを購入する必要があります。

課金システム

有料コンテンツの課金方法は以下の2種類です。

  • クレジット購入
    • 基本の方式。1クレジット=1$で8クレジットから。
    • 40クレジット以上同時に購入すると割引があります
  • Advantageサブスクリプション
    • 期間内はクレジットを消費せずにすべての有料ラボを利用可能
    • 月間プラン:$55/月
    • 年間プラン:$495/年

課題の紹介

私が実際に選んでみてよかったクエストがありますので、その印象についてご紹介します。

  • Insight from Data with BigQuery
    • BigQueryを使ったデータの処理についてのクエストです
    • 実際のオープンデータを使って学ぶので、データの応用について想像しやすかったです
    • このクエストの最後のラボは通常のラボより難易度が上がっていて、クリアした時の達成感がうれしいです

その他いくつかおすすめのクエストをご紹介します。

  • G Suite Essentials
    • Google Workspaceを初めて使うスタッフの教育に最適のクエストです
    • 最後のラボは未翻訳なのでご注意ください。これを抜いて進めても問題ないです
  • Google Cloud Essentials
    • 先程の画面です
    • 初めてGCPに触れるエンジニアの教育として最適のクエストです

ここまでざっくりとQwiklabsのサービスについて説明してきました。
ここでQwiklabsを実際に使ってみてここはいいなと思う部分とちょっと工夫する必要があるなと思った部分について紹介していきます。

メリット

  • 本物のクラウドの環境が使える
    • 自分で試しに環境を作るより安く色々なサービスを試せます
    • 現在日本語に対応しているのはGCP,AWSです
  • 無料のラボがたくさんある
    • 試したことのないサービスの内容をかじるには最適です
  • 学習目標を設定しやすい
    • 習得したいサービスに対して必要なラボをまとめたクエストが構成されているので学習を進めやすいです
    • エストのバッジが履修確認になるのでわかりやすいです
  • 理解するまで置いていかれない
    • 各ステップの次に進行するためにはコンソールでの実操作が必要なので、通常の座学より理解度が高いです
    • 操作を間違えても正しい結果にたどり着くまで待っていてくれるので焦る必要がありません
  • 資格試験対策になる
    • Googleの資格試験における標準学習環境として提示されています
    • チャレンジラボはケーススタディになっており、実際の問題解決と同じような形で実力をつけることが可能です

デメリットと対策

  • 好き勝手に環境を作ることはできない
    • ラボの問題解決が目的なので、それ以外のことはできません
  • 時間切れになるとラボが強制終了する
    • クレジットを買うとやり直しが効かないので再履修を繰り返すと最終的に高価になってしまいます
    • 対策としてはサブスクリプションがおすすめです。決められた期間内にできるだけ色々なものを試すとコスパが高くなると思います
  • 課題の解決に英語力が必要
    • 基となるデータセットが全て英語で構成されていて、かつ普段扱っている分野と別のものであるため、見たことのない単語を見かけることがしばしばあります
    • ラボは日本語のものを選べば翻訳済みなのですが、サービス特有の技術用語はそのままカタカナ化されているのでテキストを噛み砕いて読む必要があります

まとめ

Qwiklabsは導入部から深い学習まで可能なクラウド向けのeラーニングサービスです。
実際に様々なサービスを業務に投入する前にここで学ぶことで問題解決能力を上げ、実力をつけてから業務に臨むことができるので、ぜひ一度試してみてください。


リベル・エンタテインメントでは、このような最新技術などの取り組みに興味のある方を募集しています。
もしご興味を持たれましたら下記サイトにアクセスしてみてください。
https://liberent.co.jp/recruit/

ゲームのデータをBigQueryにインポートする方法

f:id:Liberent-Dev:20211210161913p:plain

こんにちわ。 システム開発部ネットワーク課のsupercontinueです。

はじめに

http://takano-plantuml-server.herokuapp.com/svg/SoWkIImgAStDuU8gpixCAqWiIinLoCtFoq_EAChFJLKeAIfDvUBYqdZSFEznqyx7JViVD-zvtDmE8flsQohewjefQ3XbfWUMfXPLQeBLBGFBRGEHZUiUD-q6QvX6WfuN2tkUTazzkd7fixLRC5Kx9fVa5ocW22fOARoStVPYHSVZvjrFEzgUpPl0vP2QbmBq5000

ゲームのサービスを運営する上で、ユーザーの行動データを集計・分析する必要があります。

集計・分析するプラットフォームとして、Google Cloud の BigQuery は一般的なオプションの1つです。

BigQueryは膨大なデータを分析するのに特化したデータベースです。

以下では、ゲームのサービスで使うデータの種類ごとに BigQuery にインポートする方法を説明します。

  • マスターデータ

    • ゲームサービスにおいて、ガチャやストーリーやレベルアップに必要な経験値など、一般的にマスターデータと呼ばれるデータがあります。
    • 内容によってデータのサイズはまちまちですが、一般的にはユーザーデータやログと比較すれば、十分小さいと言えます。
  • ユーザーのセーブデータ

    • 経験値や持っているアイテムなどを保存しているデータです。
    • ユーザー数に応じてデータ全体のサイズが大きくなります。数百万のユーザーを考えると、大きなデータになることが想像できます。
  • ユーザーの行動履歴

    • ユーザーが、ゲームで、いつ・何をしたのかを記録したデータです。
    • ユーザー数とサービス期間によって、どんどんデータは蓄積し、膨大な大きさのデータになります。

マスターデータをインポート

本番サービスのデータを更新したら、BigQueryのマスターデータも更新します。

マスターデータは比較的サイズが小さい・更新頻度が低いため、BigQueryのマスターデータを一旦全部削除し、新規にマスターデータを追加します。

費用・時間・オペレーションの単純さの面で、一旦全部削除し、新規に追加する方がベターです。

http://takano-plantuml-server.herokuapp.com/svg/SoWkIImgAStDuU8gpixCAqWiIinLoCtFoq_EAChFJLKeAIfDvUBIA2akqrJGjLFGSCfC3onDBQhKLB1IyCbFJE5oICrB0Me70000

下記は tsv のマスターデータをインポートする例です。

bq --location=${MY_REGION} rm --force --table ${GCLOUD_PROJECT}:${DATASET}.${table}

bq load --autodetect --source_format=CSV --encoding=UTF-8 --field_delimiter='\t' --skip_leading_rows=1 \
        --max_bad_records=10 \
        ${GCLOUD_PROJECT}:${DATASET}.${table} ${file}

CIで自動で更新されるように設定します。

分析時の煩雑さが増しますが、マスターデータを日付ごとにBigQueryに保存するほうが良いかもしれません。データ自体が小さいため、BigQueryに置いておいてもコストの心配がないからです。

ユーザーのセーブデータをインポート

ユーザーのセーブデータは、1日1回、ユーザーデータベースである Google Cloud Spanner から Google Cloud Storage にエクスポート(バックアップ)をしています。

そのバックアップデータを、BigQuery にインポートします。

http://takano-plantuml-server.herokuapp.com/svg/SoWkIImgAStDuU8gpixCAqWiIinLoCtFoq_EAChFJLKeAIfDvUBI22v8pCjBBT9KqBLJq71t3jPKi59mIIn9JCl9B-U2281ad3BJ0qjJYof1qZxvYIbS3gbvAK330G00

ユーザーデータベースからBigQueryへ直接インポートもできますが、バックアップとしてGCSにデータがありますし、トラブルがあった時のやり直しや負荷を考えて、GCSへエクスポートされたものをソースとするのがベターです。

まずは avro形式でGCSヘエクスポート

Google Cloud Storage にエクスポートするには、Google Cloud Dataflow を使います。

下記のように、Google Cloud Storageには、avro形式でエクスポートしています。

TEMPLATE_LOCATION="gs://dataflow-templates/2020-01-09-00_RC00/Cloud_Spanner_to_GCS_Avro"

gcloud dataflow jobs run ${JOB_NAME} \
  --gcs-location=${TEMPLATE_LOCATION} \
  --region=${MY_REGION} \
  --staging-location=${MY_SPANNER_BACKUP_GS_URL}/temp \
  --parameters=instanceId=${MY_INSTANCE_ID},databaseId=${MY_DATABASE_ID},outputDir=${MY_SPANNER_BACKUP_GS_URL}/avro > tmp.log

上記の例では、ユーザーデータベースの Google SpannerからGCSへavro形式でエクスポートする、Googleが提供するテンプレートを利用しています。

テンプレートジョブは時々更新されており、最新版が自分の環境で突然動かなくなることがあります。

そのため、リリースを指定して使うのが良いでしょう。

つまり、下記のような latestは、使わない方が良いです。

TEMPLATE_LOCATION="gs://dataflow-templates/latest/Cloud_Spanner_to_GCS_Avro"

GCSのコストはとても低いので、過去の必要な日数分を保存するために利用できます。

GCSのavro形式のデータをBigQueryへインポート

以下では最新のセーブデータだけをBigQueryに入れています。

bq --location=${MY_REGION} rm --force --table ${GCLOUD_PROJECT}:${DATASET}.${table}

bq --location=${MY_REGION} load \
        --source_format=AVRO \
        ${DATASET}.${table} \
        "${MY_SPANNER_BACKUP_GS_URL}/avro/${MY_INSTANCE_ID}-${MY_DATABASE_ID}-${DATAFLOW_JOBID}/${table}.avro*"

上記のようなバッチスクリプトを1日1回実行します。

ユーザーデータをBigQueryに日付別に保存するかどうかは、分析方法とコストによって判断する必要があります。BigQueryに毎日蓄積させるとコストが増大していきます。そもそもGCSに日付別データがあるので、必要に応じてBigQueryに読み込むことができ、そのほうがコストが下がるケースがあるためです。

ユーザーの行動履歴をインポート

ユーザーの行動履歴は、1秒間に何千レコードも発生・追加する必要があるようなログデータです。ゲームによってはテラバイトのオーダーになるような巨大なデータです。

このようなデータは、一般的にストリーミングとして扱います。

ゲームサーバが出力するユーザー行動ログを、ストリーミングとしてBigQueryへ送信することで、ログデータを取り込むことができます。

http://takano-plantuml-server.herokuapp.com/svg/SoWkIImgAStDuU8gpixCAqWiIinLoCtFoq_EAChFJLKeAIfDvUBIUDoqwN7pdiVD2nutRGKp9ZnkNFUuUUtZfWsQ2hfs2XfEcUc1fQb5bPeALWeGySVDgq4gc_Q3oCRbZvjsFcxkUDoy2cBEouR69_iNSZcavgK0BGS0

ゲームサーバでログを出力する

BigQueryで扱いやすいように、jsonフォーマットでログを出力します。

go だと下記のような感じです。

var LoggerChild *logging.Logger
func LogJSON(ctx context.Context, level logging.Severity, v interface{}) {
    jsonPayload, err := json.Marshal(v)
    if err != nil {
        return
    }

    ret := ctx.Value(myLogDataContextKey)
    if ret != nil {
        if myLogData, ok := ret.(*MyLogData); ok {
            LoggerChild.Log(logging.Entry{
                Payload:  json.RawMessage(jsonPayload),
                Severity: level,
                Trace:    myLogData.TraceID,
                Labels: map[string]string{
                    // 自分で定義したラベルとデータ
                },
            })
        }
    }
}

BigQueryにテーブルを作る

ユーザー行動ログのテーブルの設定は下記のようにするのがベターです。

  • テーブルタイプ
    • 分割
  • 分割基準
    • DAY
  • フィールドで分割
    • レコードのtimestamp

ゲームの場合、日付単位での集計が多く、テーブルを日付で分割することで、速度とコストでメリットがあります。

ログルーターでログを送信する

Google CloudでログをBigQueryにストリームで送信するには、ログルーターシンクを定義します。

  • フィルタで、プロジェクトIDやログとして扱う条件を設定します。

    • ログにMyGameLogType のようなフィールドを設定しておき、そのフィールドに値があるログのみを送信するという感じで設定します。
  • 送信先にBigQueryのテーブルを選びます。

おわりに

ゲームのデータをBigQueryで集計・分析するために、必要なデータをインポートする方法を説明しました。

基本的に一度構築すれば手間はかかりません。少ない労力でBigQueryの活用を始めることができます。

BigQueryのコストは利用方法によって大きく変わるので、適切な構成にする必要があります。


リベル・エンタテインメントでは、このような最新技術などの取り組みに興味のある方を募集しています。もしご興味を持たれましたら下記サイトにアクセスしてみてください。 https://liberent.co.jp/recruit/

Google Cloud Spannerを使った際に感じた良かった点と注意点

Google Cloud Spannerを使った際に感じた良かった点と注意点

みなさま、こんにちは!
システム開発部のK.Mです。

弊社でGoogle Cloud Spannerをデータベースに使用する機会がありましたので、開発・運用時に感じた良かった点・注意点を個人的な見解を交えて記載していきます。

f:id:Liberent-Dev:20211125175521p:plain

  • Google Cloud Spannerを使った際に感じた良かった点と注意点
    • Google Cloud Spannerとは
    • 良かった点
    • 注意点
    • 開発時、運用時に起きた他の事例
    • その他、未確認事項
    • まとめ
    • 最後に

Google Cloud Spannerとは

Googleが開発した分散データベース
RDBMSとNoSQLの良い部分が合体したデータベース

良かった点

  • フルマネージドなので運営中に手がかからない

    • 運営期間中は追加実装など他業務に集中出来る。
      実際の運用時にspannerが落ちて繋がらなくなるということはありませんでした
    • イベントなどの負荷が上がりそうな時に事前にノード数を増やしたり、アクセス数が落ち着いてからノード数を減らすという作業しか行っていない
    • それ以外だと1日1回GCPの管理画面からspannerのCPU負荷やレイテンシに問題が発生していないかを確認する程度の作業量でした
  • データの水平・垂直分割しなくてもspanner側で勝手にやってくれる

    • DBの読み書き処理で水平・垂直分割の処理が不要なので、事前に分割しないといけないぐらいのデータ量になる想定がついている場合は、「実装コストが減る=テスト工数が減る=変なバグを仕込む心配が無い」という形になります
    • 例えると、MySQL ClusterやMySQLのSpiderストレージエンジンと同じような機能が設定不要で使えるということです
    • この機能は、かなり強いです
  • 運用時にメンテナンスを入れずにスキーマー変更が可能

    • 使用した案件では、本番環境にて動作確認をするためのメンテナンスを入れるという工程があったため、メンテナンス中にスキーマー更新を行っていたが、運営サイクルにてメンテナンスを無くすことを検討しているのであれば、魅力的な機能
  • 配列型や構造体型でデータが持てる

    • DBの設計がすっきりして、プログラム側での処理がしやすくなる
    • 配列型の一例
      • ストーリーの第何話を読んだというのを単純に実装しようとして、ユーザーIDと読んだストーリーの話数を保存するテーブルを作った場合、下記のように読んだストーリー数分のレコードが作られてしまいデータが膨れ上がるし、selectやinsert、updateの速度にも影響が出てしまう。(インデックスを設定すればselect自体の速度は速くなるが、insertの速度がデータが増えていくたびにインデックスの更新も入り遅くなっていきますので通常は取りえない設計)

        ユーザーID 読んだストーリーID
        1 1
        1 2
        1 3
        2 1
        2 2
      • 次に考えられるのが無駄にレコードが作られないように、読んだストーリー部分をカンマ区切りの文字列などで保存するという方法がある。こうすることで、ユーザー数分のレコードで済むのでデータ数は激減するが、プログラム側でDBからの読み込んだ際に、カンマで区切られた文字列をカンマ毎に分けて数字にしたり、DBに書き込む際に、数字をカンマで連結して文字列にしたりという処理が入ってきて、少し煩雑になってしまいます。

        ユーザーID 読んだストーリーID
        1 "1,2,3"
        2 "1,2"
      • そういった諸々を回避する方法として読んだストーリーIDをint型の配列型に設定することが可能になっています。配列型に設定出来る型自体は自由です。

        ユーザーID 読んだストーリーID
        1 [1,2,3]
        2 [1,2]
      • goの場合ですが、spannerから読み込んだ時点でint型のスライス(goでの配列のようなもの)として扱えるようになっているので、追加する場合は下記のようにappendするだけでデータが追加されます。

ストーリーテーブル.読んだストーリーID = append(ストーリーテーブル.読んだストーリーID, 4)
  • spannerの管理画面にて下記のような統計を表示するページがあり、クエリのCPU使用率や実行回数、レイテンシが見れるので調査のためにSQL(EXPLAINとか)を叩かなくてもブラウザ上で確認が出来るので調整が簡単に行える
    f:id:Liberent-Dev:20211122185625p:plain

  • GCP標準機能であるトレースにて、スタックトレースのようにspannerのコール順が分かるので、チューニング時にネックになっている箇所が分かりやすい。

    • 下記図はスタックトレースの一例になりますが、この内容ですとReadが頻繁に呼ばれているので、なるべくまとめてRead出来れば処理を短縮出来そうなので調べてみる。
      この例に挙げたケースは、バッチ処理で各テーブルを読み込んでいるという処理だったので、そのままにしておくという判断をしています。 f:id:Liberent-Dev:20211122185621p:plain
続きを読む