大規模Androidアプリ開発を支えるデリバリー - ビルド時間長期化への立ち向かい方
by
gree_tech
Link
Embed
Share
Beginning
This slide
Copy link URL
Copy link URL
Copy iframe embed code
Copy iframe embed code
Copy javascript embed code
Copy javascript embed code
Share
Tweet
Share
Tweet
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