Slide 1

Slide 1 text

Qiita 株式会社 Tomoya Chiba (@tomoasleep) GitHub Actions による RSpec の時間を半分以上短 縮した話 1

Slide 2

Slide 2 text

千葉 知也 (@tomoasleep) Qiita: https://qiita.com/tomoasleep Twitter: https://twitter.com/nemunemu3desu Qiita 株式会社 共通基盤グループ シニアエンジニア Qiita の開発、運用、技術全般をいい感じにする仕事を しています 自己紹介 2

Slide 3

Slide 3 text

GitHub Actions, Datadog 前提の話がちょこちょこあります ざっくりこんな感じで CI 改善するんだなっていう感じで見てもらえると おことわり 3

Slide 4

Slide 4 text

10 年以上続く & モノリスで Qiita はたくさんのテストがある CI の時間も長くなってしまっていた 課題: CI が遅い 4

Slide 5

Slide 5 text

CI の速度 ≒ Try & Error の速度 CI が遅いと開発のボトルネック、ペースダウンになる 不安定なテストがあると更に足を引っ張る これを改善していきたい → サイドタスクとして進める Why?: CI の速さは開発の速さ 5

Slide 6

Slide 6 text

CI 高速化のために取り組む 6

Slide 7

Slide 7 text

… まず何をする? 7

Slide 8

Slide 8 text

継続的に 計測できる状態にする 一番遅い部分を直す → 高速化 改善効果の可視化、定量化 悪化していることに気付ける & 気にするようにする まずは計測から始める 8

Slide 9

Slide 9 text

GitHub Actions は標準だとテストや実行時間の分析が弱い int128/datadog-actions-metrics を利用している Workflow 全体や Job 単位の実行時間などを Datadog に送ってくれる Qiita での計測方法: カスタムアクションを使っている 9

Slide 10

Slide 10 text

より高機能なものとして、 Datadog 公式の CI/CD の可視化機能もある https://www.datadoghq.com/ja/product/ci-cd-monitoring/ Flaky Test の検出、テストのデバッグ、などは魅力的だが… まずは必要な計測を小さく始めて、定着させるために、一旦見送り int128/datadog-actions-metrics も各種費用は掛かる 送信用 GitHub Actions の実行料金 各 Workflow の課金時間が +1 分 されるイメージ Datadog Custom Metrics の量に応じた料金 計測方法の選定 ( 詳細) 10

Slide 11

Slide 11 text

開発の活発さを表す指標 ( デプロイ回数, etc) 改善するしばらく前から取っていたほうが良い 費用関連の情報 ( 全体的な料金、課金時間、実行回数, etc) マシンスペック、マシン台数は金銭コストとのトレードオフ 無駄なコストを削減 → 費用掛けたい部分に回す 継続的に取るのがやや面倒 「GitHub API で GitHub Actions の課金時間、平均課金時間を計算する」 https://qiita.com/tomoasleep/items/91159263a0c11dffbf7c 他に計測したほうが良いもの 11

Slide 12

Slide 12 text

小さい工数で大きく改善したい → 並列の質と量を上げる 量 GitHub Actions の並列数 (Matrix) の調整 parallel_tests の導入 質 テスト配分のバラツキを抑える 今回の改善方法: 並列の質と量を上げる 12

Slide 13

Slide 13 text

n 分割するので、時間を減らすのに大きく貢献する 各マシンで必要な処理分、費用が増えてしまう 量の改善その1: GitHub Actions の並列数 (Matrix) の調整 13

Slide 14

Slide 14 text

手っ取り早く時間を減らすのに大きく貢献する 各マシンで必要な処理分、費用が増えてしまう GitHub Actions の並列数 (Matrix) の調整 14

Slide 15

Slide 15 text

手っ取り早く時間を減らすのに大きく貢献する 各マシンで必要な処理分、費用が増えてしまう Ruby, RSpec, 各種インフラのセットアップ等… ※ Cache 等で緩和可能 GitHub Actions の並列数 (Matrix) の調整 15

Slide 16

Slide 16 text

調整 → 計測を繰り返す 費用とのトレードオフがあるので、いい塩梅で調整する 複数種類ある CI の時間を同じぐらいになるように調節する → 今回の改善: 費用との兼ね合いで、並列数 1.3 ~ 1.6 倍程度で調整 最も遅いもので、34 分 → 20~24 分程度の改善 GitHub Actions の並列数 (Matrix) の実際の調整 16

Slide 17

Slide 17 text

https://github.com/grosser/parallel_tests 適切な並列数で RSpec, minitest, ...etc を並列実行 RSpec コマンドを同時に複数実行している $ parallel_rspec --verbose -- spec/hoge_spec.rb spec/fuga_spec.rb 2 processes for 2 specs, ~ 1 specs per process TEST_ENV_NUMBER= PARALLEL_TEST_GROUPS=2 rspec spec/hoge_spec.rb TEST_ENV_NUMBER=2 PARALLEL_TEST_GROUPS=2 rspec spec/fuga_spec.rb 量の改善その2: parallel_tests を導入する 17

Slide 18

Slide 18 text

matrix のメリットに加えて… 、 遊んでいる CPU を有効活用するので早くなるし、安くなる (GitHub Actions のデフォルトは 2core なので CPU が余りがち) コア数分の並列なので、 Matrix よりは並列数の自由度は小さい 複数の RSpec 間のデータが干渉しないように設定する必要がある parallel_tests のメリット、デメリット 18

Slide 19

Slide 19 text

RSpec は増えるが、RDBMS, Redis, Elasticsearch, FileSystem, は増えない それぞれでアクセス箇所を分ける必要がある 割り振られた番号 (TEST_ENV_NUMBER) を prefix, suffix として使って分ける parallel_tests 導入の注意点: 相互の干渉を防ぐ 19

Slide 20

Slide 20 text

スコープを絞る ( 逼迫してない System Spec, Feature Spec では見送り) 事前に変なの見つけたら教えてとお願いしておく RSpec の tag で、並列実行出来ないものは除外出来るように備えた it ' 並列実行したくないやつ', :no_parallel do end Qiita での parallel_tests 導入 (Matrix 変更と併用) 20

Slide 21

Slide 21 text

導入後: 2core のマシンで、実行時間、課金時間が 30~40% 削減 20~24 分 → 14 分程度に改善 Qiita での parallel_tests 導入 21

Slide 22

Slide 22 text

実行時間のばらつき を、過去の実行時間ベースの配分で抑える テストレポートを出力, 配分に利用できるツールがあるのでそれらを使う https://github.com/sj26/rspec_junit_formatter https://github.com/mtsmfm/split-test 巨大なテストファイルがあると、配分しきれないこともあるので要チェック 質の改善: 実行時間ベースのテスト配分 22

Slide 23

Slide 23 text

34 分程度 → 14 分程度に改善 CI がまだ終わっていないという状態は明らかに減った ( ヒアリングで改善の反応を集めたが、指標でも改善が分かると良かった) コストも改善前より若干安い程度に抑えられた 最終的な効果 23

Slide 24

Slide 24 text

CI の計測が本当に大事 ( 比較的) 安価に出来る手段はあるので使おう 上手く並列実行するための方法を紹介した 並列数の調整: 楽かつ効果的だが費用に注意 parallel_tests: 設定必要だが、速度にも費用にも寄与 実行時間ベースの配分: 並列数が多い、ばらつきが多いならあり まとめ 24