全国1億2000万の Docker ファンの皆さんこんにちは。

MySQL の起動がとてつもなく遅いのは有名な話。 ところが Docker コンテナの起動はなかなか早いので、 MySQL を使っているようなテストを高速化するケースで有用性が認められるのではないかと思って PoC を書いてみた。

(宣伝)こういった話も含めて YAPC でトークしたいので SNS 等で upvote お願いします: ( ✌'ω')✌ 楽しいモデル層開発 - YAPC::Asia Tokyo 2014 (宣伝おわり)

MySQL を使ったテスト

MySQL を使ったテストをする場合、だいたい次の 2 パターンになる。

  • MySQL をテストのたびに起動してクリーンな状態で使う
  • ローカルにデーモンとして起動した MySQL に接続して DROP TABLETRUNCATE でクリーンな状態にして使う

だけど、「起動が遅い」「setup/teardown に時間がかかる」「並列にテストできない」といった問題を抱え、最終的にはスローテスト問題に帰結する。

Test::Docker::MySQL

都度 MySQL を使うようなテストは MySQL の起動が高速化さえすれば既知の問題は解消でき、更にそのままテスト時間の短縮に繋がる。

そこで Test::Docker::MySQL を PoC として書いてみた。結果としては、

  • 起動時間が 30 sec -> 4 sec に短縮
  • MySQL を複数起動できるので並列にテストを実行できる

と、トータルのテスト時間は相当短縮できる結果になって今後の方針に影響を与える結果になった。

使い方

ドキュメントに書いてあるとおりに docker をセットアップすれば次のように使える。 Docker Hub 便利。

use Test::Docker::MySQL;
my $dm_guard = Test::Docker::MySQL->new;
my $port = $dm_guard->get_port;

my $dsn = "dbi:mysql:database=mysql;host=127.0.0.1;port=$port";
my $dbh = DBI->connect($dsn , 'root', '', { RaiseError => 1 });

ポイント

  • Test::Docker::MySQL#get_portdocker run ... が走る
    • コンテナの起動は早い
  • Test::Docker::MySQL のインスタンスがスコープを抜けると docker kill ... を自動的に実行してくれる
    • スコープをベースとして MySQL インスタンスを管理できる

ベンチマーク

だいたい次のようになって、インスタンス起動数が増えるごとにどんどん差が広がる。

  • Test::Docker::MySQL

    $ cat tdm.pl
    use Test::Docker::MySQL;
    
    
    my $dm_guard = Test::Docker::MySQL->new;
    my $port_1 = $dm_guard->get_port;
    my $port_2 = $dm_guard->get_port;
    
    
    $ time perl tdm.pl
    real    0m4.020s
    user    0m0.134s
    sys     0m0.059s
    
  • Test::mysqld

    $ cat tm.pl
    use Test::mysqld;
    
    
    my $mysqld_1 = Test::mysqld->new(
        my_cnf => { 'skip-networking' => '' }
    );
    my $mysqld_2 = Test::mysqld->new(
        my_cnf => { 'skip-networking' => '' }
    );
    
    
    $ time perl tm.pl
    real    0m30.291s
    user    0m1.002s
    sys     0m1.200s
    

既知の問題

docker run ... コマンドが戻った直後には実は MySQL に接続できなくて、 1.2 秒後くらいに接続できるようになる。 なので、ライブラリの内部では 0.2 秒ごとに接続をリトライしている。

原因がわかっていなくて、 port forwarding か何かがネックになっているのかとか邪推しているけど、理由知っている人がいたら教えて欲しい。