Lock in $30 Savings on PRO—Offer Ends Soon! ⏳
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
計器進入!OpenTelemetryで見える アプリのパフォーマンスボトルネック
Search
Andrey Chernov
November 28, 2025
0
9
計器進入!OpenTelemetryで見える アプリのパフォーマンスボトルネック
DroidKaigi.collect { #28@Fukuoka }
Andrey Chernov
November 28, 2025
Tweet
Share
More Decks by Andrey Chernov
See All by Andrey Chernov
Performance for Conversion! 分散トレーシングでボトルネックを 特定せよ
inetand
0
5.8k
Featured
See All Featured
Building Flexible Design Systems
yeseniaperezcruz
329
39k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.6k
Six Lessons from altMBA
skipperchong
29
4.1k
Agile that works and the tools we love
rasmusluckow
331
21k
GitHub's CSS Performance
jonrohan
1032
470k
For a Future-Friendly Web
brad_frost
180
10k
Mobile First: as difficult as doing things right
swwweet
225
10k
Reflections from 52 weeks, 52 projects
jeffersonlam
355
21k
A better future with KSS
kneath
240
18k
[RailsConf 2023] Rails as a piece of cake
palkan
58
6.1k
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
48
9.8k
Product Roadmaps are Hard
iamctodd
PRO
55
12k
Transcript
DroidKaigi.collect { #28@福岡 } 計器進入!OpenTelemetryで見える アプリのパフォーマンスボトルネック Andrey Chernov
Andrey Chernov andousan 2 val andousan = flowOf( Me(nickname =
"andousan"), Company.Pixiv(position = "Android Engineer"), Experience(android = 9.years()), Passion(about = "Kotlin Multiplatform の信者"), Passion(about = "o11y ❤"), LinkedIn(id = "inetand"), Github(id = "inetand"), ) FukuokaScope().launch { andousan.collect(DroidKaigiCollector) }
DroidKaigi.collect { #28@福岡 } DroidKaigi 2025 After Session talk andousan
セッションペー ジ
CVRがいきなり落ちた。なぜ? 4
プロダクト指標値低下の要因特定が困難 • プロダクト指標値低下の考えられる要因が多い • ユーザーの環境で何が起こっているのかが把握できない • 異変に気づくタイミング • ユーザーからのFB •
プロダクト指標の変動 • 手元でリグレッション 5
Observability 6
モバイルアプリのObservabilityとは? 7
モバイルアプリのObservabilityとは? • クラッシュレポート? • アプリのパフォーマンス? • ユーザーの行動アナリティックス? • アプリのバグ検知? •
全部? 8
答えは:NO! それはただのテレメトリー 9
テレメトリーとは • システムではなにが起こっているかを示すデータ • ユーザーテレメトリー ◦ ユーザーの行動を分析するためのデータ ◦ 例:ボタンクリック、セッション時間、画面遷移など •
パフォーマンステレメトリー ◦ アプリパフォーマンスの情報を原因と結果を結びつける 「パンくず」のようなデータ ◦ 例:アプリ起動時間、リクエストにかかる時間など 10
テレメトリーとは 11
Observabilityとは • Observability != サービスのモニタリング • テレメトリの変動がなぜ起きたのか を説明するためのプロセス • 観測は手元ではなく、ユーザーの実環境で行う
• ユーザーテレメトリー と パフォーマンステレメトリ の関連付け • リアルタイム性が重要 12
モバイルObservabilityの現状(Firebase) • クラッシュレポート → Firebase Crashlytics • アプリのパフォーマンス → Firebase
Performance • ユーザーの行動アナリティックス → Firebase Analytics • Firebaseでユーザーとパフォーマンスの テレメトリーがすでに 完結しているのでObservabilityの観点では充実している? 13
Firebaseエコシステムの限界 14
❶ BigQuery へのエクスポートが 24時間がかかる • RUM*として利用できない ❷ トレースの関係性がない 。子のトレースも設定できない ❸
サンプリングを制御できず、重要なトレースが欠損する • サンプリング方式は固定(head-samplingのみ) • カスタムトレースのセッションのサンプリング Firebase Performanceの制限 15 *RUM – Realtime User Monitoring
トレースが分散する問題 16
トレースが分散している問題 17
トレースが分散している問題 18
トレースが分散している問題 19
OpenTelemetry 分散トレーシングを実現するための仕様と計装 20
OpenTelementry(OTel)とは • CNCF*のOSS規格 1. メトリックス 2. ログ 3. トレース •
三本柱のシグナルを提供する標準化された 仕様とOSSの計装SDK 21 *CNCF(Cloud Native Computing Foundation)プロジェクト
OpenTelementry(OTel)とは • コレクター • ベンダー非依存 • ツール選定が柔軟 22 *https://opentelemetry.io/ja/docs/collector/ コレクター
| OpenTelemetry
Trace & Span • トレース:処理の経路を示す • トレースは個別処理単位の スパンでできている • span1.parent_idとして
span2.idを設定すると親子 関係ができる 23
Metrics & Logs Metrics • 数値ベースの集計データ • 時系列で「状態の変化」を監視 • CPU使用率、エラーレート、レイテンシー分布
などを計測 • Counter, Gauge, Histogram など Logs • テキスト/構造化ログ 24
OpenTelemetry in Mobile Enough talk! Show the Code! 25
OpenTelemetry SDKの選択肢 26 • otel-android SDK
OpenTelemetry SDKの選択肢 • otel-android SDK • otel-java SDK • Embrace
Kotlin SDK • Datadog Tracing Android SDK • Elastic OTel Android SDK • Honeycomb OTel Android SDK • …or 独自のラッパーを実装する 27
OpenTelemetry SDKの選択肢 • otel-android SDK • otel-java SDK • Embrace
Kotlin SDK • Datadog Tracing Android SDK • Elastic OTel Android SDK • Honeycomb OTel Android SDK • …or 独自のラッパーを実装する 28
① OpenTelemetryの初期化 29 val exporter = OtlpHttpSpanExporter.builder().setEndpoint("http://10.0.2.2:4318/v1/traces").build() val resourceMeta =
Resource.builder() .put("service.name", "sponsor-booth-app:android") .put("service.version", BuildConfig.VERSION_NAME) .build() val tracerProvider = SdkTracerProvider.builder() .setResource(resourceMeta) .addSpanProcessor(BatchSpanProcessor.builder(exporter).build()).build() val otelJava = io.opentelemetry.sdk.OpenTelemetrySdk.builder().setTracerProvider(tracerProvider).build() val otelKotlin: OpenTelemetry = otelJava.toOtelKotlinApi() val tracer = otelKotlin.tracerProvider.getTracer("sponsor-booth-app", "0.1.0”) Kotlin
利用例:Spanを作成する 30 val span = tracer.createSpan( name = "span1" )
// アプリ起動、画面遷移、I/O処理など span.end() Kotlin
利用例:親付きSpanを作成する 31 val parent = tracer.createSpan( name = "span1", )
// Start of the session val child = tracer.createSpan( name = "span2", parentContext = parent.storeInContext( otelKotlin.contextFactory.root() ) ) // アプリ起動、画面遷移、I/O処理、BGジョブなど child.end() // 他のspanも開始できる parent.end() Kotlin
利用例:親付きSpanを作成する 32 val parent = tracer.createSpan( name = "span1", )
// Start of the session val child = tracer.createSpan( name = "span2", parentContext = parent.storeInContext( otelKotlin.contextFactory.root() ) ) // アプリ起動、画面遷移、I/O処理、BGジョブなど child.end() // 他のspanも開始できる parent.end() Kotlin
OpenTelemetry Java SDKの留意点 • WorkManager経由でのSpanの同期 ◦ 送信リトライ ◦ DozeMode・Network制限の考慮など •
未送信・同期に失敗したSpanの永続化 • 親Spanの管理 ※ opentelemetry-androidのStableリリースで上記の課題が解決される見込み 33
実際に測定してみよう! ボトルネックを特定する 34
リクエストにかかる時間 ネットワークの考慮 • CDN経由でのDNS解決 • 環境の問題 • 端末の問題 35
ネットワークリクエストの測定 36 private fun startSpanForMetric(metric: String): CatSpan { if (requestMeasurementSpan
== null) { // 親のSpanが作成されていなければ作成する requestMeasurementSpan = createRequestMeasurementSpanIfNotCreated() } return tracer.startSpan(name = metric, parent = requestMeasurementSpan) } // 他のメソッドも同様に対応する override fun dnsStart(call: Call, domainName: String) { super.dnsStart(call, domainName) dnsSpan = startSpanForMetric("dns_lookup") } override fun dnsEnd(call: Call, domainName: String, inetAddressList: List<InetAddress>) { super.dnsEnd(call, domainName, inetAddressList) dnsSpan?.stop() } // 他のメソッドも同様に対応する TimingEventListener.kt
ネットワークリクエストの測定 37 fun provideOkHttpClient(tracer: Catracer): OkHttpClient { return OkHttpClient.Builder() .eventListenerFactory
{ TimingEventListener(tracer) } .build() } Kotlin
38 ネットワークリクエストの測定結果
リクエスト時間(Firebase) 39
結果考察 40
Firebase Performance vs OTel 41 Firebase Performance OpenTelemetry SDK Open
Source ❌ 🟢 Vendor-Lock Free ❌ 🟢 分散トレーシング対応 ❌ 🟢 自動計装 🟢 🔺(独自実装) サンプリング制御可否 ❌ 🟢 バックエンド・インフラの 分散トレース ❌ 🟢 Logの対応 ❌ 🟢
バックエンド 42
Grafana (alloy) 43
DataDog 44
Honeycomb 45
導入前後での観測プロセスの変化 46 Before After
Firebase Performance (before) • 遅いのか • 早いのか 47
OpenTelemetry + Grafana (after) 48
OpenTelemetry + Grafana (after) 49
OpenTelemetry + Grafana (after) 50
Catracer SDK 51 Coming soon? ※ 現在、APIデザインの段階
ご清聴ありがとうございました 52