💾
マイクロサービスのシステム改善に伴うデータ基盤のログ対応奮闘記
こんにちは。
datatec-jpアドベントカレンダー9日目の記事です!!
自分はデータ基盤の開発保守運用を担当するデータエンジニアです。この3ヶ月間、ログ取得周りで大きな変更に追従し続けたので、そのことについてまとめます
本日話すこと
- 今どうやってログを取り込んでるの?
- 弊社での諸々の背景をまず書きます
- 今のデータ基盤ってどんな感じで取ってるの?
- ログ出力についてシステム周りどうなってるの?
- ログ取得に関するモデリングの変移
- 意識したこと、工夫したこと
今どうやってログを取り込んでるの
本当に概要だけざっくり書きます。
システムとデータ基盤について詳しく知りたい方は過去の登壇資料である「みんなの考えた最強のデータアーキテクチャ」登壇資料解説をご覧下さい。
システム周り概要
- 全部GCPで動いています
- マイクロサービス化が進んでおり、各サービスはGAEで動いてます(図では4種類)
- 各サービスで2種類のログを出力してます
- リクエストログ: UA、referrer、リクエストの種類など
- アプリケーションログ: 分析観点で欲しい情報をアプリケーション側で落とす(JSONとか)
ログ取り込みまで
- 一部のサービスが別言語で実装されている(図ではDサービスがscalaで実装)
- サービスごとに、ログ出力の方法とカラム名が違う
- ログはBQにエクスポートされる
- 1つのデータセットに複数のテーブルが出力される(言語ごとに)
- データ基盤では以下のようにログを取り込んでいる
-
traceId
を使ってリクエストログとアプリケーションログを紐付けて1リクエスト1レコードを生成 - 特定のテーブルは、アプリケーション側の特定の情報だけ取り出して実体化
- 一部のサービスだけログ出力方法が違うので、サービスごとに抽出方法を変える
-
データ基盤の初期版
- 過去の資料から引用ですが、BQからBQへスケジュールクエリ経由でデータ生成していました
【変更その1】GAEからCloudRun移行
今年の6月ぐらいに、サービスのCloudRun化を進めている噂を聞く。
何がどう変わるの
- GAEで動いていたサービスがCloudRunに移行される
- ログの出力内容(カラム名等)は変わるが、リクエストとアプリケーションの2種類は引き続き
- 図ではGAE由来のログを青、CloudRun由来のログを緑で表現
- 図ではBサービスだけCloudRun化されてる例になります
- Bサービス由来のログだけ、取り方を変えなきゃいけない
- 何より全サービス一気に変わるわけじゃなく、各サービスがそれぞれのタイミングでCloudRun化するとのこと
- え!いつどのサービスが変わるのか把握せなあかんじゃん
- スケジュールクエリがめちゃめちゃカオスになる。。。
ログ取得の設計
- また以前の記事から図を引用しますが、ちょうどdbtに移行しているタイミングでした
- ログ周りも層を分けて取り込むように設計しました
- このタイミングでは以下のように設計しました
- CloudRun移行が各サービスごとに実施されるため、全てサービスごとに別ける
- 全般的なリクエストログテーブルもサービスごとに分離
- CloudRun移行のタイミングで、stg層が参照先をGAE由来(青)からCloudRun由来(緑)に替える
- メリット
- 移行する際、stg層だけ修正すれば良いので影響範囲が限定される
- 言語の差分(Dサービスがscalaで実装されてる等)はfct層で気にしなくていい
- デメリット
- どのリクエストが何サービス由来なのかを知る必要がある
- 移行日はGAE由来とCloudRun由来が混在するので、リリース日だけ特殊な対応が必要
なんか、これなら乗り越えられそうですね!安心〜〜〜
【変更その2】APIゲートウェイ的なサービスが爆誕
ある日、特定のログがほぼ0になる事件が発生!!何が起きた!?明日から海外旅行で2週間休むんやけど/(^o^)\
どうやら、システムの内部改善で登場した「APIゲートウェイ」的な役割を持つサービスの影響であることがわかった
何がどう変わるの?
システム的な詳細は省きますが、ざっっっくり以下のようなイメージです
- アプリケーションが直接サービスにリクエストを投げない
- 間にAPIゲートウェイ的な役割を持つサービスが登場(一旦APIゲートウェイサービスって呼びます)
- どのリクエストが何サービスに問い合わせをすればいいのか深い理解をしている君です
- APIゲートウェイサービスはCloudRunで動きます
- 今までリクエストログとして落ちていた情報が、APIゲートウェイサービス側に落ちるようになった
- いつ、どのサービスが、APIゲートウェイを経由するようになるかは、各サービスごとに異なる
- え!こいつも各タイミングで切り替わるの!?また把握せなあかんじゃん!!
- 以下の図がサマリです
- Aサービスは、APIゲートウェイ対応とCloudRun移行対応が完了
- Bサービスは、APIゲートウェイ未対応でCloudRUn移行対応が完了
- C,DはGAEのまま
- APIゲートウェイサービスはCloudRunで本来は緑ですが、落ちる情報が変わるので黄色で表現
ログ取得の設計
- このタイミングでは以下のように設計しました
- 同じようにAPIゲートウェイ対応が済んでるかどうかで取り方を変えればええやん
- (何がどこに落ちるのか、結構複雑になってきたので、図はめちゃめちゃ簡略化してます
サーバーサイドチームと連携すれば、漏れとか無さそう。なんか乗り越えるんじゃね〜〜?
移行期間めっちゃ大変だった
そんなことはなかった。本当に辛かったです。
反省点
- リリース日に「参照先切り替えデプロイ」と「当日混在するから両方取る」をするだけじゃん〜では無かった
- 当日GAE由来とCloudRun由来とAPIゲートウェイ由来をそれぞれ取る、という実装とテストを毎回ちゃんとやっていたが、これめちゃめちゃコストかかる
- 例: 2022-12-03、10時ににCサービスのCloudRun移行の場合
- 2022-12-02までのBサービスはGAE由来のログだけ
- 2022-12-03の10時付近まではGAE由来のログを取る
- 2022-12-03の10時付近移行はCloudRun由来のログを取る
- 2022-12-04移行はCloudRun由来のログだけ
- リリース日だけ混在するのでそういう対応をする必要あり、だるい!
- 翌日は正しいデータから取ってるよね?の確認コストも高い
- 将来的にかかるリソースが凄まじいのに見通しが甘かった
- Nサービスについて「CloudRun移行」「APIゲートウェイ移行」それぞれ移行作業が発生する
- 図だと4サービスなので、単純計算で8回作業が発生する(実際はサービスはもっと多いので対応回数もっと多い)
- 1リリースにつき、実装とテスト、混在テスト、翌日確認、諸々合わせて○日リソース持っていかれる。あれ、ヤバない?
さらなる改善の動きが
- Dサービスが別言語で実装されているが、一部のAPIから順番にGoLangに移行することに
- Dサービスで落ちていたログが、既存のBサービスや新規のEサービスに移籍される
- GoLangログの落とし方に共通化されるので嬉しい動きだが、あれ、○○リクエストってDサービスから落ちなくなるの!?え!!
把握しなければいけないこと
- CloudRunの移行時期と対象サービス
- APIゲートウェイサービスの移行時期と対象サービス
- DサービスのGoLang移行の時期と対象APIと、それがデータ基盤に影響があるのか
当時はメリットとして設計のベースだった「サービスごとにテーブルを別ける」があまりメリットになってないじゃん ← この振り返りが一番重要!!
移行期間どうやって乗り切った
- 以下考えたこと
- システム側がリリースするたびにデータ基盤がリリースするのが辛い、よってやめたい
- GAE→CloudRunに移行した場合、両方にログが落ちることはない
- よって移行有無関係なく、とにかく任意のサービスについて両方から取ってこればよくね!?
- 一部無駄なクエリが発生するかもしれないが、データ量がそこまで多くない&リリースコストを鑑みて、一通りとって存在するものからリクエストログを生成する方針に
- 設計案
- stg層で、アプリケーションまたはリクエストログは、GAE(青)CloudRun(緑)APIゲートウェイサービス(黄)全部から取り込み、存在するものから生成する方針へ
- mart層では、GoLang移行や新規サービス移行の対応をしなくて済むように、全サービスを統合するテーブルを作る
- 全ての移行が完了したら、改めてCloudRun(緑)とAPIゲートウェイサービス(黄)だけ取るように修正する。つまりこのリリースと完了のリリースの2回だけで済む!
- メリット
- システムのリリース日にデータ基盤がリリースしなくていい。これがでかい!
- GoLang移行を気にしなくていいのが良い
- デメリット
- 一旦全部取る、みたいなSQLになっているので、データ量的に無駄なクエリを走らせている
ログ基盤設計まとめ
- stg: サービスごとに分離。全対象から取って存在するものから生成
- mart: サービスごとに分離せず、とにかく1つのテーブルに統合する
把握しなければならないこと
- 以下しっかり把握しなければいけなかったが、システムリリース翌日に確認しておくだけで済むようになった
- CloudRunの移行時期と対象サービス
- APIゲートウェイサービスの移行時期と対象サービス
- DサービスのGoLang移行の時期と対象APIと、それがデータ基盤に影響があるのか
まとめ
- システムは常に変化しており、設計当時のメリットやデメリットが、現在当てはまらないケースもある
- よって定期的に振り返ることは大事
- きれいなやり方で完璧なスーパープラン、みたいなものに拘らない
- 今回は無駄なSQLを投げる代わりに、将来的に1回のリリースで全て移行完了するという意思決定をした
- (このサービスってこのタイミングでは○○に落ちていないんだけど、、という気持ちを捨てる)
- データ量がそこまで多くないのと、自分の保守運用コストがめちゃめちゃ持っていかれたので、そこを判断材料とした
- 今回は無駄なSQLを投げる代わりに、将来的に1回のリリースで全て移行完了するという意思決定をした
- 偶発的に発見したシステム側の変更もあるので、エンジニアとのシンクは引き続きやる!
開発チームがtruncベース開発とマイクロサービスにより大いなる進化を遂げており、その変化にデータ基盤が追従するのにかなり苦労したが、自分がシステム側を結果的に詳しくなったり、運用できなくね!?みたいな経験も出来たので良かった。
データ基盤の保守運用で一番大事なのは「分析に影響がでないこと」なので、完璧を目指さないというのも大事かなと思いました。
以上です!
Discussion