Slide 1

Slide 1 text

大規模Androidアプリ開発を支える デリバリー ビルド時間長期化への立ち向かい方 REALITY株式会社 エンジニア 小宮光滋

Slide 2

Slide 2 text

Komiya Mitsushige 2014年にグリー株式会社(現:グリーホールディ ングス株式会社)へ入社。 株式会社WFSでモバイルゲームのクライアント開 発を経た後、REALITY株式会社にジョイン。 Android開発を中心に携わり現在はテックリードを 務めている。 REALITY株式会社 エンジニア 2 REALITY上の姿 リアルワールド上の姿

Slide 3

Slide 3 text

目次・アジェンダ ● REALITYについて ● ビルド処理の様々なプロファイリング方法 ● 見えてきたREALITYでの課題 ● 一般的な最適化の方法 ● REALITY固有の問題への対応 ● 全体のビルド時間推移とまとめ 3

Slide 4

Slide 4 text

目次・アジェンダ ● REALITYについて ● ビルド処理の様々なプロファイリング方法 ● 見えてきたREALITYでの課題 ● 一般的な最適化の方法 ● REALITY固有の問題への対応 ● 全体のビルド時間推移とまとめ 4

Slide 5

Slide 5 text

REALITYについて 5

Slide 6

Slide 6 text

6 自分好みのアバターで ライブ配信 ● 2018年8月リリースの バーチャルライブ配信アプリ ● 今年の8月で7周年を 迎えました🎉

Slide 7

Slide 7 text

実はピュアUnity製ではない作り 7

Slide 8

Slide 8 text

実はピュアUnity製ではない作り 8

Slide 9

Slide 9 text

積み重なった7年以上の歴史 ● 運用年月により積み重なった数多くの画面・機能が存在する ○ 配信・視聴 ○ チャット ○ フィード投稿などなど…… ● 日々膨れ上がるコードベース ● モジュール数は89個 ● Kotlinの行数は約31万行 ● 依存ライブラリは約200個 9

Slide 10

Slide 10 text

長くなっていくビルド時間 場合によっては 1時間以上かかることも! 10

Slide 11

Slide 11 text

なんとかしよう 11

Slide 12

Slide 12 text

⚠ Caution ● 一般的な改善手法の紹介も含みますが、一方でREALITYアプリ内での限 定的な内容が含まれる可能性があります ● Androidアプリのビルドパイプラインに関わる方を対象とする関係上、 Gradleとは何か?などの一般的なツールの説明については含まれない場合 があります 12

Slide 13

Slide 13 text

Androidビルド環境について ● Gradle 8.14.3 + AGP 8.12.1 ● CI/CDはGitHub Actionsで実行 ● 開発・QA用アプリはFirebase AppDistributionで配布 13

Slide 14

Slide 14 text

目次・アジェンダ ● REALITYについて ● ビルド処理の様々なプロファイリング方法 ● 見えてきたREALITYでの課題 ● 一般的な最適化の方法 ● REALITY固有の問題への対応 ● 全体のビルド時間推移とまとめ 14

Slide 15

Slide 15 text

ビルド処理の様々なプロファイリング方法 15

Slide 16

Slide 16 text

CI Analyzerによる GitHub Actions Workflow の情報収集と可視化 ● CIサービスからビルドデータを 収集するOSSツール ● GitHub Actionsで稼働 ● データはBigQueryに収集 ● Looker Studioで可視化 ● ビルド時間の推移を可視化出来る 16

Slide 17

Slide 17 text

Actions Runnerの マシンリソース使用率の 可視化 ● catchpoint/workflow-telemetry- action ● yamlに数行追加でSummary上に マシンのメトリクスを可視化 ● CPU / Memory / IOを グラフで可視化してくれる ● ログを入れるよりもラク 17

Slide 18

Slide 18 text

Gradle Build Scan ● Gradleビルドメタデータの収集 ● 各タスクレベルに分割して タイムライン可視化 ● 各タスクのキャッシュヒット キャッシュミスなど細かい 分析が可能 ● 詳細分析にはこれがおすすめ 18

Slide 19

Slide 19 text

目次・アジェンダ ● REALITYについて ● ビルド処理の様々なプロファイリング方法 ● 見えてきたREALITYでの課題 ● 一般的な最適化の方法 ● REALITY固有の問題への対応 ● 全体のビルド時間推移とまとめ 19

Slide 20

Slide 20 text

見えてきたREALITYの課題 20

Slide 21

Slide 21 text

以下に時間がかかっている傾向がある ● R8によるminify ○ 充分なヒープがあるにもかかわらず、処理時間が安定していない ○ ビルドごとによって振れ幅が大きい ○ R8だけで6m ~ 1hも振れ幅がある ● Protocol Buffersからのコード生成・コンパイル時間 ● 外部ライブラリ関係のDexファイルの処理 21

Slide 22

Slide 22 text

原因は見えてきた 22

Slide 23

Slide 23 text

なにはともあれ 一般的な最適化からやってみよう 23

Slide 24

Slide 24 text

Android公式には ビルド速度最適化ガイド が存在する ● おすすめの手法 ● ビルド構成最適化のヒント ● 速度改善のための一般的な プロセスの紹介 などなど 24

Slide 25

Slide 25 text

目次・アジェンダ ● REALITYについて ● ビルド処理の様々なプロファイリング方法 ● 見えてきたREALITYでの課題 ● 一般的な最適化の方法 ● REALITY固有の問題への対応 ● 全体のビルド時間推移とまとめ 25

Slide 26

Slide 26 text

一般的な最適化の方法 26

Slide 27

Slide 27 text

Gradle Configuration Cache ● Gradleの構成フェーズをキャッシュ化するもの ● GitHub Actions上で適切に使うにはコツがいる(後述) ● ⇒約32%のビルド時間削減(Releaseビルド, キャッシュヒット時) 27

Slide 28

Slide 28 text

setup-gradle actionsでのキャッシュ保存 ● Gradle ユーザーホームディレクトリの重要な部分をキャッシュ ● setup-gradleを使ったビルドやテスト処理を回しキャッシュを更新 ● キャッシュの使用状況の詳細なレポートも出してくれる ● GitHub ActionsのCacheは10GB制限なので注意 ● Configuration Cacheも保存出来るが、利用に暗号化キーの設定が必要 28

Slide 29

Slide 29 text

actions/cacheによるbuild dirキャッシュ ● setup-gradleで保存されない部分をキャッシュ ● 特にGradleのConvention Pluginを採用している場合、該当モジュールの buildディレクトリが無いとConfiguration Cacheを再利用できないこと がある 29

Slide 30

Slide 30 text

Gradle Remote Cacheについて ● GCSやAWS S3でRemote Cacheを ホスト出来る ● 単純に使うだけではビルド時間は 逆に長くなってしまった ○ キャッシュファイルの ネットワークIOコストが掛かる ● うまく運用できている方いたら 是非お話しましょう 30

Slide 31

Slide 31 text

JVM heap/metaspaceの最適化 ● VisualVMを用いてローカル環境での使用量チェック ● そこから大まかに見積もってheap/metaspaceサイズを決める 31

Slide 32

Slide 32 text

Parallel GC利用 ● GCはデフォルトのG1GCからParallel GCに変更 (-XX:+UseParallelGC) ○ G1GCは大規模メモリ向けで低遅延 ○ Parallel GCはスループット重視 ● REALITYでのアプリビルドではParallel GCの方が速度面で優秀 ● ⇒ Debugビルドは約27.2% ● ⇒ Releaseビルドは約7.5%のビルド時間削減 32

Slide 33

Slide 33 text

kaptの廃止(DataBindingの廃止) ● kaptはJava スタブを生成するコストがある ● 古い機能などはDataBinding実装のものが残っていた ● まずViewBinding化、少しずつJetpack Compose化 ● あまり削減は出来なかったが レガシーコードの改善という点でも有用 33

Slide 34

Slide 34 text

GitHub Actions Larger Runner ● 強いマシンは早い ● ubuntu-latest-16coreマシンを利用 ● マルチコアスケールするようにGradleの並列ビルド設定を忘れずに ● worker数はデフォルトを利用(プロセッサ数と同じworker数) ● 強いマシンはRAMも多く、特にGradleビルドでは恩恵が大きい ● 特に前述のJVMヒープ調整もやりやすくなる 34

Slide 35

Slide 35 text

目次・アジェンダ ● REALITYについて ● ビルド処理の様々なプロファイリング方法 ● 見えてきたREALITYでの課題 ● 一般的な最適化の方法 ● REALITY固有の問題への対応 ● 全体のビルド時間推移とまとめ 35

Slide 36

Slide 36 text

REALITY固有の問題への対応 36

Slide 37

Slide 37 text

時間がかかっている処理おさらい ● R8 ⇐!!特に時間がかかっている!! ○ 処理時間が安定しておらず、ビルドによって振れ幅が大きい ○ R8だけで6m ~ 1hも振れ幅がある ● Protocol Buffersからのコード生成・コンパイル時間 ● 外部ライブラリ関係のDexファイルの処理 37

Slide 38

Slide 38 text

R8に立ち向かう 38

Slide 39

Slide 39 text

R8は難しい ● もともと処理時間がかかる ● 公式ではビルド速度やデバッグの観点から 必要なとき以外は実行しないように言及されている ● 時折長期化することがGoogle Issue Trackerにも数多く挙げられている 39

Slide 40

Slide 40 text

せめて処理時間を安定させたい 40

Slide 41

Slide 41 text

runInSeparateProcess 41 ● R8実行プロセスを Gradleデーモンから分離する ● ヒープサイズをGradleデーモンと は別で割り当てられる ● rootのsettings.gradle.ktsに設定 ● ⇒ 処理時間は6~10min程度に安定 ⇒ 90%近い処理時間削減

Slide 42

Slide 42 text

どうにもならなくなったら ● runInSeparateでもダメな場合、ヒープサイズやマシンスペックが 追いついていない可能性がある ● コストの兼ね合いで強いRunnerを使えないこともある ● Debugビルドを活用し、QAやリリース前検証など、 本当に必要な場合にのみReleaseビルドを利用することを検討しよう 42

Slide 43

Slide 43 text

Protocol Buffers由来の コード生成やコンパイルについて 43

Slide 44

Slide 44 text

大量の.protoと生成コード、乗らないキャッシュ ● REALITYではWebAPI req/resをProtocol Buffersでシリアライズ ● 実装でKotlin DSLを使っているためJava / Kotlin双方生成している ● 生成ファイル数が多く、特にKotlinのコンパイルに時間がかかる ● 注意深く見ていくと、キャッシュヒットがほとんどないことがわかった 44

Slide 45

Slide 45 text

Gradle Cache Keyについて ● org.gradle.caching.debug=true指定すると Task毎のキャッシュキーの計算過程をログ出力出来る ● キャッシュ生成/利用時のTaskで計算過程がどこでズレるかチェック 45

Slide 46

Slide 46 text

Gradle Cache Keyについて ● 今回はGradle Build Scanの有無でinputArtifactsやcompilerOptionsの 入力が異なっており、結果キャッシュキー計算が変化してヒットしていな いことが分かった ○ つまり分析時のみキャッシュヒットしにくい状況になってしまっていた…… ● Build Scan向けにもキャッシュを作ることで解決 ● ⇒ キャッシュヒット時は約93%の処理時間削減 ⇒ ただ分析中のみの劣化であり、あまり実感につながるものではない 46

Slide 47

Slide 47 text

外部ライブラリ関係のDexファイルの処理 47

Slide 48

Slide 48 text

Dexファイルとは ● Dalvik 実行可能ファイルの略 ● 大雑把にまとめるとJava(Kotlin)ファイルをAndroid環境で実行可能な 形式に変換圧縮したもの ● 外部ライブラリ関係のdexをまとめる処理に時間がかかる ● => 外部ライブラリが多い! 48

Slide 49

Slide 49 text

外部ライブラリが多い! ● 色々ライブラリが残ってしまっている状態があった ● LiveDataなどの古い実装由来のもの ● 画像表示ライブラリ、通信ライブラリなど 複数の選択肢があり混在して投入されそのままになっているもの ● Material Design 2/3 ● やむなく複数バージョンを共存させているもの(JUnit4, 5など) 49

Slide 50

Slide 50 text

ライブラリ移行にAI Code Agentが有効 ● 移行事例のサンプルがあると AIに真似させやすい ● 定型的であるとより効果的に 機能する ● 自立してイテレーションを回すために 単体テスト環境が充実していることが 望ましい 50

Slide 51

Slide 51 text

コードを減らす取り組み ● 改善Week ○ 先送りされがちな改善項目にフォーカスする一週間 ○ ライブラリアップデートや移行などもよく行われる ● REALITYダイエット計画 ○ 未使用機能・使用率の低い機能を消していく取り組み ○ 2〜3000行ほどのコード削減 ● まだまだ改善の余地はあり、頑張っています ● こうした取り組みに興味がある方は是非、 この後のアスクザスピーカーなどでお話出来ればと思います 51

Slide 52

Slide 52 text

目次・アジェンダ ● REALITYについて ● ビルド処理の様々なプロファイリング方法 ● 見えてきたREALITYでの課題 ● 一般的な最適化の方法 ● REALITY固有の問題への対応 ● 全体のビルド時間推移とまとめ 52

Slide 53

Slide 53 text

全体のビルド時間推移とまとめ 53

Slide 54

Slide 54 text

ビルド時間全体の推移 54

Slide 55

Slide 55 text

まとめ 1/2 ● Gradle Taskレベルのプロファイリングには Gradle Build Scanがおすすめ ● 一般的な改善策としてはGC選択、ヒープ調整、スペックアップが 導入しやすい ● Gradle Configuration Cacheはクセがあるので注意 ● R8で問題があったらrunInSeparateProcessを試す ● キャッシュヒットしない場合はデバッグオプションで調査 ● 依存するライブラリは可能な限り減らしていく 55

Slide 56

Slide 56 text

まとめ 2/2 ● ビルド速度の最適化手法は多岐に渡り、GradleやCI/CD環境など アプリロジックの実装とは系統の異なる知識を求められる ● 一方、可視化の道具や一般的な最適化手法はある程度まとまっており、 出来る範囲から段階的に進めていきやすい側面もある ● 迅速に成果が出てこないこともあり、粘り強く改善の取り組みを 続けていくことが重要 56

Slide 57

Slide 57 text

ご清聴ありがとうございました 57

Slide 58

Slide 58 text

No content