Skip to content

Instantly share code, notes, and snippets.

@mackermedia
Created July 15, 2014 16:26
Show Gist options
  • Save mackermedia/4319b60359cd8a6bef2c to your computer and use it in GitHub Desktop.
Save mackermedia/4319b60359cd8a6bef2c to your computer and use it in GitHub Desktop.
Ruby Application Server Comparison

TL;DR of big comparison blog post: https://blog.engineyard.com/2014/ruby-app-server-arena-pt1


Passenger

  • best for situations where you want to conserve memory when an app has low traffic
  • good for hosting multiple applications on a single server
  • for always-on dedicated app, this killing of workers can have negative side-effects: new workers need to be spun up on new requests (also after nginx restart)
  • must install via compiled into nginx source (via Passenger)
  • no ability to have zero downtime deploys

Unicorn

  • best for single application on a server with fast clients that stick to normal request/response application flow cycle.
  • master process loads app in memory and forks to workers. kills long-running workers and spawns new ones (which can make things like sockets or long time duration requests problematic)
  • master process only watches workers and manages them
  • uses unix socket
  • ability to run (in Ruby) before_fork and after_fork blocks (could be used to disconnect and reconnect ActiveRecord connection)
  • ability to have zero-downtime deploys by sending master the correct signal (HUP or USR2 + QUIT)

Thin

  • similar architecture to unicorn (launches multiple workers & listens to a socket), but it has not master process
  • each worker opens its own socket and nginx configured to "round-robin" requests to workers.
  • based on EventMachine architecture (not fully async)
  • best used for single application running at all times on a host. applications that can benefit from evented architecture (long-polling application) may benefit significantly

Puma

  • truly concurrent app server unlike any of the others
  • can be configured to bind to ports, or to pull from a socket (like Thin and Unicorn), but will open a new thread for each incoming request.
  • b/c Ruby has issues with executing multiple threads concurrently (Global VM Lock GVL), Puma runs best under JRuby or Rubinius.
  • best used for single applications running on a host (like Thin and Unicorn). Since it's multi-threaded, if you run a Ruby implementation w/out an internal GVL (JRuby/Rubinius), you can theoretically run a single Puma process on your machine instead of one worker per core.
  • even w/out JRuby or Rubinius, might benefit if application isn't particularly CPU bound, but does execute multiple external requests to databases, APIs, disk I/O, etc.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment