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

広告配信基盤を支える Rust プロジェクトの CI を高速化してみた!

Avatar for Eno Eno
September 18, 2025

広告配信基盤を支える Rust プロジェクトの CI を高速化してみた!

Avatar for Eno

Eno

September 18, 2025

Other Decks in Programming

Transcript

  1. プロジェクトの課題 
 CI/CDが遅く、DEV環境にリリースするまでにも1時間程度かかってしまい作業が滞ってしまう 
 (機能ブランチ)pre-testing.yaml 
 ↓
 (masterブランチ)マージ 
 ↓


    (releaseブランチ)masterからPR 
 ↓
 (releaseブランチ) pre-testing.yaml 
 ↓
 (releaseブランチ)マージ 
 ↓
 release.yaml
 ↓
 (CDKリポジトリ)コンテナイメージ更新PR 
 ↓
 (CDKリポジトリ)PR中でのCI 
 ↓
 (CDKリポジトリ)マージ 
 ↓
 devリリース

  2. 個人のモチベーション 
 - 個人要因
 - Rustの勉強がしたい
 - カリカリにチューニングすることに興味がある
 - 環境要因


    - 配属されたからには何か定量的な成果を得て安心したい
 - 大型PJにアサインされた都合上設計をしている時間が圧倒的に多く、成果に対して焦燥感にかられていた
 →「レビューなどをしてもらっている間にこれやっておきました〜みたいな感じでやっちゃおう!」 

  3. 実践したこと 
 フルコンパイルをできるだけ避けるようにする (←主にこっちについて話します) 
 - 依存クレートを含めて毎回コードベースをフルコンパイルしてしまっていた 
 - 依存クレートのダウンロード時


    - Docker Build時
 - テスト時にしか走らないコンパイルが余計に発生してしまっていた 
 - テストランナーダウンロード時のプロダクションコード・当該クレートのフルコンパイル
 - Integration Test用にCI環境上に立てたDBコンテナへのマイグレーションスクリプト自体のフルコンパイル
 
 余計なCIの実行を削除する 
 - そもそも実行しなくていいステップやジョブ、ワークフローがあるのではないか? 
 

  4. フルコンパイルをできるだけ避ける 
 1. actions/cacheを使って依存クレートのビルド結果をキャッシュする 
 依存クレートのビルド結果をキャッシュしてプロダクションコードのみをコンパイル対象にする。 
 👍キャッシュが新鮮なうちは意図した通りにビルド時間を短縮することができる。 
 ⚠キャッシュが保存されてから数日経つと、「依存クレートの依存クレート」のバージョン更新などで結局当該

    クレートにコンパイルが発生してしまう 
 masterブランチ上に保存したキャッシュはヒットするたびに保存期間が7日間にリセットされるためどんどん古く なっていってしまう。 
 
 → actions/cacheを使って依存クレートを1日1回キャッシュするバッチを回すようにし、他のCIはこのキャッシュ を参照するようにすることで安定して新鮮なキャッシュを利用するようにした。 
 
 
 4-5minの短縮
  5. フルコンパイルをできるだけ避ける 
 2. サードパーティのクレートをダウンロード時はpreビルド済み配布物をダウンロードする 
 テストランナーとして cargo-nextest を使用しているが、taiki-e/install-actionを使ってpreビルド済みの配布物 をダウンロードするようにする 


    👍そのままインストールしてプロダクションコードベースを含めてフルコンパイルが走ってしまう時とは違い、瞬 時にダウンロードが完了する 
 👍cargo-nextest の公式からも推奨されているインストール方法 
 > Pre-built binaries can be used in continuous integration to speed up test runs.
 
 
 5minの短縮
  6. フルコンパイルをできるだけ避ける 
 3. Docker Layer Cache として依存クレートの成果物をキャッシュする 
 👍マルチステージビルドをさらに細分化し、Docker Layer

    Cacheに切り出すことができるレイヤーを最適化し、 cargo-chef を使って依存クレートのビルド結果をキャッシュすることでDocker Build時の所要時間を短縮する 
 
 https://docs.docker.com/build/cache/ 
 15minの短縮
  7. フルコンパイルをできるだけ避ける 
 4. CI環境で行うmigrationの実行結果をキャッシュから復元する 
 ※Integration Test用にCI環境上に立てたDBコンテナへのマイグレーションスクリプトをクレートとして切り出し ていたが、スキーマやシードデータには変更は滅多にないにもかからわず当該クレートと依存クレートをフルコ ンパイルした上でコンテナの起動を行っていた。 


    
 👍MySQLコンテナは通常、データを /var/lib/mysql ディレクトリに保存するためこのディレクトリをコピー ・actions/cacheを使ってキャッシュし、次回以降この復元されたディレクトリをマウントした状態でコンテナを立ち 上げることでマイグレーションスクリプトの実行をスキップ(≒ マイグレーションスクリプトクレートのコンパイル の回避)
 
 3minの短縮
  8. appendix 
 リンカーとしてmoldを使用するようにする 
 コンパイル時間の遅さを解消するためにより高速なリンカーとしてmoldというリンカーがある 
 
 - 今回はコンパイル箇所を減らす方向でチューニングをした 


    - リンカーによる優位性が顕著に見られるほどコードベースが大きくないため(?)あまり効果が見られな かった
 - とはいえキャッシュを保存するときのworkflowのコンピューティング時間を減らすことは良いことなので一 応採用している

  9. appendix 
 rustc 1.90.0 でデフォルトのリンカーが従来よりも高速なlldというリンカーになるらしい 
 
 > TL;DR: rustc

    will start using the LLD linker by default on the x86_64-unknown-linux-gnu target starting with the next stable release (1.90.0, scheduled for 2025-09-18 ), which should significantly reduce linking times. Test it out on beta now, and please report any encountered issues. 
 > The linking phase is too slow. This was a very common complaint, and it is indeed a real issue, because unlike the rest of the compilation process, linking is always performed "from scratch". The Rust compiler usually delegates linking to an external/system linker, so its performance is not completely within our hands. 
 Rustのコンパイルの処理の中でもリンク部分は外部システム(LLVM lld)に移譲して いるためリンク処理自体の改善は難しいとのこと
 デフォルトのリンカーをlldというより高速なリンカーに代替する変更が入ったバージョン1.90.0 がちょう ど今日安定版になるらしい 🎉
 今後に期待!