Sounds like a Mongrel/Rails performance post on <a href="http://mongrel.rubyforge.org/">http://mongrel.rubyforge.org/</a> waiting to happen :)<br><br><div><span class="gmail_quote">On 5/23/06, <b class="gmail_sendername">Zed Shaw
</b> <<a href="mailto:zedshaw@zedshaw.com">zedshaw@zedshaw.com</a>> wrote:</span><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">On Tue, 2006-05-23 at 17:13 -0700, Kevin C wrote:
<br>> I'm confused here.<br>><br>> Does this not-thread-safe mean we can only run ONE mongrel for ONE app<br>> on ONE server? Can we start another mongrel for the same app on the<br>> same server but on a different port (and serve through proxy)?
<br>><br>> I suppose we can run another mongrel for the same app on another server.<br>><br><br>Short explanation: Yes, this is normally what you have to do to get a<br>good production setup going.<br><br>Here's the long explanation that should help you understand what's going
<br>on. First, the Mongrel way:<br><br>1) Mongrel is thread safe as far as it will run any registered handlers<br>in threads and make sure that multiple threads have their own resources.<br>2) Mongrel HttpHandler objects are connected to URIs, but there's only
<br>one per each URI. This means that they run fast since there's no object<br>creation, but that they are very old school and a pain to develop for,<br>only useful for people who really need the speed.<br>3) Mongrel handlers are run in order using a processing chain. Let's
<br>say you register 4 handlers to "/":<br> uri "/", :handler => AuthenticationFilter.new<br> uri "/", :handler => DoFastStuffHandler.new<br> uri "/", :handler => StatisticsFilter.new
<br> uri "/", :handler => DeflateFilter.new<br><br>What happens is that each of these is run in order with the same<br>HttpRequest and HttpResponse objects, they get their turn, and then the<br>final results are sent back to the user. (NOTE: Filter and Handler are
<br>both HttpHandler classes, just named differently for clarity).<br>4) When your handler runs, any instance variables (@foo) are reused by<br>all the threads. You have to work to guard these yourself. It's much<br>like old-school Java servlet programming. This is done for speed only,
<br>and most people won't be writing handlers unless they are uber advanced.<br><br>OK, so now how does rails fit into things? The problem with Rails is<br>that it's got so much code generation and automagic going on that it's
<br>really difficult to make it thread safe. Things would be different if<br>Ruby could ensure that it's code generation and class loading were<br>atomic, but it can't. Because of this Rails has to be locked while it's<br>
processing.<br><br>So, let's say you hit a Rails action with one thread, then this is what<br>happens:<br><br>1) RailsHandler first checks if the request could be page cached or is a<br>file.<br> a) If it is then the DirHandler takes over instead. THIS IS FAST
<br>AND NOT LOCKED. Done, next request.<br>2) RailsHandler determines that this isn't a file and isn't page cached,<br>so it must run the Rails Dispatcher to service the request.<br>3) LOCK!!! But only the call to Dispatcher, the rest of Mongrel keeps
<br>trucking.<br>4) Wait hours for everyone's IO.popen to a perl script that talks to ten<br>databases to produce a full index of the internet and then image map it<br>to generate a CAPTCHA.<br>5) While the above is happening, #1 and #2 still keep going processing
<br>clients. Mongrel is threaded so it happily queues clients up that are<br>all waiting at #3.<br>6) UNLOCK. #4 completes THE FIGHT BEGINS! Whichever client stuck at #3<br>gets the lock will then continue and you're back at #3.
<br>7) Continue until your IO.popen kills server. Incidentally, the results<br>of the Rails request are sent back to the client *after* the lock is<br>released. Rails actually spits its junk to a StringIO so that it can
<br>get done without worrying about socket crap, and then Mongrel deals with<br>the IO and threads from there.<br><br>(I'm mentioning IO.popen because it's incredibly evil, don't use it or<br>fork).<br><br>Now, what this generally means is if you have page caching turned on and
<br>most of your rails requests are pretty snappy, then you can most likely<br>handle quite a few concurrent users without any problems. As long as<br>clients get in and get out of the #3 through #6 LOCK/UNLOCK region<br>
you're set. It also means that you only pay a lock penalty for Rails to<br>run it's action and generate results to a StrinIO. Mongrel handles all<br>the socket garbage in a threaded way.<br><br>The problem comes when folks expect Rails to be an operating system.
<br>They have it spawning processes, managing tons of files, generating maps<br>and reports and latex output and putting them through pre-press<br>operations that take 10 minutes. When this happens you have 3 choices:<br>
<br>1) Only let one person use the application.<br>2) Start a bunch of Mongrels listening on various ports (on various<br>machines) and use pound, pen, balance, lighttpd, litespeed, or apache to<br>proxy requests for a "fronting" machine to the N backends.
<br>3) Rewrite your stuff to use BackgroundDRB or some other custom off-load<br>worker server, and use a nice AJAX "Job in progress..." set of actions<br>to keep things snapppy. Best part about this is you can actually shove
<br>a large portion of the status out into a Mongrel handler (now you know<br>why I covered it).<br><br>Now, why doesn't Mongrel do forking you may ask? All my tests found<br>that the fork available in Ruby just isn't reliable. It causes IO to
<br>get dropped, sockets to go away, files get closed at weird times, and<br>it's just generally bad news. Also, fork isn't really well supported on<br>win32. Nope, it's just loads easier to use mongrel_cluster to manage a
<br>ton of systems, or to setup a bunch of win32 services that listen on<br>different ports.<br><br>Well, hope that long answer helped you out.<br><br><br>--<br>Zed A. Shaw<br><a href="http://www.zedshaw.com/">http://www.zedshaw.com/
</a><br><a href="http://mongrel.rubyforge.org/">http://mongrel.rubyforge.org/</a><br><br><br>_______________________________________________<br>Mongrel-users mailing list<br><a href="mailto:Mongrel-users@rubyforge.org">Mongrel-users@rubyforge.org
</a><br><a href="http://rubyforge.org/mailman/listinfo/mongrel-users">http://rubyforge.org/mailman/listinfo/mongrel-users</a><br></blockquote></div><br><br clear="all"><br>-- <br>I was thinking of the immortal words of Socrates, when he said, "I drank what?"