Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
計器進入!OpenTelemetryで見える アプリのパフォーマンスボトルネック
Search
Andrey Chernov
November 28, 2025
0
14
計器進入!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
SERP Conf. Vienna - Web Accessibility: Optimizing for Inclusivity and SEO
sarafernandez
1
1.3k
We Analyzed 250 Million AI Search Results: Here's What I Found
joshbly
0
250
The agentic SEO stack - context over prompts
schlessera
0
560
Building a Modern Day E-commerce SEO Strategy
aleyda
45
8.4k
JAMstack: Web Apps at Ludicrous Speed - All Things Open 2022
reverentgeek
1
290
Odyssey Design
rkendrick25
PRO
0
430
Faster Mobile Websites
deanohume
310
31k
The Cult of Friendly URLs
andyhume
79
6.7k
Game over? The fight for quality and originality in the time of robots
wayneb77
1
66
Large-scale JavaScript Application Architecture
addyosmani
515
110k
Unsuck your backbone
ammeep
671
58k
Thoughts on Productivity
jonyablonski
73
5k
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