• 18
    いいね
  • 0
    コメント

前置き

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

今回作成したコードは、もうちょっと実用性が上がってツールとしての体裁が整ったら改めて紹介したいな、と思っています。

ではでは、良いお年を〜

この投稿は Go Advent Calendar 201620日目の記事です。