Awesome Series @ Planet Ruby
Rubies (Virtual Machines, Compilers, ...) • ActiveRecord • Webframeworks (Micro, Macro, APIs, ...) • Webservers (Single-Threaded, Multi-Threaded, Evented, ...) • Static Generators (Sites, Books, Presentations, ...) • Events (Conferences, Camps, Meetups, ...) • Blogs (News, Opinions, Podcasts, ...)
A collection of awesome Ruby web servers (single-threaded, multi-threaded, multiplexed, etc.)
[ANNOUNCEMENT] Looking for awesome Ruby Gems? See the Ruby Gems of the Week Series @ Planet Ruby.
WEBrick • Passenger Family • Puma • Unicorn 'n' Friends • Thin • Goliath • Reel • HTTP-2
multi-threaded
An HTTP server toolkit; ships with the standard library (stdlib); lets you use HTTP(S) servers, proxy servers, and virtual-host servers; by Masayoshi Takahashi, Yuuzou Gotou et al
(github: ruby/ruby/lib/webrick.rb+webrick/**)
require 'webrick'
server = WEBrick::HTTPServer.new :Port => 1234
server.mount '/', WEBrick::HTTPServlet::FileHandler, './'
trap('INT') { server.stop }
server.start
Ruby - Yes | Rubinius - Yes | Java - Yes
c++ - multi-threaded, evented, multi-process, watchdog
A web server - also known as "Raptor", mod_rails or mod_rack - with a zero-copy architecture, watchdog system and hybrid evented, multi-threaded and multi-process design; by Hongli Lai (Phusion B.V.) et al
Note: The "standard" runs single-threaded; for "advanced" higher throughput, see the commercial enterprise edition.
(web: phusionpassenger.com, github: phusion/passenger, gem: passenger depends on rack)
Ruby - Yes (Recommended) | Rubinius - ?? | Java - No
c, ragel - multi-threaded, multi-process
A simple, fast, threaded, and highly concurrent HTTP 1.1 server for rack apps;
(re)uses the Mongrel HTTP parser (in C/Ragel);
allows firing up multiple workers using the -w
option;
by Evan Phoenix et al
(web: puma.io, github: puma/puma, gem: puma depends on rack)
Ruby - Yes (*) | Rubyinius - Yes (Recommended) | Java - Yes (Recommended)
Note: (*) Global Interpreter Lock (GIL) in (C)Ruby "blocks" higher multi-threaded throughput
c - multi-process
An HTTP server for rack apps and Unix; workers all run within their own isolated address space and only serve one client at a time for maximum robustness; by Eric Wong et al
Note: Use Unicorn with a fully-buffering reverse proxy such as nginx for slow clients. Unicorn will never ever use new-fangled things like non-blocking async socket I/O, threads, epoll or kqueue for supporting slow clients (long-running requests).
(web: unicorn.bogomips.org, git: unicorn, github mirror: defunkt/unicorn, gem: unicorn depends on rack, kgio)
Ruby - Yes (Recommended) | Rubinius - ?? | Java - No | Windows - No
multi-process, multi-threaded, evented, eventmachine, fibers
A web server for sleepy apps and slow clients; based on unicorn, but designed to handle long request/response times and/or slow clients; Rainbows! is about diversity - network concurrency models supported include: Epoll, EventMachine, FiberPool, FiberSpawn, NeverBlock, Revactor, ThreadPool, ThreadSpawn, WriterThreadPool, WriterThreadSpawn, XEpoll, XEpollThreadPool, XEpollThreadSpawn and more; by Eric Wong et al
(web: rainbows.bogomips.org, git: rainbows, gem: rainbows)
multi-threaded
A multi-threaded, (optionally) multi-process, internally async (no public async API, yet, just synchronous Rack 1.x), supports Rack streaming and more; by Eric Wong et al
(web: yahns.yhbt.net, git clone: yhbt.net/yahns, gem: yahns)
c, ragel - evented, eventmachine
A simple and fast web server powered by EventMachine; (re)uses the Mongrel HTTP parser (in C/Ragel); by Marc-André Cournoyer et al
(web: code.macournoyer.com/thin, github: macournoyer/thin, gem: thin depends on rack, eventmachine)
Ruby - Yes (Recommended) | Rubinius - ?? | Java - ??
evented, eventmachine, fibers
A non-blocking (async) web server framework; powered by event machine; uses fibers to untangle the complicated callback-based code into "plain old" linear-execution
(web: goliath.io, github: postrank-labs/goliath, gem: goliath depends on rack, eventmachine)
Ruby - Yes (Recommended) | Rubinius - ?? | Java - ??
c - evented, celluloid, fibers
A fast, non-blocking "evented" web server built on Celluloid::IO; supports Rack via the reel-rack addon; technically "multi-fiber" via Celluloid; by Tony Arcieri et al
(github: celluloid/reel, gem: reel depends on celluloid)
Ruby - Yes (Recommended) | Rubinius - ?? | Java - Yes (*)
Note: (*) Compatible extension for Java
HTTP/2 protocol and HPACK header compression machinery in all Ruby (no C extensions);
includes an HTTP2::Server
for testing;
by Ilya Grigorik et al
(github: igrigorik/http-2, gem: http-2)
c - evented
A fast, single-threaded engine for arbitrary network communications; wraps all interactions with IP sockets, allowing programs to focus on coding the network protocols; works for both network servers and clients; by Francis Cianfrocca, Aman Gupta et al
(web: rubyeventmachine.com, github: eventmachine/eventmachine, gem: eventmachine)
Ruby - Yes (Recommended) | Rubinius - ?? | Java - ??
c - evented, fibers
Evented I/O for celluloid actors; build fast evented programs like you would with EventMachine or Node.js using regular synchronous libraries based on TCPSocket; by Tony Arcieri et al
(github: celluloid/celluloid-io, gem: celluloid-io)
Ruby - Yes (Recommended) | Rubinius - ?? | Java - ??
Server | Rack | HTTP/1.1 | HTTP/1.1 Pipelining | HTTP/2 |
---|---|---|---|---|
WEBRick | Yes | Yes | x | x |
Passenger | Yes | Yes | x | ?? |
Puma | Yes | Yes | x | x |
Unicorn | Yes | Yes | x | x |
Thin | Yes | Yes | x | x |
Goliath | Yes | Yes | Yes | x |
Reel | Yes(*) | Yes | Yes | x |
HTTP-2 | ?? | x | ?? | Yes |
(Note: Reel supports Rack via reel-rack addon)
Notes on HTTP Pipelining:
- WEBRick -- couldn't find any information; a quick look over the code on WEBRick didn't turn up anything.
- Passenger -- couldn't find any information or Passenger.
- Puma -- found this closed issue, which leads me to believe it doesn't.
- Unicorn -- explicitly documents that it does NOT support pipelining.
- Thin -- there's an open issue where several people repeatedly claim pipelining is broken.
- Goliath -- pipelining is an explicit design goal of Goliath
- Reel -- has pipelining support; confirmed by the author (Tony Arcieri).
Note: HTTP/2 supports a more advanced model; HTTP/2 is message-oriented and therefore even more advanced than traditional HTTP/1.1 pipelining.
Server | Multi-Threaded | Multi-Fiber | Multi-Process | Evented | Watchdog | C Extension |
---|---|---|---|---|---|---|
WEBRick | Yes | x | x | x | x | x |
Passenger | Yes | x | Yes | Yes | Yes | Yes |
Puma | Yes | x | Yes | x | x | Yes |
Unicorn | x | x | Yes | Yes | Yes | Yes |
Thin | Yes | x | x | Yes | x | Yes |
Goliath | x | Yes | x | Yes | x | Yes |
Reel | Yes (*) | Yes (*) | x | Yes | Yes (*) | Yes (*) |
HTTP-2 | ?? | x | x | Yes | x | x |
(Note: Thin, Goliath, ... using EventMachine)
Notes on Reel:
- Reel using Celluloid:IO for evented, non-blocking async I/O
- Reel single-threaded by default but supports multithreading with Celluloid
- Reel technically "multi-fiber" via Celluioid
- Reel supports watchdogs via Celluloid supervisors
- Reel uses a C extension on CRuby but has a compatible Java extension for JRuby
Todo: What features to add?
- Multi-App
- Streaming ?
- Websocket ?
- Server-sent events (SSE) ?
HTTP - just a few lines of plain text describing each request and response sent over a TCP socket
Example: HTTP Request /index.html
(type in your browser http://localhost/index.html
)
GET /index.html HTTP/1.1
Host: localhost
Example: HTTP Response /index.html
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 39
<html>
<h1>Hello, World!</h1>
</html>
Example: httpd.rb
require 'socket'
server = TCPServer.new 80
loop do
# step 1) accept incoming connection
socket = server.accept
# step 2) print the request headers (separated by a blank line e.g. \r\n)
puts line = socket.readline until line == "\r\n"
# step 3) send response
html = "<html>\r\n"+
"<h1>Hello, World!</h1>\r\n"+
"</html>"
socket.write "HTTP/1.1 200 OK\r\n" +
"Content-Type: text/html; charset=utf-8\r\n" +
"Content-Length: #{html.bytesize}\r\n"
socket.write "\r\n" # write a blank line to separate headers from the html doc
socket.write html # write out the html doc
# step 4) close the socket, terminating the connection
socket.close
end
Starting a super simple HTTP server - uses the builtin WEBrick machinery - with an one-liner. Example:
$ ruby -run -e httpd . # . is the DocumentRoot e.g. current working folder
=> [2016-08-02 19:14:35] INFO WEBrick::HTTPServer#start: pid=4396 port=80
or with a different port and document root e.g.:
$ ruby -run -e httpd ./_site -p 5000
=> [2016-08-02 19:14:35] INFO WEBrick::HTTPServer#start: pid=4397 port=5000
or to get all options:
$ ruby -e "require 'un'; httpd" -- --help
resulting in:
Run WEBrick HTTP server.
ruby -run -e httpd -- [OPTION] DocumentRoot
--bind-address=ADDR address to bind
--port=NUM listening port number
--max-clients=MAX max number of simultaneous clients
--temp-dir=DIR temporary directory
--do-not-reverse-lookup disable reverse lookup
--request-timeout=SECOND request timeout in seconds
--http-version=VERSION HTTP version
-v verbose
Source in ruby/ruby/lib/un.rb (search for the httpd
method) e.g.:
def httpd
setup("", "BindAddress=ADDR", "Port=PORT", "MaxClients=NUM", "TempDir=DIR",
"DoNotReverseLookup", "RequestTimeout=SECOND", "HTTPVersion=VERSION") do
|argv, options|
require 'webrick'
opt = options[:RequestTimeout] and options[:RequestTimeout] = opt.to_i
[:Port, :MaxClients].each do |name|
opt = options[name] and (options[name] = Integer(opt)) rescue nil
end
options[:Port] ||= 8080 # HTTP Alternate
options[:DocumentRoot] = argv.shift || '.'
s = WEBrick::HTTPServer.new(options)
shut = proc {s.shutdown}
siglist = %w"TERM QUIT"
siglist.concat(%w"HUP INT") if STDIN.tty?
siglist &= Signal.list.keys
siglist.each do |sig|
Signal.trap(sig, shut)
end
s.start
end
end
$ passenger -h
resulting in:
Phusion Passenger Standalone, the easiest way to run web apps.
Available commands:
passenger start Start Phusion Passenger Standalone.
passenger stop Stop a Phusion Passenger instance.
passenger status Show the status of a running Phusion Passenger instance.
$ passenger start --help
resulting in:
Usage: passenger start [DIRECTORY] [OPTIONS]
Starts Phusion Passenger Standalone and serve one or more web applications.
Server options:
-a, --address HOST Bind to the given address. Default: 0.0.0.0
-p, --port NUMBER Use the given port number. Default: 3000
-S, --socket FILE Bind to Unix domain socket instead of TCP socket
--ssl Enable SSL support (Nginx engine only)
--ssl-certificate PATH Specify the SSL certificate path (Nginx engine only)
--ssl-certificate-key PATH Specify the SSL key path
--ssl-port PORT Listen for SSL on this port, while listening for HTTP on the normal port (Nginx engine only)
-d, --daemonize Daemonize into the background
--user USERNAME User to run as. Ignored unless running as root
--log-file FILENAME Where to write log messages. Default: console, or /dev/null when daemonized
--pid-file FILENAME Where to store the PID file
--instance-registry-dir PATH Use the given instance registry directory
--data-buffer-dir PATH Use the given data buffer directory
Application loading options:
-e, --environment ENV Framework environment. Default: development
--ruby FILENAME Executable to use for Ruby apps. Default: /home/gerald/.rvm/gems/ruby-2.1.4/wrappers/ruby (current context)
-R, --rackup FILE Consider application a Ruby app, and use the given rackup file
--app-type NAME Force app to be detected as the given type
--startup-file FILENAME Force given startup file to be used
--spawn-method NAME The spawn method to use. Default: smart
--static-files-dir PATH Specify the static files dir (Nginx engine only)
--restart-dir PATH Specify the restart dir
--friendly-error-pages Turn on friendly error pages
--no-friendly-error-pages Turn off friendly error pages
--load-shell-envvars Load shell startup files before loading application
--debugger Enable debugger support
Process management options:
--max-pool-size NUMBER Maximum number of application processes. Default: 6
--min-instances NUMBER Minimum number of processes per application. Default: 1
--pool-idle-time SECONDS Maximum time that processes may be idle. Default: 300
--max-preloader-idle-time SECONDS Maximum time that preloader processes may be idle. A value of 0 means that preloader processes never timeout. Default: 300
--concurrency-model NAME The concurrency model to use, either 'process' or 'thread' (Enterprise only). Default: process
--thread-count NAME The number of threads to use when using the 'thread' concurrency model (Enterprise only). Default: 1
--rolling-restarts Enable rolling restarts (Enterprise only)
--resist-deployment-errors Enable deployment error resistance (Enterprise only)
Request handling options:
--max-request-time SECONDS Abort requests that take too much time (Enterprise only)
--sticky-sessions Enable sticky sessions
--sticky-sessions-cookie-name NAME Cookie name to use for sticky sessions. Default: _passenger_route
--vary-turbocache-by-cookie NAME Vary the turbocache by the cookie of the given name
--disable-turbocaching Disable turbocaching
...
$ puma -h
resulting in:
puma <options> <rackup file>
-b, --bind URI URI to bind to (tcp://, unix://, ssl://)
-C, --config PATH Load PATH as a config file
--control URL The bind url to use for the control server
Use 'auto' to use temp unix server
--control-token TOKEN The token to use as authentication for the control server
-d, --daemon Daemonize the server into the background
--debug Log lowlevel debugging information
--dir DIR Change to DIR before starting
-e, --environment ENVIRONMENT The environment to run the Rack app on (default development)
-I, --include PATH Specify $LOAD_PATH directories
-p, --port PORT Define the TCP port to bind to
Use -b for more advanced options
--pidfile PATH Use PATH as a pidfile
--preload Preload the app. Cluster mode only
--prune-bundler Prune out the bundler env if possible
-q, --quiet Quiet down the output
-R, --restart-cmd CMD The puma command to run during a hot restart
Default: inferred
-S, --state PATH Where to store the state details
-t, --threads INT min:max threads to use (default 0:16)
--tcp-mode Run the app in raw TCP mode instead of HTTP mode
-V, --version Print the version information
-w, --workers COUNT Activate cluster mode: How many worker processes to create
--tag NAME Additional text to display in process listing
-h, --help Show help
$ unicorn -h
resulting in:
Usage: unicorn [ruby options] [unicorn options] [rackup config file]
Ruby options:
-e, --eval LINE evaluate a LINE of code
-d, --debug set debugging flags (set $DEBUG to true)
-w, --warn turn warnings on for your script
-I, --include PATH specify $LOAD_PATH (may be used more than once)
-r, --require LIBRARY require the library, before executing your script
unicorn options:
-o, --host HOST listen on HOST (default: 0.0.0.0)
-p, --port PORT use PORT (default: 8080)
-E, --env RACK_ENV use RACK_ENV for defaults (default: development)
-N do not load middleware implied by RACK_ENV
--no-default-middleware
-D, --daemonize run daemonized in the background
-s, --server SERVER this flag only exists for compatibility
-l {HOST:PORT|PATH}, listen on HOST:PORT or PATH
--listen this may be specified multiple times
(default: 0.0.0.0:8080)
-c, --config-file FILE Unicorn-specific config file
Common options:
-h, --help Show this message
-v, --version Show version
$ thin -h
resulting in:
Usage: thin [options] start|stop|restart|config|install
Server options:
-a, --address HOST bind to HOST address (default: 0.0.0.0)
-p, --port PORT use PORT (default: 3000)
-S, --socket FILE bind to unix domain socket
-y, --swiftiply [KEY] Run using swiftiply
-A, --adapter NAME Rack adapter to use (default: autodetect)
(rack, rails, ramaze, merb, file)
-R, --rackup FILE Load a Rack config file instead of Rack adapter
-c, --chdir DIR Change to dir before starting
--stats PATH Mount the Stats adapter under PATH
SSL options:
--ssl Enables SSL
--ssl-key-file PATH Path to private key
--ssl-cert-file PATH Path to certificate
--ssl-disable-verify Disables (optional) client cert requests
Adapter options:
-e, --environment ENV Framework environment (default: development)
--prefix PATH Mount the app under PATH (start with /)
Daemon options:
-d, --daemonize Run daemonized in the background
-l, --log FILE File to redirect output (default: /home/gerald/test/log/thin.log)
-P, --pid FILE File to store PID (default: tmp/pids/thin.pid)
-u, --user NAME User to run daemon as (use with -g)
-g, --group NAME Group to run daemon as (use with -u)
--tag NAME Additional text to display in process listing
Cluster options:
-s, --servers NUM Number of servers to start
-o, --only NUM Send command to only one server of the cluster
-C, --config FILE Load options from config file
--all [DIR] Send command to each config files in DIR
-O, --onebyone Restart the cluster one by one (only works with restart command)
-w, --wait NUM Maximum wait time for server to be started in seconds (use with -O)
Tuning options:
-b, --backend CLASS Backend to use, full classname
-t, --timeout SEC Request or command timeout in sec (default: 30)
-f, --force Force the execution of the command
--max-conns NUM Maximum number of open file descriptors (default: 1024)
Might require sudo to set higher than 1024
--max-persistent-conns NUM Maximum number of persistent connections
(default: 100)
--threaded Call the Rack application in threads [experimental]
--threadpool-size NUM Sets the size of the EventMachine threadpool.
(default: 20)
--no-epoll Disable the use of epoll
Common options:
-r, --require FILE require the library
-q, --quiet Silence all logging
-D, --debug Enable debug logging
-V, --trace Set tracing on (log raw request/response)
-h, --help Show this message
-v, --version Show version
Abbrev | |
---|---|
C | C Programming Language |
C++ | C++ Programming Language |
HTTP | Hypertext Transfer Protocol |
HTTPD | HTTP Daemon |
HTTPS | HTTP Secure or HTTP over SSL |
IO or I/O | Input/Output |
IP | Internet Protocol |
PID | Process Identifier |
SSL | Secure Sockets Layer |
TCP | Transmission Control Protocol |
URI | Uniform Resource Identifier |
URL | Uniform Resource Locator |
More
Abbrev | |
---|---|
BV or B.V. | Besloten Venootschap [nl] |
Tony Arcieri • Michael Dippery • Uwe Kubosch • Hongli Lai • Eric Wong
License
The awesome list is dedicated to the public domain. Use it as you please with no restrictions whatsoever.
Questions? Comments?
Send them along to the ruby-talk mailing list. Thanks!