about summary refs log tree commit homepage
path: root/DESIGN
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2009-03-09 15:29:59 -0700
committerEric Wong <normalperson@yhbt.net>2009-03-09 16:12:22 -0700
commit32a5a5e91bd78795f546e2a8b8b775f1e1989ed9 (patch)
treee7e2efc0bad50405cf330a6b1c8d524113fa3a2f /DESIGN
parentbfc3aae9b85b520c87539fdf203587c3a1c9453f (diff)
downloadunicorn-32a5a5e91bd78795f546e2a8b8b775f1e1989ed9.tar.gz
Reformat README to avoid preformatted text.
Document signal handling in SIGNALS.
Split out DESIGN, it's probably not as useful to end-users
Update CONTRIBUTORS
LICENSE: copyright is for me (Eric Wong), not Zed since this
is a Mongrel fork.
Diffstat (limited to 'DESIGN')
-rw-r--r--DESIGN80
1 files changed, 80 insertions, 0 deletions
diff --git a/DESIGN b/DESIGN
new file mode 100644
index 0000000..cc359ca
--- /dev/null
+++ b/DESIGN
@@ -0,0 +1,80 @@
+== Design
+
+* Simplicity: Unicorn is a traditional UNIX prefork web server.
+  No threads are used at all, this makes applications easier to debug
+  and fix.  When your application goes awry, a BOFH can just
+  "kill -9" the runaway worker process without worrying about tearing
+  all clients down, just one.  Only UNIX-like systems supporting
+  fork() and file descriptor inheritance are supported.
+
+* The Ragel->C HTTP parser is taken from Mongrel.  This is the
+  only non-Ruby part and there are no plans to add any more
+  non-Ruby components.
+
+* All HTTP protocol parsing and I/O is done just like Mongrel:
+    1. read/parse HTTP request in full
+    2. call Rack application
+    3. write HTTP response back to the client
+
+* Like Mongrel, neither keepalive nor pipelining are supported.
+  These aren't needed since Unicorn is only designed to serve
+  fast, low-latency clients directly.  Do one thing, do it well;
+  let nginx handle slow clients.
+
+* Configuration is purely in Ruby and eval().  Ruby is less
+  ambiguous than YAML and lets lambdas for
+  before_fork/after_fork/before_exec hooks be defined inline.  An
+  optional, separate config_file may be used to modify supported
+  configuration changes (and also gives you plenty of rope if you RTFS
+  :>)
+
+* One master process spawns and reaps worker processes.  The
+  Rack application itself is called only within the worker process (but
+  can be loaded within the master).  A copy-on-write friendly garbage
+  collector like Ruby Enterprise Edition can be used to minimize memory
+  usage along with the "preload_app true" directive.
+
+* The number of worker processes should be scaled to the number of
+  CPUs, memory or even spindles you have.  If you have an existing
+  Mongrel cluster, using the same amount of processes should work.
+  Let a full-HTTP-request-buffering reverse proxy like nginx manage
+  concurrency to thousands of slow clients for you.  Unicorn scaling
+  should only be concerned about limits of your backend system(s).
+
+* Load balancing between worker processes is done by the OS kernel.
+  All workers share a common set of listener sockets and does
+  non-blocking accept() on them.  The kernel will decide which worker
+  process to give a socket to and workers will sleep if there is
+  nothing to accept().
+
+* Since non-blocking accept() is used, there can be a thundering
+  herd when an occasional client connects when application
+  *is not busy*.  The thundering herd problem should not affect
+  applications that are running all the time since worker processes
+  will only select()/accept() outside of the application dispatch.
+
+* Blocking I/O is used for clients.  This allows a simpler code path
+  to be followed within the Ruby interpreter and fewer syscalls.
+  Applications that use threads should continue to work if Unicorn
+  is serving LAN or localhost clients.
+
+* Timeout implementation is done via fchmod(2) in each worker
+  on a shared file descriptor to update st_ctime on the inode.
+  Master process wakeups for checking on timeouts is throttled
+  one a second to minimize the performance impact and simplify
+  the code path within the worker.  Neither futimes(2) nor
+  pwrite(2)/pread(2) are supported by base MRI, nor are they as
+  portable on UNIX systems as fchmod(2).
+
+* SIGKILL is used to terminate the timed-out workers as reliably
+  as possible on a UNIX system.
+
+* The poor performance of select() on large FD sets is avoided
+  as few file descriptors are used in each worker.
+  There should be no gain from moving to highly scalable but
+  unportable event notification solutions for watching few
+  file descriptors.
+
+* If the master process dies unexpectedly for any reason,
+  workers will notice within :timeout/2 seconds and follow
+  the master to its death.