berkshelf / vagrant-berkshelf

A Vagrant plugin to add Berkshelf integration to the Chef provisioners
Other
378 stars 100 forks source link

vagrant-berkshelf makes Vagrant sluggish #101

Closed dergachev closed 10 years ago

dergachev commented 11 years ago

After installing vagrant-berkshelf, running vagrant executable has a 2+ second lag:

for N in {1..3} ; do time vagrant ; done
#    real   0m2.830s
#    real   0m2.524s
#    real   0m2.531s

vagrant plugin list
#    vagrant-berkshelf (1.3.3)
#    vagrant-cachier (0.1.0)
#    vagrant-digitalocean (0.1.2)
#    vagrant-omnibus (1.0.2)
#    vagrant-vbox-snapshot (0.0.4)
#    vagrant-vboxmanage (0.0.2)

vagrant plugin uninstall vagrant-berkshelf

for N in {1..3} ; do time vagrant ; done
#    real   0m0.731s
#    real   0m0.744s
#    real   0m0.721s

vagrant plugin install librarian-chef

for N in {1..3} ; do time vagrant ; done
#    real   0m0.909s
#    real   0m0.938s
#    real   0m0.942s

Clearly the problem is vagrant-berkshelf, the fact that it requires a huge amount of dependent gems unconditionally.

Here's one way to look at the bloat:

mkdir -p ~/code/berkshelf-debug
cd ~/code/berkshelf-debug
git clone https://github.com/RiotGames/vagrant-berkshelf.git
cd vagrant-berkshelf

# install all dependent gems to a local folder; takes a minute or 2
bundle install --path=./vendor

ls vendor/ruby/2.0.0/gems | wc -l
#    75 gems

There are 75 (!!) gems that are downloaded as dependencies.

Here's a Vagrantfile that will help measure why it's slow:

if ENV['PROFILE_REQUIRE']
  require 'benchmark'
  module Kernel
      # make an alias of the original require
    alias_method :original_require, :require

    # rewrite require
    def require name
      time = (Benchmark.realtime { original_require name } * 1000).round
      if time > 50
        $stderr.puts "#{time} MS elapsed requiring #{name}"
      end
    end
  end
end

# not using Vagrant.require_plugin because it suppresses STDOUT
require "vagrant-berkshelf"

Vagrant.configure("2") do |config|
  config.vm.box = "precise64"
end

Let's install it and see what the culprits are. Additionally, we run a few diagnostic benchmarks to get a sense for the overhead of using bundler, etc:

cd ~/code/berkshelf-debug/vagrant-berkshelf

time ruby -e 'require "json"'
#    real   0m0.112s

time bundle exec ruby -e 'require "json"'
#    real   0m1.064s

time bundle exec ruby -e 'require "vagrant-berkshelf"'
#    real 0m1.967s

time vagrant
#    real 0m0.848s

time bundle exec vagrant
#    real   0m1.179s

# now lets add a Vagrantfile that requires vagrant-berkshelf
# and supports PROFILE_REQUIRE env variable
wget https://gist.github.com/dergachev/6770076/raw/Vagrantfile

time bundle exec vagrant
#    real   0m2.121s

time PROFILE_REQUIRE=1 bundle exec vagrant
#    real   0m2.198s

The output from the invocation with PROFILE_REQUIRE=1 was:

72 MS elapsed requiring celluloid
53 MS elapsed requiring psych
55 MS elapsed requiring yaml
78 MS elapsed requiring net/ssh
57 MS elapsed requiring httpclient/auth
79 MS elapsed requiring httpclient
58 MS elapsed requiring nokogiri/xml
103 MS elapsed requiring nokogiri
106 MS elapsed requiring wasabi/document
107 MS elapsed requiring wasabi
108 MS elapsed requiring savon/wasabi/document
77 MS elapsed requiring nori/xml_utility_node
83 MS elapsed requiring nori
85 MS elapsed requiring savon/soap/xml
234 MS elapsed requiring savon/client
237 MS elapsed requiring savon
353 MS elapsed requiring winrm/soap_provider
422 MS elapsed requiring winrm
776 MS elapsed requiring ridley
991 MS elapsed requiring berkshelf
1000 MS elapsed requiring berkshelf/vagrant
1001 MS elapsed requiring vagrant-berkshelf

From the above, it's obvious that winrm is a major part of the problem. In general though, we could shave 900ms if vagrant-berkshelf would only require berkshelf if it needs it. (However, my familiarity with berkshelf is insufficient to take a stab at this).

Related issues:

labavalencia commented 11 years ago

I have this same problem. And its getting really disruptive.

My config is as follows: ruby 2.0.0p247 (2013-06-27 revision 41674) [x86_64-darwin12.4.0] gem -v -> 2.0.3 76 gems installed Vagrant 1.3.1 Berkshelf (2.0.10) vagrant-berkshelf (1.3.3) (the only vagrant plugin i am using) Test Kitchen version 1.0.0.beta.3

The test explained above (for N in {1..3} ; do time vagrant ; done) with and without the vagrant-berkshelf plugin goes from 0.33s to 1.85s. Six times slower!

I am using vagrant with berkshelf and test-kitchen (using serverspec) to migrate a group of physical servers to AWS. Step by step I have been creating the recipes necessary to provision all the servers' packages, middleware and proprietary software. This includes passing big tar.gz files to recreate some websites and to replicate databases.

Initially all went well and the TDD iterations were bearably fast. But as the recipes grew it became too slow.

An added problem is it is spending time doing things that are not needed. After a test has failed, I make a change and re-converge the VM previous to re-verify it: first berkshelf spends quite some time just resolving cookbook dependencies that have not changed and then it spends and awful lot of time copying cookbook resources that are already in the VM from the previous run. Only then chef begins working on the recipes. At this point resource idempotence works quite well.

The only way I have found to accelerate things a bit is commenting on the berksfile all the cookbooks that are already tested and the same thing in the .kitchen and vagrant files. But this is a pain in itself.

Now I was thinking about creating my own vagrant box with all the tested provisions on it after every successful iteration so I do not have to provision all every time. Far from an ideal workflow too.

Any help out there?

dergachev commented 11 years ago

@mydocumenta let's not confound what this issue is about (vagrant-berkshelf needlessly requiring ALL its gems dependency every time I run something as simple as vagrant status) and the fact that vagrant-berkshelf might be unnecessarily re-downloading unchanged cookbooks (I know it used to happen, but I'm not sure if that's the case anymore... hunt around the issue queue).

For your case, As a temporary workaround, consider using https://github.com/jimmycuadra/vagrant-librarian-chef or simply manually committing all your downloaded cookbooks to your git repo.

Also there are a few plugins that can really speed up iterating on this stuff:

tmatilai commented 11 years ago

... [berkshelf] spends and awful lot of time copying cookbook resources that are already in the VM from the previous run

This is done by test-kitchen, which unfortunately is using scp and not rsync. Berkshelf just copies them to a local directory which should be a fast operation (compared to all the other issues you listed).

Lazy loading the dependencies only when needed should indeed help some. But that should be done in both here and in Berkshelf itself.

jmasramon commented 11 years ago

Ok, thanks to both. I have been trying librarian-chef with the vagrant plugin and it is much faster (although it has its own problems).

mlafeldt commented 11 years ago

You're right—vagrant-berkshelf makes Vagrant painfully slow. :/

However, I'd never go back to Librarian-Chef, which is IMO way less sophisticated. Instead, you could always use Berkshelf directly by running berks install --path cookbooks before vagrant up/provision. If you don't like having to run two commands instead of one, a simple Rake task might help.

dergachev commented 10 years ago

@reset any thoughts on this?

For anyone else annoyed by this, I created a gem that works around this problem: https://github.com/dergachev/vgrnt

Note:

reset commented 10 years ago

@dergachev yes, I have a few ideas to alleviate this problem.

  1. We're going to be improving the load times of Berkshelf itself which will inherently speed up vagrant-berkshelf.
  2. Uninstall the vagrant-berkshelf plugin and instead follow these instructions to use a specific branch (in this case head) of Berkshelf and vagrant-berkshelf. These steps will allow you to pick and choose which projects you want to require the vagrant-berkshelf plugin for.
dergachev commented 10 years ago

@reseet thanks!

I am happy to see there's also progress on this here: https://github.com/berkshelf/berkshelf/issues/899

sethvargo commented 10 years ago

Ridley's host connector stuff has been moved out of Ridley core and Berkshelf is much faster. Additionally, Mitchell has done some awesome work in Vagrant to speed up plugins.