SlideShare a Scribd company logo
僕とJenkinsおじさんの
360日戦争
株式会社ミクシィ
Masaaki Goshima(@goccy54)
自己紹介
• 2012年度新卒としてミクシィに入社
• 趣味でPerlの処理系を作っている
• 技術部たんぽぽGに所属
– たんぽぽGって何? : 開発者のための開発を行う
– 具体的にどんなことしてるの?:
• 技術的負債を効率的に返済するための
ツール作成
• mixi.jpのJenkinsの保守・運用
Jenkinsとの出会い
• たんぽぽG配属後の6月某日、Jenkins
運用の命を受け、おじさんとの戦いの火
蓋が切って落とされた…
アジェンダ
• おじさんをどうにかするための準備
– mixiのテスト環境と課題の把握
• おじさんとの闘い、そして…
– テスト実行フローと課題解決
• おまけ
– mixiとおじさんのアブノーマルな関係
• mixiの変わったJenkinsの使い方の紹介
mixiのテスト環境と課題
mixiのリリースフロー
Jenkins
本番サーバ
deploy
時間
mixi.git
repositoryの変化
開発者
コミット
リリース時間
Full test
Full testの中身と実行環境
• 言語 : Perl
• テストファイル数 : 18000以上
• テスト項目数 : 25万以上
• 実行環境(Jenkins Slaveのスペック)
• CPU : 24 core (Xeon 2.67GHz)
• Memory : 64GB
テスト所要時間
min
おじさんから与えられた課題は
強大だった…
• Full testにかかる時間が長いと
その分リリースするまでに時間がかかる
…
さて、
どうしますか?
何らかの方法で
テスト実行を高速化する必要がある
課題を解決するためには…
テスト実行フローと課題解決
テスト実行の仕組みを詳細に
理解する
• 高速化のアプローチを考えるため、
テスト実行の仕組みをもっと掘り下げる
1. Jenkins X Perl
- テスト実行フローの理解
2. 並列実行の問題とFixture
- テスト実行方法の理解
1. Jenkins X Perl
Jenkins X Perl
Perlのテストファイル(18000)
Jenkins
Prove
テスト実行
1..1
ok 1
TAP形式の出力
収集
1
2
3
JUnit形式のXMLファイルを生成
4 5
結果を読み取って表示
Jenkins X Perl
Perlのテストファイル(18000)
Jenkins
Prove
テスト実行
1..1
ok 1
TAP形式の出力
収集
1
2
3
JUnit形式のXMLファイルを生成
4 5
結果を読み取って表示
この2つについて
もう少し詳しく解説
ProveとTAP
• Prove
– テストの並列実行・再帰的実行をサポート
– 失敗したテストだけ実行するなど多機能
– テスト側がTAP形式で出力することをサポートし
ていれば、他言語でも利用可能
ex) prove --ext=.js --exec node
• TAP(Test Anything Protocol)
– 成功なら「ok」、失敗なら「not ok」
– とにかくシンプル!
# test : xxx
ok 1 – pattern1
ok 2 – pattern2
2. 並列実行の問題とFixture
並列実行の問題
• mixiでは大量のテストを捌くために、
proveのオプションで並列にテストを処理
している
• 並列実行は高速実行するためにかかせな
いが、深刻な問題がある
共通DB参照によるデータ
不整合問題
DB(MySQL)
Prove
並列実行テストA テストB
Insert
select
delete
select
insert
select
期待した結果とは
異なる結果が返っ
てきて、テストが
FAILする
Fixture
• テスト毎に同一データから別DBを作成し
て、それを参照する
DB(MySQL)
Prove
並列実行テストA テストB
Insert
select
delete
select
insert
select
DB(MySQL)
テストA用のDB テストB用のDB
create create
ボトルネックの把握
• 大量のテストを処理する上では、次の
処理が無視できないオーバーヘッドにな
る
–Fixtureによるテスト毎のDB生成・破棄
–テスト毎のモジュール読み込み
• 巨大なモジュール/依存の多いモジュール
課題解決のために
~ テスト高速化手法 ~
高速化アプローチ
• モジュール読み込み時間を削る
–forkprove : proveで並列実行する際、fork
して子プロセスで行う
• 親プロセスでモジュールをロードすることで、
子プロセスでのモジュール読み込みが発生しない
• Fixtureで生成したDBをキャッシュする
– 一度DBを作成したら、Write処理
(Insert, Update, Delete)が発生するまでDBを使い
回す
• DB生成コストを削減
しかしそう簡単にはいかない
• よくも悪くもモジュールを先読みすると
不整合を生じるケースがある
– モジュールの読み込み順が大事な場合など
• 生成したDBをCacheする機構は実装が難
しく、実装コストと効果が釣り合うか分
からない
– ReadOnlyなテストがどれだけあるのか、調査
が必要
しかしそう簡単にはいかない
• よくも悪くもテスト側でモジュール読み込み
を行わないと、不整合を生じるケースがある
– モジュール読み込み時をhookして何かやる場合
など
• 生成したDBをCacheする機構は実装が難し
く、実装コストと効果が釣り合うか分からな
い
– ReadOnlyなテストがどれだけあるのか、調査が
必要
どうしたものかと悩みに悩む…
もはや高速化することはできないのか
そこに、48人の女神が現れた!
※正確には、AKBの名を冠した48のノードを
Jenkinsスレーブとして使えるようになった!
JKS48
テスト実行を複数ノードで!
Jenkins
テスト実行要求
Masterノード
Slaveノード
Slaveノード
Slaveノード
18000
6000
6000
6000(Rino)
(Mariko)
(Mayu)
(Yuko)
min
圧倒的勝利
• リソースって大事ですね
ひとまず、おじさんとの闘いはここで幕を閉じる
JKS48
mixiの変わったJenkinsの使い方
remotetest
• 負荷のかかるテストはJenkinsを介して行う
開発者
個人開発環境サーバ
ログイン
Jenkins
Jenkins Slaveサーバ
git://git.mixi.jp/repo.git –b branch
開発中のブランチをJenkinsに投げてしまう
空いているslaveでテストを実行
低スペック
高スペック
問題点1
• Jenkinsの仕様上、前のテスト結果を知る
必要があるため、後に実行したテストが
待たされる
テスト実行キューの順番
前
後
30分
50分
後に実行されたテストの方が
先に終わっても、
前のテスト結果が出るまで
待たされる
問題点2
• テスト実行キューを同じタイミングで大
量に投げられると、テスト終了時に
Jenkinsマスターノードが高負荷になる
テスト実行キューの順番
1分おき
Master
テスト結果を表示するための計算やレンダリング処理
ほぼ同タイミング
おわりに
• remote testにも適した軽量CIツールの
導入が期待される
• 構想はあるので、試しに作ってみます
ぼくとJenkinsおじさんの360日戦争
ぼくとJenkinsおじさんの360日戦争

More Related Content

ぼくとJenkinsおじさんの360日戦争