From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Eric Wong Newsgroups: gmane.comp.lang.ruby.mongrel.devel Subject: [ANN] Unicorn: UNIX+localhost/LAN-only Mongrel fork Date: Wed, 11 Feb 2009 15:04:58 -0800 Message-ID: <20090211230457.GB22926@dcvr.yhbt.net> Reply-To: mongrel-development-GrnCvJ7WPxnNLxjTenLetw@public.gmane.org NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit X-Trace: ger.gmane.org 1234397661 25735 80.91.229.12 (12 Feb 2009 00:14:21 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Thu, 12 Feb 2009 00:14:21 +0000 (UTC) To: mongrel-development-GrnCvJ7WPxnNLxjTenLetw@public.gmane.org Original-X-From: mongrel-development-bounces-GrnCvJ7WPxnNLxjTenLetw@public.gmane.org Thu Feb 12 01:15:36 2009 Return-path: Envelope-to: gclrmd-mongrel-development@m.gmane.org X-Greylist: delayed 578 seconds by postgrey-1.31 at rubycentral.org; Wed, 11 Feb 2009 18:14:40 EST Content-Disposition: inline User-Agent: Mutt/1.5.18 (2008-05-17) X-BeenThere: mongrel-development-GrnCvJ7WPxnNLxjTenLetw@public.gmane.org X-Mailman-Version: 2.1.11 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: mongrel-development-bounces-GrnCvJ7WPxnNLxjTenLetw@public.gmane.org Errors-To: mongrel-development-bounces-GrnCvJ7WPxnNLxjTenLetw@public.gmane.org Xref: news.gmane.org gmane.comp.lang.ruby.mongrel.devel:83 Archived-At: Received: from rubyforge.org ([205.234.109.19]) by lo.gmane.org with esmtp (Exim 4.50) id 1LXPEt-0007J9-KS for gclrmd-mongrel-development@m.gmane.org; Thu, 12 Feb 2009 01:15:36 +0100 Received: from rubyforge.org (rubyforge.org [127.0.0.1]) by rubyforge.org (Postfix) with ESMTP id 607E615B802C; Wed, 11 Feb 2009 19:14:12 -0500 (EST) Received: from dcvr.yhbt.net (dcvr.yhbt.net [64.71.152.64]) by rubyforge.org (Postfix) with ESMTP id A4F9015B8026 for ; Wed, 11 Feb 2009 18:14:40 -0500 (EST) Received: from localhost (unknown [127.0.2.5]) by dcvr.yhbt.net (Postfix) with ESMTP id 131121F407; Wed, 11 Feb 2009 23:04:58 +0000 (UTC) List-Post: Hello all, Last week, I finally decided to put into motion some ideas I've been kicking around for a year in my head since last year... Basically I don't want to have to deal with threads or support platforms that rely on or encourage threads. Especially given MRI 1.9 where kernel threads are more difficult to debug than green ones. Given the limited scope of this project, I'm thinking it's better to be a part of the Mongrel project since there is shared code and use the Mongrel Rubyforge account for distributing tarballs/gems. I don't have the resources or drive to manage things like support, documentation, bug-trackers myself. Being a UNIX terminal fart, I still find the web-based things painful to use. The source is under the same license as Mongrel and in git (see below) so feel free to contribute :) Of course I've yet to actually thoroughly test, deploy real applications or even run benchmarks on Unicorn. That'll probably happen later today or tomorrow... Here's the README (also at http://unicorn.bogomips.org/) git repository locations are in there, as well. ------------------------------- 8< ---------------------------- = Unicorn: UNIX + LAN/localhost-only fork of Mongrel Only run this behind a full-HTTP-request-buffering reverse proxy if you're serving slow clients. That said, nginx is the only reverse proxy we know of that meets this requirement. == Features * process management: Unicorn will reap and restart workers that die because of broken apps and there is no need to manage multiple processes yourself. * doesn't matter if your application is thread-safe or not, workers all run within their own isolated address space and only serve one client at a time... * able to listen on multiple interfaces, including UNIX sockets, each worker process can also bind to a private port via the after_fork hook for easy debugging. * should support all Rack applications (though only Sinatra has been tested) * nginx-style binary re-execution without losing connections. You can upgrade unicorn, your entire application, libraries and even your Ruby interpreter as long as unicorn is installed in the same path * before_fork and after_fork hooks in case your application has special needs when dealing with forked processes. These can be used to setup signal handlers for logrotation, too. * Ruby 1.9-compatible (at least the test cases all pass :>) == 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 is 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 hooks be defined inline. An optional, separate hot_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. * 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. * Since workers only work on one client at a time, the temporary file for storing large POST/PUT requests is reused for the lifetime of the process. This should limit temp directory growth on UNIX filesystems where temp file names are never purged from the containing directory. * If the master process dies unexpectedly for any reason, workers will notice within :timeout/2 seconds and follow the master to its death. == License Unicorn is copyright 2009 Eric Wong and contributors. It is based on Mongrel: Mongrel is copyright 2007 Zed A. Shaw and contributors. It is licensed under the Ruby license and the GPL2. See the include LICENSE file for details. == Install The library consists of a C extension so you'll need a C compiler or at least a friend who can build it for you. Finally, the source includes a setup.rb for those who hate RubyGems. You can get the source via git via the following locations: git://git.bogomips.org/unicorn.git http://git.bogomips.org/unicorn.git == Usage See the Sinatra example. It should be capable of running all Rack applications. Since this is a preforking webserver == Contact Newsgroup and mailing list coming, or it'll be a part of the Mongrel project... Email Eric Wong at normalperson-rMlxZR9MS24@public.gmane.org for now. ------------------------------- 8< ----------------------------