Edited at
gumiDay 4

Fluentd 経由で BigQuery に Schema-less なログを入れる

More than 3 years have passed since last update.


背景

gumi で提供しているソーシャルゲームは, サーバ/クライアント共に様々なログを Fluentd 経由で各種データストアに入れており, 適宜, 解析を行っている.

ログの種別により, Schema-full or Schema-less を選択しているが, 本記事では Schema-less なログの取り扱いを話題とする.


Schema-less なログの必要性

サーバ/クライアントの開発時から運用時まで, 常に次のような要望がある.

「気軽に適当なフォーマットでログを出力したい」

Schema-full なデータストアを採用する場合, 開発者に次のルールを強いる必要がある.


  • ログ出力前にテーブルのスキーマを定義せよ

  • ログ出力中にテーブルのスキーマを変更するなら, 別テーブルにせよ

これらのルールを開発者が守らない場合, Fluentd 側でエラーが発生するため, 開発者はインフラ担当のヘイトを稼ぐことになる. そして, インフラ担当に怒られた開発者は, 別の手段を模索し始め, 各プロジェクトごとに別々の仕組みが構築される.

よって, Schema-less なデータストアを使用し, Schema-less なログを出力する必要がある.


データストアの選定

Schema-less なデータストアを選定する場合, 筆者は, まず始めに MongoDBElasticsearch を候補にあげる. その後, Schema-full だが, データ取得時にフィールドに格納されている JSON フォーマット文字列から必要な情報を部分的に抜き取れる RedshiftBigQuery を連想する.

それぞれのデータストアに得手不得手があるため, gumi では, 適宜, 用途により使い分けている(一つのログを複数の用途で使用するため, ログの複製を複数のデータストアに保存することが多い).

今回の要件は, 「気軽に適当なフォーマットのログを出力したい」 であるため, 次の観点から BigQuery を採用した.


  • SQL なら書ける人が多い

  • ディスクスペースを考慮する必要がない


  • JSON 関連の関数の応答速度が速い


  • ModeAnalytics などで楽にグラフを作成できる

蛇足だが, 前述した他のデータストアを, gumi では次の用途で使用している.


  • MongoDB - 行動ログを入れ, カスタマーサポート時に使用

  • ElasticSearch - 自由入力文字列を入れ, 伏字処理や特定単語の検索に使用

  • Redshift - 検索頻度は高いが, 年単位で遡る事がない場合, BigQuery の代わりに使用

  • S3 & Glacier - 蛇足の蛇足. あらゆる全てのログのバックアップに使用


その他の前提条件

サーバ/クライアントから何らかの経路を辿り Fluentd へログが渡されていることを前提条件とする.


ログの取り扱い


ログを JSON フォーマット文字列にシリアライズする

前述した通り, BigQuery は Schema-full なデータストアであるため, ログを JSON フォーマット文字列に変換し, 一つのフィールドに入れる必要がある.

gumi では, ログを JSON フォーマット文字列にシリアライズする Fluentd Plugin fluent-plugin-record-serializer を作成し, 運用している.

Plugin をインストール後, Fleuntd に次のような設定を追加し,


fluent.conf

<filter pattern>

type record_serializer
</filter>

次の様なログを送ると,

{

"spam": "ham",
"egg": "cheese"
}

次の様にシリアライズされる.

{

"tag": "pattern",
"payload": "{\"spam\": \"ham\", \"egg\": \"cheese\"}"
}

ちなみに, fluent-plugin-record-serializer は Oj をインストールすると CPU 負荷が減る.


BigQuery への保存

Fleuntd から BigQuery にログを入れるため, fluent-plugin-bigquery を使用する.

次の様な本末転倒な Schema ファイルを設置し,


schemaless_schema.json

[

{
"name": "tag",
"type": "STRING"
},
{
"name": "time",
"type": "INTEGER"
},
{
"name": "payload",
"type": "STRING"
}
]

Fleuntd に次のような設定を追加すると,


fluent.conf

<match pattern>

type bigquery

method insert
auto_create_table true
schema_path /path/to/schemaless_schema.json

# ..snip..
</match>


指定したプロジェクトのテーブルに, Schema-less なログが入る.


ログの確認

JSON_EXTRACT 関数を使用し, 必要なログを取得する.

SELECT JSON_EXTRACT(payload, '$.spam') as spam

FROM [pattern_20151204]
WHERE JSON_EXTRACT(payload, '$.egg') = 'cheese'


まとめ

SELECT や WHERE 句に payload を指定すると, 非常にサイズの大きいフィールドを扱うため, BigQuery 破産の可能性が上昇する. ご利用は計画的に.