
Bootsnap: Optimizing Ruby App Boot Time - Finbarr
https://engineering.shopify.com/235340559-bootsnap-optimizing-ruby-app-boot-time
======
JohnBooty
Wow! This is potentially a real gain for us. We have a big in-house,
monolithic Rails app.

My initial experiment was encouraging. Boot time in development mode went from
~23sec to ~16sec, and I only enabled it for the main engine that comprises
about 85% of our codebase so the real gains might be larger.

Looking forward to seeing what it can do in production mode - our boot times
there are horrendous and it's a big deal for things like cron jobs. Thank you
to all those who worked on this.

------
chrisseaton
In the implementation of Ruby that I work on, TruffleRuby, we've been
exploring lazy parsing, where the parser will find a method but not fully
parse it until the method is called for the first time. I wonder if there's
any other modifications you could make to the VM itself to improve startup
time.

~~~
burke
The particularly frustrating thing, when I've started thinking about
optimizing boot time at a VM level, is that it's near-impossible to
"understand" what loading a file actually does, since it's all just evaluated
in a single namespace.

It would be great if we somehow had a way to load a module-as-file without
unknown side-effects, and without depending so deeply on the other contents of
the global namespace.

But this is basically describing a complete overhaul of most of what makes
ruby ruby, so... ¯\\_(ツ)_/¯

~~~
chrisseaton
Yes if there were special Ruby source files that only had classes and modules
at the top level, and only defined nested classes and modules and methods in
those, then it would be a lot quicker to load things.

~~~
burke
Yep. But even then though, what if:

    
    
        class A
          B = "c".freeze
        end
    

And elsewhere:

    
    
        class String
          def freeze
            raise "because I can, that's why"
          end
    
          # or even method_added, TracePoint, ...
        end
    

It feels like something should be possible here, but it's really steep uphill
battle.

~~~
chrisseaton
Right - that's why I said nothing but methods and nested classes - expressions
in method bodies would be disallowed. And tracing and method added hooks and
so on, yes.

You could say it was a separate language .rb-module or something, to make it
formal.

~~~
dragonwriter
> Right - that's why I said nothing but methods and nested classes -
> expressions in method bodies would be disallowed.

I presume you mean "expressions that aren't method definitions in class
bodies" (though that's a problem, because of things like attribute
declarations) rather than "expressions in method bodies", since methods with
no expressions in their bodies would be pointless.

------
burke
I'm the primary author, can answer questions if you have any.

~~~
wolco
Curious when did shopify go with Ruby/rails. If I remember when the company
was initially started they were looking for php developers. Was the orginal
stack built in Ruby/rails?

~~~
burke
Nope, we've been Rails since before Rails was even public. I'm sure we've
hired a PHP developer here and there over the years, but our core platform has
always been Ruby.

~~~
ksec
>Nope, we've been Rails since before Rails was even public.

How is that possible? Or you mean Ruby before Rails?

~~~
burke
Tobi knows DHH; apparently we started building with rails before its public
release. Don't quote me on that, but I've heard it in passing a few times.

~~~
halostatue
Probably before Rails 1.0, certainly.

I don’t remember if Tobi was involved in the Ruby community in late 2004 when
DHH introduced Rails at RubyConf 2004 (in DC), and I don’t remember him being
at that conference, either.

But I do remember seeing Tobi involved in ruby-talk by early 2005.

But Shopify has always been a Rails shop.

------
dobs
Gave this a quick shot on my own monolithic app and it cut startup time almost
in half. Impressive considering how easy it was to configure!

Startup time was one reason we started migrating away from Rails in a previous
workplace, between frustrating startup time in development and test and
occasional quirkiness of zeus and spring. Bootsnap would have been a godsend.

~~~
burke
I've tossed around the idea of writing zeus again now that I actually
understand the language I wrote it in. Spring is much simpler, but because of
the manner in which it's loaded, it isn't capable of detecting certain types
of file change, which reduces developer confidence in it.

Zeus is capable of detecting any sort of invalidating file change, but is
pretty buggy (or at least was historically -- the Stripe guys improved it a
lot after I stopped working on it).

~~~
ischi
Still fairly buggy,some terminal issues should be fixed now but reloading has
race conditions still.

------
jitl
This is awesome, and I'd love to use it for the command-line dev tools that I
write. Unfortunately this gem requires Ruby 2.3+, but macOS built-in Ruby,
which is the Ruby we target, is only 2.0.0.

Does anyone know of a good solution for prebuilt, relocatable Rubies on macOS
that I could easily bundle with my tool? I'm reluctant to use Homebrew or
another package manager like rbenv, where I'd have to implement a non-trivial
bootstrap process. Phusion's travelling-ruby project would be perfect, but
it's unmaintained.

I just want my CLI to boot in 0.05s without needing to change languages. Love
Ruby, but getting decent perf takes a bit of effort.

~~~
guu
Have you considered trying mruby? That would allow you to ship standalone
binaries.

[https://github.com/hone/mruby-cli](https://github.com/hone/mruby-cli)

~~~
burke
I can't believe I hadn't though of this. Could be a really useful idea!

------
dismantlethesun
I'm kinda shocked that Ruby boot times can be up to 25 seconds for a
monolithic app.

A Python project I work on has 279,124 lines of code and boots up in 2.5
seconds.

Without downloading it, all I can find is Discourse had 60,000 lines of code 3
years ago [1]. Assuming as an extreme estimate they tripled their code size in
3 years, we have 180,000 LOC taking 6 seconds to boot up according to the
article.

Is this normal for Ruby? Is the author using a spinning disk drive rather than
an SSD?

[1]
[https://github.com/bleonard/rails_stats](https://github.com/bleonard/rails_stats)

~~~
burke
The largest culprit for slow ruby boot times is an O(n) number of syscalls
over the LOAD_PATH each time `require` is called, so the number of syscalls is
essentially O(n*2) to the number of gems. The load-path-caching feature of
bootsnap (cf. bootscale) fixes this, and accounts for a reduction from 25 to
~9.5 seconds. The iseq/yaml caching only accounts for the last ~3.5 seconds.

~~~
lathiat
Aaron Patterson did a really great talk detailing the process called "Code Is
Required". He's a really great presenter both humour wise and manages to often
explain relatively technical things very understandably. Highly recommend
watching this (and his other stuff)

you can watch it here:
[https://www.youtube.com/watch?v=_bDRR_zfmSk](https://www.youtube.com/watch?v=_bDRR_zfmSk)

------
Cerium
Thanks for releasing this, I gave it a try.

Starting benchmark time: 13.05 seconds. With load_path_cache: 10.01 seconds

Sadly, with compile_cache on I'm getting an error.
/vendor/bundle/ruby/2.3.0/gems/bootsnap-0.2.14/lib/bootsnap/compile_cache/iseq.rb:30:in
`fetch': No space left on device (Errno::ENOSPC)

Any ideas on what causes this?

~~~
burke
Yep, you're probably using linux. The cache backend for compiled artifacts is
filesystem extended attributes, which have a maximum size of 64MB on darwin,
but as little as 4kB on some linux configurations (if they're even enabled,
which they often are not).

Practically speaking, the compilation caching features are not supported on
linux. Eventually we'll change the cache backend or add a different one that
does work on linux.

~~~
Cerium
Yes. I am using Linux. Thanks for the quick response.

------
ausjke
Considering PHP7, Java8/Kotlin, Go, C++17, Python3, Javascript/ES6 etc these
days, how will Rudy be doing in the long run? any reason for new comers to
pick up Ruby instead of the mentioned list? I just started using PHP myself.

~~~
deedubaya
Avoiding a flame war, it depends on what your goals are.

From a language standpoint: Ruby emphasizes developer happiness at the expense
of some things, like performance/concurrency for example.

From a career standpoint: There is a lot of ruby in the world today. There
will be lots of applications to maintain as the years go on, which is +1 from
a career perspective. Lots of people will also continue to write new ruby
software, because it's effective and easy to be productive in.

All the languages you mentioned + ruby are all good languages to learn for
various reasons. All have their weaknesses and strengths. None of them are an
effective hammer for every nail you'll encounter.

~~~
camus2
> There is a lot of ruby in the world today

If you live in the west coast, certainly. Anywhere else in the world
absolutely not.

> Ruby emphasizes developer happiness at the expense of some things,

That's a strange statement. Plenty of developers enjoy writing PHP, or C++ or
even Java. Ruby doesn't make developers more happy, by no serious metrics.

Ruby had its shot but wasted it because of the petulance, the arrogance, the
immaturity and the toxicity of its community.

> None of them are an effective hammer for every nail you'll encounter.

Ruby (in fact Rails since that's really what it is all about) is clearly
redundant in the era of light weight servers and thick clients.

~~~
paulddraper
You are being unduly pessimistic (or maybe petulant/arrogant/toxic).

Ruby is the language for the second most popular HTTP MVC framework (Rails)
and the first most common popular tool (Chef).

My biggest grip with Ruby are mostly that the community seems more amateurish
than average. SO Ruby questions are like Javascript questions in 2008. with a
lot of misinformation and the assumption that you were using jQuery (or Rails
for Ruby). I'm sure there are a lot of Ruby experts that know how to program
well. They just don't seem as common as say, in the Python community.

------
omarforgotpwd
Might have missed something, but why not just merge these changes into Rails?

~~~
yxhuvud
For starters, because it only works on mac.

------
misterbowfinger
Are there plans to support JRuby?

~~~
burke
No. I'm not opposed to it, but we don't use it at Shopify and I doubt the
RubyVM::InstructionSequence API is compatible.

Bootscale should work, and the load-path-caching feature of bootsnap should
work too, if you can get the gem to install.

------
iagooar
-

~~~
noir_lord
> In 2017 there is really no reason to defend a monolithic architecture.

I wonder if in 2019 I'll be seeing "In 2019 there is really no reason to
define a micro-services architecture".

The pendulum it keeps on swinging.

~~~
rhizome
thin/thick clients all over again.

~~~
noir_lord
Yep and others, I've been around programming long enough to have seen that
come and go several times now.

