Some of you might know that we are a bootstrapped upstart with a shoestring budget.
This means that we are frugal about how we budget for resources and buy-into new stuff only more carefully. Which is great because then our end users get to enjoy performance of a well tuned app top down.
Through this post we explain how we used jemalloc—a memory allocator—to improve performance of our Rails application. It helped us reduce our RAM usage by 30%.
But first, what is jemalloc?
By default Ruby uses the
glibc for memory allocation. Switching over to jemalloc has been discussed often by the experts in the Ruby/Rails community but a decision is yet to come. We are hoping this thought will see the light of the day soon and jemalloc will be considered by the Ruby core group.
It is worthwhile to mention here that several large projects and organizations like Redis, GitHub, GitLab and Discourse are already using jemalloc on production.
jemalloc is a general purpose malloc(3) implementation that emphasizes fragmentation avoidance and scalable concurrency support.
While it will take some time for ruby aficionados to arrive on this decision, we decided to take full advantage of what is available immediately. Turns out, by compiling Ruby with jemalloc we were able to reduce memory usage of our Rails application quite drastically.
An improvement of ~28.62% (>1 Gb RAM) on memory usage was registered on our production server (Linode), but YMMV.
Here are our before and after stats:
How to install:
To install jemalloc on your linux server (Ubuntu 16.04.1 LTS):
ssh into your server or the dev machine.
$ sudo apt-get update $ sudo apt-get install libjemalloc-dev # Install jemalloc
On macOS, you may use homebrew to install jemalloc, like so:
$ brew install jemalloc
If ruby is already installed on your machine, as it was in our case, you might need to remove and purge older shims and rehash it again, like so:
$ RUBY_CONFIGURE_OPTS=--with-jemalloc rbenv install 2.4.1 ➜ rbenv: /home/marvin/.rbenv/versions/2.4.1 already exists continue with installation? (y/N) y Downloading ruby-2.4.1.tar.bz2... -> https://cache.ruby-lang.org/pub/ruby/2.4/ruby-2.4.1.tar.bz2 Installing ruby-2.4.1... ruby-build: use readline from homebrew Installed ruby-2.4.1 to /home/marvin/.rbenv/versions/2.4.1 rbenv: cannot rehash: /home/marvin/.rbenv/shims/.rbenv-shim exists $ rm /home/marvin/.rbenv/shims/.rbenv-shim $ rbenv rehash
To check if your installation of Ruby is now using jemalloc, try following command:
$ ruby -r rbconfig -e "puts RbConfig::CONFIG['LIBS']" -lpthread -ljemalloc -lgmp -ldl -lcrypt -lm # Output
Presence of a string like
-ljemalloc in the output indicates that the memory allocator library we wanted is correctly loaded before starting ruby. Brilliant! Now let's go ahead and restart our app, and there it is folks: a faster rails app that's also light on your wallet.
Like it? Great! Do you have more tips or tricks to suggest for vertical scaling?
Please share on comments below.
Hi! I'm Marvin Danig CEO and Cofounder of Bubblin Superbooks—the best way to read and share books on web.
Let's follow each other on Twitter?