Posted at

RailsのRSpecにとってDocker for Macはどれぐらい遅いのか?

More than 1 year has passed since last update.

Railsを開発しているとRSpecの実行時間が遅くて開発効率が悪くなることがあります。

これは開発環境にDocker For Macを使っているからでしょうか?


背景

Docker For Macは遅いと言われます。

これは現在のDocker For Macでも遅いのでしょうか?


rawフォーマットは試していません

また、最新のDocker For Macでは速くなっているようです。

Docker for Macのディスクスループットを約2倍にする - Qiita


Docker Community Edition 17.12.0-ce-mac46 2018-01-09 (Stable)の更新で、ディスクスループットが320MiB/secから600MiB/secになるらしいので適用する。

APFS, SSD, High Sierraで有効。


現在Sierraを使っているので、試していません。


実行環境


  • MacBook Pro Late 2013

  • macOS Sierra 10.12.6

  • Docker Community Edition 17.12.0-ce-mac49 (21995)


手段

AWS EC2のAmazon Linux2インスタンスを使って試します。

Dockerの起動時間を抜いて計測するために

docker-compose run --service-ports web bash

を実行し、Docker上で

time bundle exec rspec spec/models/hoge_spec.rb

を実行します。

bash-4.3# time bundle exec rspec spec/models/hoge_spec.rb

No DRb server is running. Running in local process instead ...
Rack::File headers parameter replaces cache_control after Rack 1.5.
....................................................................................................................................................................................

Finished in 5.15 seconds
180 examples, 0 failures

real 0m23.581s
user 0m0.010s
sys 0m0.000s

realの値がtimeコマンドの結果です。

rspecコマンドの起動から終了までの実時間です。

これは「Rails環境の読み込み」時間を含みます。

Finished in 5.15 secondsがRSpecのテストの実行時間です。

差の18.4秒は「Rails環境の読み込み時間」です。


結果

以下の環境で試しました。


  • Docker For Mac

  • t2.micro

  • c4.large

いずれもDockerとdocker-composeでRailsアプリケーションを構成しています。

環境
real
rspec
real比率
rspec比率
Rails環境読み込み比率

Docker For Mac
0m23.581s
5.15 seconds
-
-
-

t2.micro
0m14.258s
2.9 seconds
60%
56%
62%

c4.large
0m11.456s
2.52 seconds
49%
49%
48%

EC2上では40〜50%の時間短縮が計測されました。

単純にDocker for Macを使うとLinux上でDockerを使う場合の、2倍の時間が掛かると考えて良いでしょう。


Docker For Mac

bash-4.3# time bundle exec rspec spec/models/hoge_spec.rb

No DRb server is running. Running in local process instead ...
Rack::File headers parameter replaces cache_control after Rack 1.5.
....................................................................................................................................................................................

Finished in 5.15 seconds
180 examples, 0 failures

real 0m23.581s
user 0m0.010s
sys 0m0.000s


t2.micro

bash-4.3# time bundle exec rspec spec/models/hoge_spec.rb

No DRb server is running. Running in local process instead ...
Rack::File headers parameter replaces cache_control after Rack 1.5.
....................................................................................................................................................................................

Finished in 2.9 seconds
180 examples, 0 failures

real 0m14.258s
user 0m0.000s
sys 0m0.000s


c4.large

bash-4.3# time bundle exec rspec spec/models/hoge_spec.rb

No DRb server is running. Running in local process instead ...
Rack::File headers parameter replaces cache_control after Rack 1.5.
....................................................................................................................................................................................

Finished in 2.52 seconds
180 examples, 0 failures

real 0m11.456s
user 0m0.000s
sys 0m0.000s


考察


EC2の方が2倍近く速い

Docker For MacのDisk I/Oの遅さが原因に思えます。

Docker for Macのディスクスループットを約2倍にする - Qiita の効果とも一致します。

ファイルシステムのraw format化で、解消されることが期待できます。


c4.largeがt2.microより15%速い

他のインスタンスタイプ、例えば


  • t2.small

  • m4.large

  • c3.large

を使っても、t2.microとは差がありません。

これはc4.largeが(標準で)EBS 最適化インスタンスだからです。

https://aws.amazon.com/jp/ec2/instance-types/


C5、C4、M5、M4、P3、P2、G3、および D2 の各インスタンスの場合、この機能はデフォルトで有効になっており、追加料金は発生しません。


やはり、RailsのRSpecでは、Disk I/Oがボトルネックのようです。


その他の高速化


Rails application preloader

例えば、Springを使うと「Rails環境のロード時間」をスキップできます。

今回のテストのように、Rspecの実実行時間の8割が「Rails環境のロード時間」に使われている場合は、Rails application preloaderを使うと、テストの繰り返しやすさに効果的です。


 参考


スローテストを解消する

RailsのRSpecは、Rails環境のロード時間を除いても、遅いことが多いです。

特にモデルのテストの場合は、it毎にDBにテスト用のレコードを用意するためのinsert文を発行するためです。

必要なレコードが20件ある場合は、体感でわかるぐらい遅くなりました。

テスト数が多いと線形に遅くなります。

簡単に20秒掛かるテストセットが作れます。

Mac上で20秒掛かるテストが、Linux上で10秒になっても、テスト待ちのストレスはあまり解消されません。

ローカル環境とリモート環境を切り替える手間を考えると、テストの繰り返しやすさは上がりません。

地道にスローテストを解消した方が、テストの繰り返しやすさには効果が高いです。

before :allで複数のテストでまとめてテストデータを用意したり、FactoryGirl.createの代わりにFactoryGirl.buildを使ったりして、DBのレコード追加削除を減らすのが効果的です。


参考