Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Performance for Conversion! 分散トレーシングでボトルネックを 特定せよ

Performance for Conversion! 分散トレーシングでボトルネックを 特定せよ

In Android apps, sluggish startups and janky scrolling directly lead to user churn and lower conversion rates. However, as projects grow in complexity, it becomes difficult with common tools—such as Firebase Performance Monitoring—to pinpoint why performance metrics are dropping and where the actual bottlenecks lie.

For example, if the time to first frame is slow, you might assume delays in data-layer execution or image decoding are to blame, but in reality the root cause can reside in asynchronous operations outside the app—such as TCP connection establishment or DNS resolution through a CDN. Moreover, I/O contention can also trigger performance issues, so investigating bottlenecks that cannot be reproduced locally is extremely challenging.

In this session, we’ll cover the fundamentals of distributed tracing—widely used on the backend—and explain how to leverage it in Android apps. We’ll introduce techniques and monitoring strategies that clarify causal relationships between in-app processes and system-level operations, helping you identify performance issues more easily while maintaining high quality in the app, which is beloved by users worldwide in diverse environments.

Furthermore, we’ll discuss the design and operation of tracing with OpenTelemetry, highlight differences from Firebase Performance and Systrace, present examples of a mobile-customized SDK implementation, and share real-world case studies of performance improvements. By the end, you’ll understand the technologies and mechanisms needed to uncover what “slow loading” really means.

Proposed Session Outline

- Why traditional methods struggle to pinpoint performance issues
- What is distributed tracing?
- Core concepts: trace, span, and context propagation
- OpenTelemetry and its ecosystem
- Comparison with Firebase Performance and Systrace
- Designing and introducing distributed tracing for Android apps
- Granularity of measurement units
- Designing and implementing a lightweight mobile SDK
- Data collection and sampling
- Visualization and operations
- Observability with tools like Grafana
- Best practices for alert design
- Problem-solving flow and results
- Case study: observability→performance metric degradation→investigation→improvement→re-observability
- Reflections and future outlook
- Changes in the development process before and after implementation
- Future potential of distributed tracing (including AI-driven monitoring, etc.)

Avatar for Andrey Chernov

Andrey Chernov

September 11, 2025
Tweet

Other Decks in Programming

Transcript

  1. パフォーマンス管理が重要な理由 • 遅いと離脱率が⤴ • 遅いとは何か? アプリの起動時間が以下の閾値に達すると、長すぎると判断される • コールド スタートに 5

    秒以上かかっている。 • ウォーム スタートに 2 秒以上かかっている。 • ホットスタートに 1.5 秒以上かかっている。 指標の閾値がストア毎で異なる 7
  2. ネットワークリクエストの測定 26 fun provideOkHttpClient(): OkHttpClient { return OkHttpClient.Builder() .eventListenerFactory {

    TimingEventListener() } .build() } Kotlin override fun dnsStart(call: Call, domainName: String) { super.dnsStart(call, domainName) dnsTrace = FirebasePerformance.startTrace("dns_lookup") } override fun dnsEnd(call: Call, domainName: String, inetAddressList: List<InetAddress>) { super.dnsEnd(call, domainName, inetAddressList) dnsTrace?.stop() } Kotlin
  3. Tail-based サンプリング • トレースの内容を参照 した上で サンプリングする方法 • エラーを含むトレース • 全体的なレイテンシーに基づいて

    サンプリングする • 特定の属性 があるトレースを含む など 36 Tail-based Sampling Traceを参照した上で判断する 遅いトレースやエラーを含んだトレースを選択
  4. OpenTelementry(OTel)とは • CNCF*のOSS規格 1. メトリックス 2. ログ 3. トレース •

    三本柱のシグナルを提供する標準化された 仕様とOSSの計装SDK 46 *CNCF(Cloud Native Computing Foundation)プロジェクト
  5. OpenTelementry(OTel)とは • OTLP + SDK • ベンダー非依存 • ツール選定が柔軟 47

    *https://opentelemetry.io/ja/docs/languages/#status-and-releases 言語API & SDK | OpenTelemetry
  6. OpenTelemetry SDK • otel-android SDK • otel-java SDK • Embrace

    Android SDK • Embrace Kotlin SDK • Datadog Tracing Android SDK • Elastic OTel Android SDK 56
  7. Catracer SDK とは • 軽量版のOpenTelemetry Android SDK(独自SDK) • Embrace Kotlin

    SDK を基盤実装として利用 • 特定のSDKに依存しない設計になっている。KMPも対応可能 • ゴール ◦ アプリレベルでSpanを管理する(永続化を含む) ◦ Dozeモードやバックグラウンド制限に対応した同期 ◦ 特定OTel SDKに依存しないこと 58 *https://github.com/embrace-io/opentelemetry-kotlin/tree/main | OpenTelemetry Kotlin SDK by Embrace
  8. 独自SDKの設計 60 expect class Catracer { fun startSpan( name: String,

    parent: CatSpan? = null, attributesMap: Map<String, String> = emptyMap(), startTimeNanos: Long? = null ): CatSpan fun getOngoingSpan(spanDeclaration: AppSpanDeclaration): CatSpan? } Kotlin
  9. 独自SDKの設計 61 expect class CatSpan { val attributes: Map<String, Any>

    val name: String val traceId: String? val spanId: String? val parentSpan: CatSpan? val isRecording: Boolean fun start(startTimeMs: Long? = null): Boolean fun stop(stopTimeMs: Long? = null) fun putAttribute(key: String, value: String) } Kotlin
  10. 独自SDKの設計 62 interface AppSpanDeclaration { val spanName: String } enum

    class AppSpans(override val spanName: String) : AppSpanDeclaration { COLD_APP_STARTUP_SPAN("cold_app_startup"), HOME_SCREEN_FULLY_RENDERED("first_screen_fully_rendered"); } Kotlin
  11. class App : Application() { var processStartupTimestamp: Long? = null

    override fun attachBaseContext(base: Context?) { processStartupTimestamp = SystemClock.elapsedRealtimeNanos() super.attachBaseContext(base) } Kotlin 66
  12. class App : Application() { override fun onCreate() { super.onCreate()

    val tracer = Catracer by inject() catracer.startSpan( AppSpans.COLD_APP_STARTUP_SPAN, startTimeNanos = processStartupTimestamp ) val handler = Handler(Looper.getMainLooper()) handler.post(DetectStartFromBackgroundRunnable(tracer)) //... Kotlin 67
  13. registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks { override fun onActivityCreated( activity: Activity, savedInstanceState:

    Bundle? ) { catracer.getOngoingSpan(AppSpans.COLD_APP_STARTUP) ?.putAttribute("has_been_started_by_user", "true") }   override fun onActivityResumed(activity: Activity) { catracer.getOngoingSpan(AppSpans.COLD_APP_STARTUP)?.stop() unregisterActivityLifecycleCallbacks(this) } //... Kotlin 68
  14. registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks { override fun onActivityCreated( activity: Activity, savedInstanceState:

    Bundle? ) { catracer.getOngoingSpan(AppSpans.COLD_APP_STARTUP) ?.putAttribute("has_been_started_by_user", "true") }   override fun onActivityResumed(activity: Activity) { catracer.getOngoingSpan(AppSpans.COLD_APP_STARTUP)?.stop() unregisterActivityLifecycleCallbacks(this) } //... Kotlin 69
  15. /** * 仕組みの説明 * 1) この Runnable は、App#onCreate 内でメインスレッドにポストされる *

    2) アプリプロセスがバックグラウンドから起動された場合、この Runnable は どの Activity#onCreate よりも先に実行される * 3) 一方、アプリがユーザーによって起動された場合は、必ず Activity#onCreate がこの Runnable より先にシステムによってスケジューリングされる */ class DetectStartFromBackgroundRunnable( private val tracer: Catracer ) : Runnable { override fun run() { val span = tracer.getOngoingSpan(AppSpans.COLD_APP_STARTUP_SPAN) ?: return if (!span.attributes.containsKey("has_been_started_by_user")) { // スパンをキャンセルするか、もしくはあえてバックグラウンドのケースを記録するか } } } Kotlin 70
  16. ネットワークリクエストの測定 75 fun provideOkHttpClient(tracer: Catracer): OkHttpClient { return OkHttpClient.Builder() .eventListenerFactory

    { TimingEventListener(tracer) } .build() } Kotlin 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() } Kotlin
  17. OpenTelemetry Collector 84 • 非柔軟 • 単一障害点 • 帯域幅が狭い •

    スケール不能 • OTelを始めるのに最適 • アプリとコレクターの 関係が明確 …
  18. Firebase Performance vs OTel 102 Firebase Performance OpenTelemetry SDK Open

    Source ❌ 🟢 Vendor-Lock Free ❌ 🟢 分散トレーシング対応 ❌ 🟢 自動計装 🟢 🔺(独自実装) サンプリング制御可否 ❌ 🟢 バックエンド・インフラの 分散トレース ❌ 🟢 Logの対応 ❌ 🟢
  19. OTel SDKのオート計装 一部の実装ではFirebase Performanceのようにオート計装 (Zero-code instrumentation)を利用可能 ◦ ANR(応答停止): 約5秒以上 UI

    が応答しない場合に Tracing 発行 ◦ クラッシュ(未処理例外): 例外の名前、メッセージ、スレッド情報など付きで Tracing 発行 ◦ フレームの描画が >16ms(slow)または >700ms(frozen)において Tracing 発行 ◦ Fragment ライフサイクルや UI インタラクションも自動追跡可能 104
  20. AIと連携したモニタリングについて • MCPのサーバーなどを利用すれば、任意のトレースに対して モニタリングの段階で以下のような改善の提案をしてくれる 105 In mobile apps, you can

    preload a connection before it’s actually needed: For example, as soon as the splash screen appears, fire an async HEAD or small request to the API to open the TCP/TLS connection. By the time the UI needs data, the connection is already live.