こんにちは, 基盤開発チームで業務委託として働いている奥山です.
弊社で開発しているカラリアというサービスでは, モニタリングに Datadog を利用しており, Rails や Nginx などのログは Datadog に集約しています.
基本的には Datadog の UI でログを閲覧・集計すれば十分なのですが, たまに
- Datadog のログ保存期間よりも古いログを閲覧したい
- ログを他のデータと join して SQL で分析したい
ことがないでしょうか?
カラリアでも最近, Datadog に保存したログを BigQuery でクエリできるようにしたので, 検討した点を話したいと思います.
目次
現在のロギングに関する構成
まず初めに, 現在のカラリアのロギングに関する構成を簡単に紹介します.
香りEC カラリアを支える技術 で紹介されている通り, カラリアの主なアプリケーションは ECS Fargate 上で動いています.
そして, アプリケーションログを集めて Datadog へ送信するのは, サイドカーコンテナとしてデプロイされている Fluent Bit が担っています. Rails 以外のコンテナのログも Fluent Bit 経由で Datadog へ送っています.
また, Datadog のログアーカイブ機能を利用して, Google Cloud Storage (以降, GCS と略す) にログデータのアーカイブもしています.
Datadog は, 日付と時間で区切ったディレクトリ構造 (/dt=<YYYYMMDD>/hour=<HH>/
) に, NDJSON (改行区切りの JSON) を複数ファイル保存してくれます.
(BigQuery に限らず, だいたいのクエリエンジンから読みやすい形式にしてくれてるようです)
ログを BigQuery でクエリする方法の検討
上述の通り, Datadog ログは既に GCS に存在するので, ここからは GCS に保存されているログファイルを BigQuery でクエリする方法を考えます. 基本的な方法は, 次の2つかと思います.
- GCS のバケットを外部テーブルとして定義してクエリする
- BigQuery Data Transfer Service で GCS から BigQuery ストレージへデータを転送し, 標準テーブルとしてクエリする
方法1 は, BigQuery ストレージにデータを格納せずに, GCS のデータを直接クエリするお手軽な方法です. 以降, 方法1 (直接クエリ) と呼びます.
設定の仕方は,
- Cloud Storage 外部テーブルを作成する | BigQuery | Google Cloud
- Cloud Storage の外部パーティション分割データに対してクエリを実行する | BigQuery | Google Cloud
を参照してください.
方法2 は, 様々なデータソースを BigQuery ストレージに同期するジョブをスケジュールできる BigQuery Data Transfer Service を使って, クエリする方法です. 以降, 方法2 (Data Transfer) と呼びます.
設定の仕方は, Cloud Storage の転送 | BigQuery | Google Cloud を参照してください.
次の表は, この2つの方法をいくつかの観点で比較したものになります. ここからは, それぞれの観点における比較を考えていきます.
クエリの書きやすさ (パーティションフィルタ)
一般的にクエリする時には, パフォーマンス的にもコスト的にも, 無駄なデータのスキャンを抑えるために partition を指定することが大切です.
方法2 (Data Transfer) だと
select * from ... where date(event_date)='2023-03-29' -- event_date を partitioning column としている
のように直観的に partition を指定できます.
(パーティション分割テーブルに対するクエリ | BigQuery | Google Cloud も参照してください)
一方で, 方法1 (直接クエリ) だと
select * from ... where dt='2023-03-29' and hour='01'
のように partition を指定することになります.
テーブル定義には, event_date
等のログの時刻に関するフィールドと意味が重複する, partitioning の為だけの dt
, hour
フィールドが存在してしまいます.
また, クエリを書くときも, 無駄なスキャンをしないために, Datadog ログアーカイブが書き込むディレクトリ構造 (/dt=<YYYYMMDD>/hour=<HH>/
) を意識したクエリになっています.
慣れてしまえば気にする程ではないかも知れませんが, 方法1 (直接クエリ) はクエリの書き心地が若干下がります.
メンテナンスコスト
方法2 (Data Transfer) の微妙な点として, メンテナンスコストや設定の複雑さが考えられました.
先述の通り, Datadog ログアーカイブは, ログの時間に対応するディレクトリ /dt=YYYYmmdd/hour=HH/
にファイルを書き込みます.
(ファイルが追加される様子を見るに, 数分置きにログをまとめて書き込んでいる)
Datadog ログアーカイブが書き込んだデータを hourly スケジュールで BigQuery に同期したい場合, BigQuery Data Transfer Service に hourly job を設定することになります. このとき, Data Transfer のスケジュールの時刻を何分にするかが問題となります.
ログアーカイブ機能は, ある時間の間のログをいつまでに書き込むかを (アーカイブ機能なので当然ですが) 保証してません. なので, BigQuery Data Transfer Service のスケジュールを何分に設定するかが悩ましいです.
"N時のデータはN時30分に同期する" という Data Transfer Service をスケジュールすれば普段はちゃんと同期されると思いますが, Datadog のログアーカイブが遅延した時に BigQuery 内のデータが実際のログと異なる事象が起こり得ます. 方法2 (Data Transfer) を採用する場合は, BigQuery ジョブの再実行などの運用を考えておく必要があります.
下のうちのどちらかに該当する場合は, BigQuery ストレージ内にデータを置くメリットがありそうですが,
- BigQuery から Datadog のログをクエリすることが頻繁
- 大きなバッチ処理に Datadog のログを使う
そうでない場合は複雑な設定やメンテナンスと無縁の 方法1 (直接クエリ) が良さそうに思いました.
料金コスト (ストレージ)
BigQuery の標準テーブルでは partition 単位で有効期限を設定できるので, 方法2 (Data Transfer) でストレージコストが気になる場合は有効期限を付ければ緩和できます.
GCS 料金表 と BigQuery ストレージの料金表 を見ると,
- GCS の Archive Storage: $0.0025 per GB
- BigQuery の長期保存ストレージ: $0.016 per GB
なので, 頻繁に使わないデータが多い場合は料金コストに違いが出そうです.
その他
現状, 一時間当たりのログの量 (= GCS の各ディレクトリに書き込まれるファイルの総サイズ) は, 数MB 程度なので, 標準テーブルと外部テーブルによるファイル形式の違い等によるクエリの速度の差は気にしませんでした.
結論
私たちは
- BigQuery で Datadog ログを分析する機会はあまり頻繁でない
- Datadog ログの量が膨大でない
ので, 複雑な設定や考慮が不要で運用コストがない 方法1 (直接クエリ) を採用しました.
このように, Datadog がアーカイブしたログを BigQuery でクエリできるようになりました.
おわりに
Datadog で収集しているログを BigQuery でクエリするために検討したことについての話でした. Datadog でログアーカイブの有効活用法, または GCS を BigQuery からクエリする際の参考になっていればと思います.
High Link の開発チームではアプリケーション開発に加え、CI/CD といった DevOps の改善や、ログ基盤やアプリケーション監視基盤の整備を行っています. 興味がある方はぜひカジュアルにお話をするだけでも歓迎です. 詳細は下記のリンクからどうぞ!