Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
アドフリくんにおけるマイクロサービス間での一貫したトレース実現
Search
gree_tech
PRO
October 17, 2025
Technology
390
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
アドフリくんにおけるマイクロサービス間での一貫したトレース実現
GREE Tech Conference 2025で発表された資料です。
https://techcon.gree.jp/2025/session/TrackB-1
gree_tech
PRO
October 17, 2025
More Decks by gree_tech
See All by gree_tech
変わるもの、変わらないもの :OSSアーキテクチャで実現する持続可能なシステム
gree_tech
PRO
0
4.8k
マネジメントに役立つ Google Cloud
gree_tech
PRO
0
65
今この時代に技術とどう向き合うべきか
gree_tech
PRO
3
2.8k
生成AIを開発組織にインストールするために: REALITYにおけるガバナンス・技術・文化へのアプローチ
gree_tech
PRO
0
450
安く・手軽に・現場発 既存資産を生かすSlack×AI検索Botの作り方
gree_tech
PRO
0
440
生成AIを安心して活用するために──「情報セキュリティガイドライン」策定とポイント
gree_tech
PRO
1
2.4k
あうもんと学ぶGenAIOps
gree_tech
PRO
0
560
MVP開発における生成AIの活用と導入事例
gree_tech
PRO
0
590
機械学習・生成AIが拓く事業価値創出の最前線
gree_tech
PRO
0
470
Other Decks in Technology
See All in Technology
From Prompt Engineering to Loop Engineering
shibuiwilliam
1
330
本当の”仕事”を手放せる未来が見えた
mu7889yoon
0
220
秘密度ラベル初心者が第1歩でつまづかないための「設計・運用」ポイント
seafay
PRO
1
570
知見・人・API・DB・予算 ─ ナイナイ尽くしだった人事データ整備 with dbt、5年間の学び
ken6377
1
140
Text-to-SQLをAgentCoreで実現し、生成されるSQLの精度を定量的に評価する
yakumo
2
450
AIDLC_ヤフーショッピングの取り組み
lycorptech_jp
PRO
0
500
デジタル・デザイン構想 by Sayaka Ishizuka
y150saya
0
180
AIに「使われる」時代のSaaS戦略 〜既存WebAPIのMCPサーバー化における開発ノウハウ〜
ekispert_api
0
270
トークン最適化のためのユーザーストーリー分析 / User Story Analysis for Token Optimization
oomatomo
0
160
Keeping applications secure by evolving OAuth 2.0 and OpenID Connect
ahus1
PRO
1
130
AIペネトレーションテスト・ セキュリティ検証「AgenticSec」紹介資料
laysakura
2
8k
Claude Codeとハーネスについて考えてみる
oikon48
13
6k
Featured
See All Featured
Prompt Engineering for Job Search
mfonobong
0
360
SEO Brein meetup: CTRL+C is not how to scale international SEO
lindahogenes
1
2.8k
What the history of the web can teach us about the future of AI
inesmontani
PRO
1
630
Automating Front-end Workflow
addyosmani
1370
210k
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
21
1.5k
Building Flexible Design Systems
yeseniaperezcruz
330
40k
Fireside Chat
paigeccino
42
4k
The Impact of AI in SEO - AI Overviews June 2024 Edition
aleyda
5
1.1k
Chasing Engaging Ingredients in Design
codingconduct
0
230
GraphQLとの向き合い方2022年版
quramy
50
15k
Balancing Empowerment & Direction
lara
6
1.2k
Bridging the Design Gap: How Collaborative Modelling removes blockers to flow between stakeholders and teams @FastFlow conf
baasie
0
600
Transcript
アドフリくんにおけるマイクロサービ ス間における一貫したトレース実現 - アドフリくんRTBシステムにおけるObservabilityの実装事例 - グリーエックス社 エンジニア 樋口雅拓
樋口雅拓 Go / k8s / RecSys / Android / Kotlin
/ Scala / PHP / Python / Swift / AWS / GCP グリーグループのグリーエックス株式会社で、ソフトウェ ア開発に従事。広告システム開発、GREE Platformの立ち 上げ、不正利用対策、チャットアプリ開発、メディア開発 を経て2025年2月より現職。 グリーエックス社 エンジニア 2
背景と目的 • 複数のマイクロサービスを連携して1つのHTTPリ クエストを処理するシステムを構築した。 • ログやトレース情報がマイクロサービス毎に生成 され、統合して確認することができなかった。 • これを統合して確認できるようにしたため、その 事例について発表する。
発表構成 • 前提知識 ◦ サービス及びシステム概要 ◦ システムの一部であるRTBシステムについて ◦ RTBシステムのObservabilityについて • 提案方式 ◦ 一貫したトレースの実現方法 前提知識を説明した後、提案方式について説明します。 アドフリくん管理画面などRTB以外のサーバー機能、レ ポート機能については、時間の都合で割愛させていただ きます。 3
サービス及びシステム概要 4
アドフリくん - サービス概要 • モバイルアプリ向けの広告配信プラット フォーム • 「動画リワード広告」の取扱量は国内No.1 5 動画リワード広告とは
Pangle/Unity/APP LOVIN/Mintegral/Info Source/AdMob/Digital Turbine/LINE Ads Network/nend/Zucks/ maio/AMoAD
アドフリくん - システム概要 モバイルアプリ向けの広告配信プラットフォーム • メディエーション: 複数のアドネットワークを統合管理 • 収益最適化: リアルタイムでの配信比率調整
• RTB対応: Real-Time Biddingによる高収益化 • 運用効率: 自動化された管理・監視システム 6 アドフリくんは、以下のコンポーネントから構成されています。 • アドフリくんサーバー: 配信設定(利用するアドネットワークのリストや条件)をSDKに伝える。 • アドフリくんSDK: モバイルアプリに組み込み、サーバーから受け取った配信設定に従って広告を取得する。 つまり、アドフリくんはSDKとサーバーが連携して価値を提供しています。 次のスライドでは、アドフリくんサーバーが配信設定を作る方法について説明します。
アドフリくん - SDK概要 • init()で広告設定を読み込みます。 ◦ 広告設定には、アドネットワークの配信比 率や優先順位が含まれています。 • load()で広告を読み込みます。
◦ 配信設定を元に選択されたアドネットワー クに要求します。 • play()で広告を表示します。 7 // SDK初期化 AdfurikunSdk.init(activity) // 広告読み込み AdfurikunSdk.load("REWARD_APP_ID") // 再生準備確認・表示 if (AdfurikunSdk.isPrepared("REWARD_APP_ID")) { AdfurikunSdk.play("REWARD_APP_ID") } 実装例: Android
アドフリくん - アドフリくんサーバー概要 アドフリくんサーバーは、複数のアドネットワークの配信比率を適 切に調整して、収益最大化するものです。 アドフリくんでは、以下3種類に対応しています。 ウォーターフォール配信 優先度を予め設定しておき、その順序で問い合わせる。 一般的に単価が高いDSPほどターゲティングやキャップがキツく、 在庫が少ないため高単価から順番に問い合わせることが合理的。
ウォーターフォールRTBコンビネーション配信 ウォーターフォールとRTBの良い所取りをしたもの。 過去の実績からRTBのeCPMを計算し、ウォーターフォールのeCPM と比較して適切な場所に差し込む。 これにより、確実に高単価が見込めるDSPへの問い合わせをRTBよ り優先させることができる。 8 優先度1: AdMob (eCPM: $5.0) ↓ (広告なし) 優先度2: AppLovin (eCPM: $4.0) ↓ (広告表示) 並列入札: ├─ AdMob: $4.2 ├─ Unity Ads: $4.7 ← 勝者(広告表示) └─ AppLovin: $4.5 RTB (Real-Time Bidding) リクエスト毎にDSPに問い合わせ、最も高い入札額を提示した DSPの広告を配信する。 確実に最高額の広告を表示できるが、仕組みが複雑。 まとめ • ウォーターフォール配信: 対象アプリに最適な配信設定 • RTB: 対象アプリとユーザーに最適な配信設定 • ウォーターフォールRTBコンビネーション配信: 良い所 取り 直感的にはRTBが最適に見えます。 しかし、RTBと通常配信で在庫が分かれているケースが多いた め、組み合わせる事でさらに良い結果を得られる事が多い。 優先度1: AdMob (eCPM: $5.0) ↓ (広告なし) 優先度2: RTB(Unity Ads) (eCPM: $4.7) ↓ (広告表示)
システムの一部である RTBシステムについて 9
RTBシステム RTB機能を提供するシステムです。以下のよう な特徴があります。 ここでは、Observability以外の部分について説 明します。 システム特徴 • 組織: スクラム開発の導入と運用 •
設計: ドメイン駆動設計(DDD)とC4 Modelsによる可視化 • 実装: Clean Architectureの適用とテスト 駆動開発の実践 • 構築: マイクロサービスとして機能ごとに 分離されたサービス群 • 運用: Google Cloud Observabilityを利用 したログ、トレース、メトリックス 10
RTBシステムの特徴 - 組織 スクラム開発の採用 1週間スプリント - 新規技術と不明確な要件への対応 - 素早い学習サイクルの実現 -
課題の早期発見と対応 会議体の制定 - スプリントプランニング: 毎週1時間 - デイリースクラム: 毎日30分 - レトロスペクティブ: 毎週1時間 透明性の向上 - スプリントバックログの可視化 - バーンダウンチャートによる進捗管理 - ステークホルダーとの情報共有 導入効果と課題 メリット - チームコミュニケーションの改善 - 問題解決の文化醸成 - プロジェクト進捗の可視化 - 適切なフィードバックの獲得 デメリット - ベロシティの不安定化 - 中長期スケジュール見積もりの困難 - 会議コストの増加 今後の改善 - 2週間スプリントへの移行を検討 - より安定したベロシティの確立 11
RTBシステムの特徴 - 設計 C4 Modelsは、ソフトウェアアーキテクチャを4つの抽象レベルで表現する設計手法です。 従来のUMLや複雑な設計書に比べ、ステークホルダー全員が理解しややすい図で表現できます。 4階層の構成 • Level 1
(Context): システム全体と外部システムとの関係 • Level 2 (Container): システム内の主要コンポーネントと技術スタック • Level 3 (Component): 各コンテナ内部の詳細設計 • Level 4 (Code): クラス図やシーケンス図レベルの実装詳細 DDDとC4 Modelsの組み合わせにより、複雑なドメインを適切に設計・可視化できます。 チーム全員での設計議論が活発化し、より良い設計につながりました。 12
RTBシステムの特徴 - 実装 Clean Architecture 依存関係の制御 - MVCアーキテクチャの密結合問題解決 - ビジネスロジックの外部技術からの独立
- レイヤー間の責務分離 テスタビリティの向上 - 依存性注入とインターフェース活用 - 外部APIやデータベースのモック化 - 純粋なビジネスロジックのテスト 変更容易性の確保 - 特定層の変更が他層に影響しにくい構造 - データベース変更時のリポジトリ層のみ修正 レイヤー構成と責務 - Controller: HTTP、外部とのデータ変換 - UseCase: ワークフロー、アプリ固有ルール - Entity: ドメインモデル、ビジネスロジック - Repository: DB/APIなど外部技術の詳細実装 依存関係の方向性 13 - 外側の層は内側の層に依存 - 内側の層は外側の層を知らない - インターフェースによる疎結合 Controller → UseCase → Entity
RTBシステムの特徴 - 構築 マイクロサービス 機能ごとにマイクロサービスとして構築してい ます。マイクロサービスには、以下のものがあ ります。 • info API:
SDKからのリクエストを受け、 オークションAPIを使ってオークション処 理を行い、レスポンスを構築する。 • オークションAPI: オークション処理を行 い、広告コンテンツをストレージに保 存。 • Ad API: 広告コンテンツを応答する。 • DSP Notifier: オークション結果をDSPに 通知する。 CI/CDパイプライン GitHubActionsとCloudDeployを利用しています。 14
RTBシステムの Observabilityについて 15
Observabilityの三本柱 📝 ログ (Logs) イベントの詳細情報を記録 • 構造化ログ: JSON形式で の統一 •
コンテキスト: TraceIDと の関連付け • 検索性: クエリによる高速 検索 16 🔍 トレース (Traces) リクエストの流れを追跡 • レイテンシ分析: ボトル ネックの特定 • 依存関係: サービス間の関 係性把握 • エラー伝搬: 障害の原因追 跡 📊 メトリクス (Metrics) システムの健康状態を数値で把握 • エラー率: HTTP 4xx/5xx エラーの割合 • スループット: 秒間リクエ スト数 • リソース使用率: CPU・メ モリ・ネットワーク
Observability - ログ Cloud Logging SDKを利用しています。 これにより、Traceのような直感的なKeyで構造化ログを書き 込むことができます。 (逆に使わない場合、"logging.googleapis.com/trace"と いった分かりづらいKeyが必要。)
17 ## ログ出力例 { "severity": "INFO", "trace": "projects/gree-peridot/traces/37e8e45b2fc23fd035b235bcc3a58555", "spanId": "9fb57bf9f69ab602", "logName": "projects/gree-peridot/logs/info", "jsonPayload": { … }, ... } func (l *LoggingClient) OutputSpan(...) { entry := logging.Entry{ Severity: severity, Trace: fmt.Sprintf("projects/%s/traces/%s", l.projectID, traceID), SpanID: spanID, Payload: payload, } logger.Log(entry) ログパッケージ設計 ログ出力例
Observability - トレース - トレースの各要素は、スパンと呼ばれる。こ のスパンは、実装で範囲を決める。 - ログにtraceIdとspanIdを追加すると、トレー スとログを紐付けることができる。 18
_, span := tracer.Start(ctx, "AuctionEntity", trace.WithSpanKind(trace.SpanKindInternal), trace.WithAttributes( attribute.String("component", "info"), attribute.String("layer", "entity"), ), ) defer span.End() traceID := span.SpanContext().TraceID().String() spanID := span.SpanContext().SpanID().String() e.logger.OutputJsonSpan(..., traceID, spanID, トレーシング実装
Observability - メトリクス - システムメトリクスは自動収集される。 - ビジネスメトリクスは明示的に送信する必要 がある。 19 meter
:= otel.GetMeterProvider().Meter("adfurikun-business") auctionCounter, _ := meter.Int64Counter( "business_auctions_total", metric.WithDescription("Total number of auctions processed"), ) m.auctionCounter.Add(ctx, 1, metric.WithAttributes( attribute.String("auction_type", auctionType), ), ) ビジネスメトリクス実装例
一貫したトレースの実現方法 20
課題: GCPとアプリケーションのトレース連携 Cloud Load BalancingとGKEアプリケーション間のトレース情報の問題 21 Application Span (ルートスパン) ├──
Business Logic Span └── Request └── Other Micro Service └── Business Logic Span Load Balancer Span (見えない) └── Application Span (孤立) ├── Business Logic Span └── Request Other Micro Service └── Business Logic Span 実際の結果 全体のトレースが確認できない。 期待していたトレース RTBシステムは、複数のマイクロサービスを使って HTTPリクエストを処理する。 HTTP Request全体のトレースを確認したい。
解決策1: トレース情報の伝播 トレース情報の伝播はPropagatorの責務。そこで、以下のようにPropagatorを設定。 22 Load Balancer Span (見えない) └── Application
Span (孤立) ├── Business Logic Span └── Request └── Other Micro Service └── Business Logic Span これにより階層構造になったが、ルートスパンが見えないため探しづらい。 X-Cloud-Trace-Context: TRACE_ID/SPAN_ID;o=TRACE_TRUE HTTP RequestのHeaderに付与されるTRACE_IDがリクエスト側から引き継がれるようになる。 otel.SetTextMapPropagator( propagation.NewCompositeTextMapPropagator( gcppropagator.CloudTraceFormatPropagator{},... )) Load Balancer Spanが見えないのは、Load BalancerがSpan情報をCloud Traceに送信できないため。 それなら、消してしまおう。
解決策2: Load Balancer Spanの削除 // middlewareが生成するスパンにattributeを設定 otelfiber.WithCustomAttributes(func(...) ... { return
[]attribute.KeyValue{ // middlewareで生成するスパンに印をつける attribute.Bool("parent_span_is_lb", true), }}), processors: # otelFiberのMiddlewareで作成したスパンの親スパン IDを削除する transform: trace_statements: - context: span conditions: # 条件に一致するスパンの親スパン ID を持つ場合 - span.attributes["parent_span_is_lb"] == true statements: # 条件に一致するスパンの親スパン ID を削除 - set(span.parent_span_id, SpanID(0x00000)) # span情報を編集したことを記録 - set(span.status.message, "span edited") 23 Application Span (ルートスパン) ├── Business Logic Span └── Request └── Other Micro Service └── Business Logic Span トレース表示 期待通りの表示となった。 OpenTelemetry Collector設定 Application Spanの親スパン情報を消し、ルートスパンと した。 アプリケーション側の実装
OTTL実装の詳細 OTTL構文の解説 バージョン注意点 OTTLの仕様は変更されることがあります 24 よく使用される関数 - set(): 値の設定 -
delete_key(): キーの削除 - replace_pattern(): パターン置換 - truncate_all(): 文字列の切り詰め 主要な構文要素 - context: 処理対象の指定(span, spanevent, metric, log) - conditions: 変換を適用する条件 - statements: 実際の変換処理 transform: trace_statements: - context: span # スパンコンテキスト で処理 conditions: # 条件部分 - span.attributes["parent_span_is_lb"] == true statements: # 実行部分 - set(span.parent_span_id, SpanID(0x00000)) - set(span.status.message, "span edited") 他のプロセッサーとの使い分け - Filter Processor: 単純なフィルタリング - Attributes Processor: 属性の追加・削除 - Transform Processor: 複雑な変換ロジック 用途に応じて適切なプロセッサーを選択することが重要 # v0.120.0以降 processors: transform: trace_statements: - context: span statements: - set(span.parent_span_id, SpanID(0x00000)) # v0.120.0以前 processors: transform: trace_statements: - context: span statements: - set(parent_span_id, SpanID(0x00000))
今後の展望 25
CloudDeployとPrometheusの連携によるカナリアデプロイ 課題 - リスクの高いデプロイ: 一度に全てのトラ フィックが新バージョンに流れる - 障害の影響範囲: 問題発生時に全ユーザーに影 響
- ロールバック時間: 手動での判断と実行が必要 RTBシステム特有の要件 - 低レイテンシ: 50ms以下のレスポンス要求 - 高可用性: 99.9%以上の稼働率必要 - 収益への直接影響: デプロイ失敗が売上に直結 自動判定指標 - エラー率: 0.1%以下を維持 - レスポンス時間: P99で50ms以下 - DSP成功率: 95%以上 - 収益指標: 前バージョン比で5%以上の下落なし 26 現在のデプロイフロー カナリアデプロイフロー
まとめ 27
まとめ • アドフリくんを導入することで、メディアの広告収益を最大化することが できます。 • アドフリくんは、継続的に改善を行う仕組みとなっています。 • 同様の取り組みを行うことで、担当プロジェクトが継続的な改善可能とな ります。 28
ご清聴ありがとうございました 29
None