TL;DR of big comparison blog post: https://blog.engineyard.com/2014/ruby-app-server-arena-pt1
- 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
- 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
andafter_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)
- 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
- 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.