Slow Client connection blocks Mongrel - ruby-on-rails

I have a Apache + Haproxy + Mongrel setup for my rails application. When I hit a particular server page, mongrel takes around 100ms to process the request and I get the page in around 5 secs due to data transmission time on my slow home connection.
Now I see that during these 5 secs of data transmission, mongrel does not serve any other request. I am surprised as that means mongrel is serving the response html to the client and is blocked till the client receives it. Shouldn't serving response be the job of Apache?
This puts serious bottleneck in the no of requests Mongrel can serve as that would depend on the speed of the client connection. Is there any way that html generated by mongrel is served by apache/haproxy or any other web server like nginx?
I wonder how the other high traffic sites are managing it?

Most sites that use mongrel use lots of them as they do block like you are experiencing.
You'll probably want to look into passenger instead as it is they way to go these days.

mongrel itself is multi-threaded, but rails can process only one process at a time by default, although this can be changed by config. In case of mongrel, use mongrel-cluster.
FYI passenger also sets up a pool of applications but it is nicer to deploy, has better press and is more popular right now.

Related

Is it bad to use unicorn without nginx? why?

I read that unicorn is fast to serve static content, slow users, making redirects.
Why is better nginx+unicorn vs running unicorn only, and scale the number of unicorn workers when needed?
Do you have any numbers showing how much fast is nginx on each of these things(redirecting, proxying, serving static content)?
As Heroku DevCenter claims, Unicorn workers are vulnerable to slow clients.
Each worker is only able to process a single request, and if the client is not ready to accept the entire answer (aka "slow client"), the Unicorn worker is blocked on sending out the response and cannot handle the next one. Since each Unicorn worker takes up a substantial amount of RAM (again, see Heroku, it claims to handle 2-4 processes at 512 MiB RAM), you cannot rely on number of workers, since it's about the number of clients that can render your application inoperable by pretending to have slow connections.
When behind nginx, Unicorn is able to dump the entire answer into nginx's buffer and switch immediately to handling the next request.
That said, nginx with a single Unicorn worker behind is much more reliable than a bunch of Unicorn workers exposed directly.
NB: for the folks using ancient Rubies out there: if you'll be using a set of Unicorn workers, consider migrating to at least Ruby 2.0 to reduce RAM consumption by sharing common data across forked processes (ref).

Why do we need nginx with thin on production setup?

Why do we need to install nginx with thin on production setup, As thin is itself a web server. Every blog post people are using ruby+rails+nginx+thin?
As stated by Michael nginx balances thin (whatever that means). But another reason to use nginx in front of any ruby server is to serve static files (if you use page caching, they also can be served by nginx), which means requests wont even touch your ruby app, and increase a lot your performance. Also nginx although it seems to be the popular choice on the ruby/rails community, there are other alternatives like apache.
Ngnix is used to load balance thin. You may wish to use Unicorn instead. More on the matter here: http://cmelbye.github.io/2009/10/04/thin-vs-unicorn.html
Thin and all Ruby servers are slower than servers written in C language - e.g. Nginx and Apache, when serving static files - images, rendered html etc.
Nginx is lightweight and has great concurrency support. So when you have a long data transmission like upload, download or slow client it pays off. Instead of a heavy Ruby process hanging in memory, waiting for the end of transmission, you have a light Nginx process that will pass upload to a Ruby process only after the file is uploaded. Or receive response from Rails, stop Rails process and serve response for as long as required to the client.

Difference between Nginx and Mongrel?

I often read about Nginx and Mongrel being used together. Can someone explain to me how they are different? Why is Mongrel needed? Why is it not advisable to have Nginx directly communicate to the many Rails servers?
Both are web servers, but they do not share the same focus :
Mongrel is basically a ruby application server that presents an HTTP Interface. It does one thing, taking a request, passing it to your ruby code and serves the answer back in http. It does not handle concurrency, or any performance related feature. One mongrel means there is one ruby process that will handle requests.
Nginx is a fully featured web server, aimed at performances. It can deliver high performance on static files and can't handle Ruby, Python or any other language in a direct manner. It relies on FastGCI or proxying to other application servers to do that.
To be clear, your rails app by itself isn't directly usable, it needs what you can call a container (I suggest you read some about http://rack.github.com/), in this case Mongrel. When you run rails console, it's usually webrick, the most basic web "app" server we have in Ruby (it's part of the standard library).
Then why do we use Nginx in front ? Let's consider we use only Mongrel : we fire a mongrel instance, listening on the port 80. If your requests takes for example 500 ms to complete, you can handle 2 clients per second any nothing more. But wait that's clearly not enough. Let's fire another mongrel instance. But we can't have it listen on the port 80 since it's already used by the first instance and there's nothing we can do about it.
So we need something in front that can handle multiple Mongrel instances, by still listening the port 80. You throw in a Nginx server, that will (proxy) dispatch the requests to your many mongrel instances and you can now add more instances to serve more clients simultaneously.
Back to answering your question, having NGinx communicating to a rails server, means firing one or many Mongrel (or Thin / Unicorn, whatever server is available) and informing NGinx it has to pass the requests to them. It's a popular pattern to host rails services next to using Passenger, which basically provides a way for Apache workers to handle ruby code.
Difference between Nginx and Mongrel
Both are indeed HTTP server, but their focus is different. Mongrel is
a fast HTTP server aimed mostly at Ruby-based applications. it's easily extensible with Ruby code. However, it's not very
good at serving static files, i.e. it's slower than Apache and nginx.
Also, Rails is single threaded, meaning that during the course of a
request (calling a controller method until the actual rendering) the
mongrel is locked.
To work around the above mentioned disadvantages of Mongrel and
Rails, the preferred setup in a production app is to put either
Apache or nginx as the main webserver and if a request for a non-
static Rails page is received, to pass this to a number of underlying
mongrels, let the mongrel hand back the rendered page to Apache/nginx
and serve that page, together with static files such as images/
stylesheets/… It might seem a bit daunting and complex at first, but
once you actually implement it, it's extremely powerful and stable (I
have several apps that have been running for months to years on a
server without a single restart).
It boils down to this, let Apache/nginx do what it's best at, let the
mongrel cluster do what it's best at, everybody is happy.
Choosing nginx over Apache is mostly based on memory considerations.
Apache is quite a hefty webserver, especially if all you actually do
is serve some static files with it and balance the rest over a bunch
of mongrels. Nginx is very lightweight and performant and can do the
same job just as good as Apache. But if you're familiar with Apache,
don't want to get the grips with nginx configuration and have lots of
memory on your server, you can still go for Apache. On a basic VPS,
nginx is a more suitable approach.
for your more information
Apache vs Nginx
They're both web servers. They can serve static files but - with the right modules - can also serve dynamic web apps e.g. those written in PHP. Apache is more popular and has more features, Nginx is smaller and faster and has less features.
Neither Apache nor Nginx can serve Rails apps out-of-the-box. To do that you need to use Apache/Nginx in combination with some kind of add-on, described later.
Apache and Nginx can also act as reverse proxies, meaning that they can take an incoming HTTP request and forward it to another server which also speaks HTTP. When that server responds with an HTTP response, Apache/Nginx will forward the response back to the client. You will learn later why this is relevant.
Mongrel vs WEBrick
Mongrel is a Ruby "application server". In concrete terms this means that Mongrel is an application which:
Loads your Rails app inside its own process space.
Sets up a TCP socket, allowing it to communicate with the outside world (e.g. the Internet). Mongrel listens for HTTP requests on this socket and passes the request data to the Rails app. The Rails app then returns an object which describes how the HTTP response should look like, and Mongrel takes care of converting it to an actual HTTP response (the actual bytes) and sends it back over the socket.
WEBrick does the same thing. Differences with Mongrel:
It is written entirely in Ruby. Mongrel is part Ruby part C; mostly Ruby, but its HTTP parser is written in C for performance.
WEBrick is slower and less robust. It has some known memory leaks and some known HTTP parsing problems.
WEBrick is usually only used as the default server during development because WEBrick is included in Ruby by default. Mongrel needs to be installed separately. Nobody uses WEBrick in production environments.
Another Ruby application server that falls under the same category is Thin. While it's internally different from both Mongrel and WEBrick it falls under the same category when it comes to usage and its overall role in the server stack.

Is there a way to actively monitor HTTP requests on Rails, to direct the request to another mongrel if it times out?

I am working with a client who's server admin refuses to install monit or god on their webserver to restart locked or slow mongrels / threads as they reckon the application should just work flawlessly and threads should never lock / go slow.
Unfortunately their app makes a lot of calls to 3rd party webservices, many of which are slow, and their database is heavily un-optimized (I cannot access or push to change this) so there are a lot of slow AR queries causing timeouts.
Is it possible to actively monitor HTTP requests & if one gets passed to a slow / locked mongrel then re-direct it to an active one?
I know this may produce a slow response, but better slow than a connection timeout error.
Thanks!
You could install HAProxy or use nginx as a round robin load balancer, but really I suggest you skip those and install the Passenger gem available for Apache or nginx, the de facto Rails stack for a while now. You can also run Passenger in development (google for articles). I suggest you insist to the SysAdmin that Passenger is part of the application stack.

ruby rails loop causes server freeze

I am working on a Ruby on Rails project on Windows. I have Ruby 1.86 and Rails 2.35 installed. Everything is fine until I tried to implement a comet process. I have the following code written to respond to a long poll javascript request. But everytime this function is called, it will hang the whole rails server, no second request can get in, until the timeout. (I know there is juggernaut, but I like to implement one myself first :)
Is this due to my server setup? The project will be deployed on a linux server with Ngix and Passenger setup, will it suffer the same problem?
def comet_hook
timeout(5) do
while true do
key = 'station_' + station_id.to_s + '_message_lastwrite'
if Rails.cache.exist?(key)
#cache_time = DateTime.parse(Rails.cache.read(key))
if #cache_time > hook_start
#messages = #station.messages_posted_after(hook_start)
hook_start = #cache_time
break
end
end
end
...
end
Also with Rails memory store cache, I keep getting "cannot modify frozen object" error, so the above script only worked for me when I switched to File cache. :(
Your Windows setup probably consists of a single webrick or mongrel instance which can handle only one connection at a time.
Passeger and nginx setups can (and typically will), of course, accommodate multiple concurrent sessions via a cluster of webserver processes (be it a mongrel cluster behind nginx, or a cluster of Passenger Apache worker processes), if configured to do so (the servers configuration value for mongrel clusters, MaxClients for Apache/Passenger.)
Scale the number of concurrent client sessions and/or system memory based on expected traffic (e.g. if you expect 10 requests/second, where each request can take up to 5s or more to service, you will need to accommodate 50 or more client connections i.e. 50 or more Mongrel servers in the cluster or 50 or more Apache worker processes -- with non-trivial memory requirements.)

Resources