Forum: Ruby on Rails Mongrel + RubyOnRails + FileUploads = Problems?

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
B29105598b6464efc13b04cb445efa85?d=identicon&s=25 Chris Bruce (Guest)
on 2006-05-03 19:08
(Received via mailing list)
I really like the idea of using Mongrel.  But reading the FAQ, I noticed
something that might be an issue.  It stated:

"Ruby on Rails is not thread safe so there is a synchronized block
around the calls to Dispatcher.dispatch. This means that everything is
threaded right before and right after Rails runs. While Rails is running
there is only one controller in operation at a time."

So does this mean that if someone us uploading a large file (say around
80mb), that Rails will stop serving any other requests until the file is
finished uploading?


Thanks,


Chris
59de94a56fd2c198f33d9515d1c05961?d=identicon&s=25 Tom Mornini (Guest)
on 2006-05-03 20:49
(Received via mailing list)
Yes. That's why you need more than 1 FastCGI or Mongrel
instance, behind a load balanced proxy.

--
-- Tom Mornini
8c43ed7f065406bf171c0f3eb32cf615?d=identicon&s=25 Zed Shaw (Guest)
on 2006-05-03 23:18
(Received via mailing list)
Hi Chris,


On 5/3/06 12:42 PM, "Chris Bruce" <cbruce@sleeter.com> wrote:

> I really like the idea of using Mongrel.  But reading the FAQ, I noticed
> something that might be an issue.  It stated:
>
> "Ruby on Rails is not thread safe so there is a synchronized block
> around the calls to Dispatcher.dispatch. This means that everything is
> threaded right before and right after Rails runs. While Rails is running
> there is only one controller in operation at a time."
>

Keep in mind that this is a rails issue, not a Mongrel issue.  All other
aspect of mongrel are as thread safe as Ruby can be.

> So does this mean that if someone us uploading a large file (say around
> 80mb), that Rails will stop serving any other requests until the file is
> finished uploading?
>
>

Yes and no.  If you get the pre-release (which I've got to release soon
or
people will kill me), then you'll get file uploads which are streamed to
the
disk if they are too big.  You can install the pre-release like so:

  gem install mongrel --source=http://mongrel.rubyforge.org/releases/

But *NOT ON WINDOWS*.  I tend to exclude windows folks from testing
pre-releases since it's a more complicated platform to build on.

This will let many people upload files at the same time, but there's
kind of
an annoying catch.  Ruby uses the cgi.rb to process the multipart
sections
of the uploaded file.  So, while Mongrel and multithread crank the
upload to
a temp file, once this temp file is handed to Rails it has to reprocess
it
all over again.

This second processing is to find the multipart boundaries and uses a
lot of
horrible regex and backtracking.  So, with large uploads you can see
pretty
big CPU spikes and fill up your rails processes fairly quick.

So, in general, if you're doing smallish uploads--like around 1 or 2
MB--then the pre-release is good stuff.  Once the upload gets above
about
50MB things start to get a little slow.  At around 100MB it just sucks
to be
you.

Zed A. Shaw
http://www.zedshaw.com/
http://mongrel.rubyforge.org/
E3c79c779c0b390049289cdfe7cb9705?d=identicon&s=25 Bob Hutchison (Guest)
on 2006-05-04 04:27
(Received via mailing list)
On May 3, 2006, at 5:13 PM, Zed Shaw wrote:

>> So does this mean that if someone us uploading a large file (say
>> around
>> 80mb), that Rails will stop serving any other requests until the
>> file is
>> finished uploading?
>>
>>
>
> Yes and no.

[ snip ]

>
> This second processing is to find the multipart boundaries and uses
> a lot of
> horrible regex and backtracking.  So, with large uploads you can
> see pretty
> big CPU spikes and fill up your rails processes fairly quick.

Does the same issue exists for downloading?

This problem is tending to the uglier side of things, so maybe a bit
of an ugly hack won't look so bad?

What happens if you use a Mongrel handler for the file upload,
storing the file somewhere on disk, then interfere with the normal
proceedings? Maybe hacking at the request object sent to Rails by
adding a query parameter or HTTP header that says where the file was
put? Maybe a redirect with the file name instead of the file?

Would that give you the multi-threaded upload?

Bob

> http://mongrel.rubyforge.org/
>

----
Bob Hutchison                  -- blogs at <http://www.recursive.ca/
hutch/>
Recursive Design Inc.          -- <http://www.recursive.ca/>
Raconteur                      -- <http://www.raconteur.info/>
xampl for Ruby                 -- <http://rubyforge.org/projects/xampl/>
8c43ed7f065406bf171c0f3eb32cf615?d=identicon&s=25 Zed Shaw (Guest)
on 2006-05-05 02:32
(Received via mailing list)
On 5/3/06 10:26 PM, "Bob Hutchison" <hutch@recursive.ca> wrote:

>
> On May 3, 2006, at 5:13 PM, Zed Shaw wrote:
>
<snip>
>> This second processing is to find the multipart boundaries and uses
>> a lot of
>> horrible regex and backtracking.  So, with large uploads you can
>> see pretty
>> big CPU spikes and fill up your rails processes fairly quick.
>
> Does the same issue exists for downloading?
>

No since Mongrel or a fronting web server handles those so you get much
better concurrency.  Now, if your rails app is generating the content
for
each request then you're screwed.

Remember, it's not just queue length but how long each request stays in
the
queue.  If you have 10 backend Mongrels, then you have a queue length of
10
(basically).  That doesn't mean that you can only handle 10/second.
Queues
are really weird and kind of don't make sense until you simulate them.
You
have to use some statistical distribution of time for each request to
get an
idea of how such a queue performs.   And nothing beats straight up
measurement with a tool like httperf.  It's the reality bringer.

> This problem is tending to the uglier side of things, so maybe a bit
> of an ugly hack won't look so bad?
>

What you mention below isn't a hack, it's actually the primary advantage
of
using Mongrel over fastcgi.  If a Rails action is slow, you can spend a
bit
more effort and write a Mongrel Handler that will do it faster.  It's a
little tricker--kind of bare metal--but not impossible.

> What happens if you use a Mongrel handler for the file upload,
> storing the file somewhere on disk, then interfere with the normal
> proceedings? Maybe hacking at the request object sent to Rails by
> adding a query parameter or HTTP header that says where the file was
> put? Maybe a redirect with the file name instead of the file?
>

Bingo.  I actually have documentation in the queue for such a thing.
What
you could do is have the uploads be done with mongrel, have even an ajax
progress thing done with mongrel, and when it's all finished bounce it
over
to rails to complete the process.

Best of all, if you did it and managed to completely avoid an
"railsisms"
shooting for a nice REST uplaod/progress/done process, you could even
scale
that up by writing a little apache or lighttpd module.  Of course you'd
have
to be REALLY desperate to do that, but the possiblity is there.

Key with this is to avoid Ruby's sessions.  What you can do is grab the
cookie and parse out the rails session ID.  Use that as the name of a
directory where the user's uploaded file is stored.  Then, when rails is
run
to process the file you just have to match the current session id to
that
directory.  Very lightweight.

> Would that give you the multi-threaded upload?
>

Yep, but remember, just making something multi-threaded doesn't
instantly
solve all your problems.  All computers eventually have a finite level
of
concurrency, and there's always a point where just one more request can
literally break the server's back.  Where this breaking point is can be
10
concurrent or 10 million.

What you should do is test your current setup and see if that meets your
needs.  There's no point in getting paranoid and spending the next 3
months
rewriting your whole app in Mongrel only.  If what you have now meets
your
performance requirements (you do have measurable performance
requirements
right?) then don't bother.

Once you see that particular Rails actions don't meet your needs, make a
plan to try something else, but don't just grab for a Mongrel handler.
Figure out how far off your Rails action is from your needs (you do have
measurable performance requirements right?) and then develop a set of
possible solutions that might meet those needs.  Do a few small
prototypes
to see if your proposed solutions will meet the requirements (you do
have
measurable performance requirements right?).  Then pick the solution
that
does the job.

Also, after you've written the solution, retest everything and
continually
verify.  Don't believe that your own shit don't smell.  I've seen people
spend months making something they thought was really fast only to find
out
it gave them no statistically significant improvement.  I myself have
saved
tons of potentially lost development time by testing a potential
solution
before investing, and by testing as I go I avoid going down bad paths
for no
benefit.

Basing your decisions on evidence is always much better than just
blindly
reaching for what everyone else is doing.

Zed A. Shaw
http://www.zedshaw.com/
http://mongrel.rubyforge.org/
E3c79c779c0b390049289cdfe7cb9705?d=identicon&s=25 Bob Hutchison (Guest)
on 2006-05-05 04:03
(Received via mailing list)
On May 4, 2006, at 8:27 PM, Zed Shaw wrote:

>>> a lot of
> content for
> each request then you're screwed.

Doesn't look good for me then :-) I'll probably do something like below.

> to get an
> spend a bit
> more effort and write a Mongrel Handler that will do it faster.
> It's a
> little tricker--kind of bare metal--but not impossible.

This is good. I'm worried about a couple of occasional things that
are a lot nasty.

> you could do is have the uploads be done with mongrel, have even an
> you'd have
> to be REALLY desperate to do that, but the possiblity is there.
>
> Key with this is to avoid Ruby's sessions.  What you can do is grab
> the
> cookie and parse out the rails session ID.  Use that as the name of a
> directory where the user's uploaded file is stored.  Then, when
> rails is run
> to process the file you just have to match the current session id
> to that
> directory.  Very lightweight.

Okay, this is in line with what I was hoping. No way am I going to be
doing anything like an apache or lighttpd module.

> literally break the server's back.  Where this breaking point is
> can be 10
> concurrent or 10 million.

I'm only worried about two concurrent users, but where one is doing
something like uploading a 45 minute video. When that happens I think
the number of concurrent users is going to get a bit higher :-)

The remainder of your advice is good-all-the-time optimisation advice.

Cheers,
Bob

>
> measurable performance requirements right?).  Then pick the
> have saved
> Zed A. Shaw
> http://www.zedshaw.com/
> http://mongrel.rubyforge.org/
>
>
>
> _______________________________________________
> Rails mailing list
> Rails@lists.rubyonrails.org
> http://lists.rubyonrails.org/mailman/listinfo/rails

----
Bob Hutchison                  -- blogs at <http://www.recursive.ca/
hutch/>
Recursive Design Inc.          -- <http://www.recursive.ca/>
Raconteur                      -- <http://www.raconteur.info/>
xampl for Ruby                 -- <http://rubyforge.org/projects/xampl/>
14116e951e403e8faac42c0108835a53?d=identicon&s=25 Boris (Guest)
on 2006-05-05 08:26
Zed Shaw wrote:

>> What happens if you use a Mongrel handler for the file upload,
>> storing the file somewhere on disk, then interfere with the normal
>> proceedings? Maybe hacking at the request object sent to Rails by
>> adding a query parameter or HTTP header that says where the file was
>> put? Maybe a redirect with the file name instead of the file?
>>
>
> Bingo.  I actually have documentation in the queue for such a thing.
> What
> you could do is have the uploads be done with mongrel, have even an ajax
> progress thing done with mongrel, and when it's all finished bounce it
> over
> to rails to complete the process.
>
> Best of all, if you did it and managed to completely avoid an
> "railsisms"
> shooting for a nice REST uplaod/progress/done process, you could even
> scale
> that up by writing a little apache or lighttpd module.  Of course you'd
> have
> to be REALLY desperate to do that, but the possiblity is there.

Call me desperate...

I've been struggling for quite a while on getting a proxy working
between IIS (Windows Web Server) and Mongrel (actually - most time was
spend on SCGI :-S). The thing I have been fighting was file uploads as
there is a file encoding issues between the IIS and Mongrel/SCGI. This
seemed to be unsolvable on the .NET part of things - don't ask - so I
actually parked the whole project and decided to spend some time
learning Rails rather than fighting IIS and .NET on this issue.

I you have any information on the Mongrel & Rails part this would be
sweet. Especially any ideaâ??s on making this as â??transparentâ?? as possible
from a Rails point of view would be very helpful. My Ruby/Rails skills
are too limited at this point to tackle this.

/Boris
6ef8cb7cd7cd58077f0b57e4fa49a969?d=identicon&s=25 Brian Hogan (Guest)
on 2006-05-05 14:45
(Received via mailing list)
Boris:
I will have a solution to thisdocumented very shortly... I'm just
finishing
up the documentation for my rails reverse_proxy_fix plugin.

You'll be able to use IIS to receive the requests but you'll use
ISAPIRewrite (the paid version only) to forward requests to Mongrel, and
my
plugin to handle the URL rewriting (with some limitations.... the URL
rewriting only works if the URLs were written with Rails helpers.)

Docs are coming soon which include a simple (IIS to Mongrel) and an
advanced
(IIS to Lighttpd to Mongrel cluster)

I've been promising this for some time but things keep changing so fast
it's
hard to keep up. However I'm hoping to have something on my site at the
end
of the day.
14116e951e403e8faac42c0108835a53?d=identicon&s=25 Boris (Guest)
on 2006-05-05 22:45
Brian Hogan wrote:
> Boris:
> I will have a solution to thisdocumented very shortly... I'm just
> finishing
> up the documentation for my rails reverse_proxy_fix plugin.
>
> You'll be able to use IIS to receive the requests but you'll use
> ISAPIRewrite (the paid version only) to forward requests to Mongrel, and
> my
> plugin to handle the URL rewriting (with some limitations.... the URL
> rewriting only works if the URLs were written with Rails helpers.)
>
> Docs are coming soon which include a simple (IIS to Mongrel) and an
> advanced
> (IIS to Lighttpd to Mongrel cluster)
>
> I've been promising this for some time but things keep changing so fast
> it's
> hard to keep up. However I'm hoping to have something on my site at the
> end
> of the day.

Cool stuff Brian. I was planning to create a sort of mod_proxy for IIS,
so include the possibility to use multiple Mongrel instances and do not
have a need for a commercial isapi plugin.
This topic is locked and can not be replied to.