前置き
Goのプロジェクトも大きくなってくると、go testに時間がかかってくる様になりますよね〜
私の愛してやまないGAE/Goの場合は特に、テストケースの度にpythonのローカルサーバープロセスが起動する為、バカにならない時間がかかります。
そこで金の弾丸に物を言わせて、Google Container Engine(GKE)でcoreたくさんぶん回してテストを並列実行してみたらどうだろうか、と思い立ち、実験してみました。
GKEのセットアップは↓をほぼそのまま参考にさせてもらいました。とても簡単にできました\(^o^)/
GKE を使って golang アプリケーションコンテナを稼働させる
※ 今回はGKEから外向きにポートは開かないので、Serviceの設定は不要です
概要
用意した資材はこちら。
https://github.com/knightso/honeybee
とりあえず実験目的でかなりテキトーに作った状態なので、今回は詳しいsetup手順は割愛して処理の概要だけ紹介します。
(↑の資材リポジトリに必要なコードは揃ってるので興味のある人はどうぞ)
処理の流れ
クライアント(hb-client)
1. ローカルのgoファイルを解析して、テスト対象のパッケージ&関数のリストを作成
テスト対象のパッケージとファイル名の抽出は手抜きをしてgo list
(実際にはgbを使っているのでgb list
)を利用しました。
$ go list -f '{{.ImportPath}}:{{.Dir}}:{{range .TestGoFiles}}{{.}},{{end}}{{range .XTestGoFiles}}{{.}},{{end}}' ./...
これで、
importパス:ディレクトリ:hoge_test.go,fuga_test.go,piyo_test.go,...略...
みたいなレコードのリストが出力されます(便利ですね!)。
それを標準入力で受け取り、各ファイルのASTを解析し、テスト関数名を抽出しています。
→コード
2. テスト関数毎にリクエストを作成し、GAEのTaskQueue(PULL)に送信
1で解析した情報をもとにリクエストパラメータを作成し、Google Client Libraryを利用してGAEのTaskQueue(PULL)に送信します。
リクエストパラメータ |
---|
UUID |
github commit番号 |
パッケージ |
ファイル名 |
テスト関数名 |
→コード
※ 今回メッセージのやりとりにGAEのTaskQueueのみを利用しました。GAEアプリ自体は使用していません。
コンテナ(hb)
1. Taskqueueからリクエストを一件Lease
クライアントが送信したリクエストをTaskQueueから取り出します。
→コード
Lease関数で取り出した後はDeleteする必要があります。
→コード
2. githubの指定されたcommitをcheckout
ある時点までのレポジトリはdocker build時にイメージ内に、あらかじめcloneしておきます。
コンテナでは、リクエストで指定されたcommit番号でgit checkout
します。
→コード
ただ・・差分のみの取得とはいえ大量のコンテナから集中してgit checkout
するのはどうなんだろう?との懸念から現在は一旦処理をコメントアウトしてます。
3. テスト関数を指定してテスト実行
カレントディレクトリにtest.sh
というスクリプトを用意しておくとキックする仕組みにしました。
→サンプルコード
サンプルではgbを利用していますが、go testでもいけます。
4. テスト結果をTaskQueue(PULL)に送信
テスト結果を結果用TaskQueueに送信します。
→コード
送信する際に、Tagにクライアントから送られてきたUUIDを指定しています。こうすることでクライアントは自分の送信したUUIDに紐づく結果のみをLeaseすることが出来ます。
5. ログとしてCloud Datastoreにも保存
→コード
再度クライアント(hb-client)
1. TaskQueueの結果リストを監視(UUIDでタグを指定してLease)
TagにUUIDを指定して、TaskQueueからLeaseしています。
→コード
2. 送信したリクエストの数だけ結果が返ってきたらレポート出力して終了
結果
手元の開発中プロジェクトでテストしました。
まずはローカルで普通にgo test
テストケース数 | 実行時間 |
---|---|
320 | 約1,000秒 |
たった320件で1000秒って時間かかりすぎだろ!ってカンジですが、GAE/Goのaetestだとこんなカンジです。 |
↓↓
GKEクラスターで分散実行!
core数 | pod数 | 実行時間 |
---|---|---|
320 | 320 | 約80秒 |
10倍以上速くなった! \(^o^)/
と一瞬喜んでみましたが、coreが320倍になったのに実行時間はたったの10倍ってちょっとひどいですね(^^;
まあ完全並列実行しても一番長いテストケースの実行時間に集約されてしてしまうので、仕方ない面もありますが・・・費用対効果考えるとかなり微妙ですね。。
・・・という訳で軽く玉砕した感がありますが、せっかくなので記事にさせてくださいm(_ _)m
今回作成したコードは、もうちょっと実用性が上がってツールとしての体裁が整ったら改めて紹介したいな、と思っています。
ではでは、良いお年を〜