Why thin behind nginx? - ruby-on-rails

Deploying my first web app. I have been using thin, it's simple and easy. All I need is a config file.
But a lot of people use nginx and place a couple thin instance behind that. Why? Why not just use thin alone? And why use nginx rather than placing 3 thin instances behind a single thin instance?
Thanks

Scalability is the main reason. While Thin can do SSL, serve static files, and handle large responses to slow clients, Nginx is better at all of them for any given CPU and memory footprint. Even better, Nginx can do all that transparently so that the app doesn't have implement anything to benefit. It's also a decent load balancer.
Once your app scales beyond one machine, you will need something like Nginx anyway, and there is no harm in implementing it from the start. Even if your app doesn't need to scale, there are other reasons for using Nginx --- especially if you're running more than one web app on the same machine, or if the app is modular.

Related

Is it necessary to use Nginx when deploy a Rails API ONLY app?

Currently I've already read a lot tutorials teaching about Rails App deployment, almost every one of them use Nginx or other alternatives like Apache to serve static pages. Also in this QA Why do we need nginx with thin on production setup? they said Nginx is used for load balancing.
I can understand the reasons mentioned above, but I write a Rails App as a pure API backend service, the only purpose is to serve JSON formatted data for other client-side apps, no pages rendering at all. So my questions are:
In my situation, do I really need Nginx just to deploy a pure API Rails App?
If not, how should I deploy my app? just running it (with unicorn in production env) at background is good enough? like rails server -e production -d?
I'm so curious about these two question, hope someone can explain the details or show me some good references for me, thanks in advance.
See basically, Unicorn or thin are all single threaded servers. Which in a way means they handle single requests at a time, using defering and other techniques.
For a production setup you would generally run many instances of unicorn or thin ( depending on your load etc ), you would need to load balance b/w those rails application server instances, thats why you need Nginx or something similar on top.
to serve JSON formatted data for other client-side apps, no pages rendering at all
You see, it makes no difference. These tasks are similar: format certain data into a specific text-based structure. Much like rendering a view in HAML, ERB or whatever.
The difference is, you won't be serving static assets. At least, it's not practical for pure JSON APIs.
If you aim for compact JSON responses, your best bet is Unicorn (several workers) + nginx.
Unicorn is simpler and aims for fast single-client response. That is, a slow client could force Unicorn to waste a lot of time serving him a response. When backed by nginx though, it fires the entire response into nginx's buffer and heads for the next one only waiting for nginx to accept the response (since it's usually on the same machine, it's blazing fast). nginx then hands out responses. There could possibly be multiple instances of Unicorn, if one is not enough: but using only one could eliminate any kinds of data races on app level (which are possible in multithreaded apps).
Thin is designed by itself to handle multiple clients concurrently by itself, through use of threads and workers. Keep in mind though that MRI ("classic" Ruby) doesn't have "truly concurrent threads" because of GIL. Technoligies it's based on (Ruby+C) make it inferior to nginx (pure C) in terms of resource usage efficiency. nginx is even used sometimes to counter DDoS attacks, efficiency is proven in the wild (<1> <2> <3> and many more).
You could benefit from Thin if your app implied concurrent service for multiple clients, like Server-Sent Events or WebSocket usage, that require maintaining a constant connection. This one doesn't seem to. Don't count on concurrency too much where it's not required.

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.

How to run multiple tiny Ruby (Rack) apps on one server?

I want to run several (more than 2) tiny Rack-based apps on my VPS, which already has one large Rails app running.
The Rails app uses the traditional pair of Unicorn & nginx, and it requires most of the RAM that I have on my VPS.
I've tried adding similar Unicorn configurations for each app and it led me to conclude the RAM is insufficient.
So my question is: is it possible to set up one small memory-saving server which allows me to run several Sinatra apps at once?
UPDATE: in case it matters, I don't care much about the performance. These apps are not intended to do any serious jobs.
UPDATE 2: an approach based on sockets shared with Nginx is preferred over the one with ports.
Thanks!
I did my own exploration of this question and I think I found a solution which will allow me having one web-server running all my tiny apps at once.
It is based on RackStack not-yet-a-gem created by Remi Taylor (#remi on Github) https://github.com/remi/rack-stack.
RackStack is inspired by Rack::Builder, which as well seems being good for accomplishing a task like this - RackStack just goes in the same direction further, abstracting "stack" functionality in a way I found very nice and handy.
Here is a demonstration of RackStack which consists of two sample apps (Sinatra and Rack): https://github.com/stanislaw/skeletons/tree/master/rack_stack. To mimic stack app behavior on a real server I modified my /etc/hosts file to have localhost2 host pointing to 127.0.0.1.
I fire up Thin server and then run requests on localhost or localhost2: the requests to 'localhost' are served by FirstApp, to 'localhost2' by SecondApp.
I can't now foresee any problems that can appear, when I will test my apps on a real server, but now this approach seems to be exactly what I was looking for: I imagine, that on a real server Nginx will pass requests to all the hosts associated with my rack apps to a socket listened by Thin server. So, RackStack will meet only those requests which are addressed to the apps I have in my stack.
Any suggestions, improvements of this scheme or alternatives are still appreciated!

why do we need an apache server when we deploy a rails app?

i though we could just deploy it with webrick or mongrel
Most Ruby application servers will only run a single Ruby process (and Ruby has a global interpreter lock that makes multithreading quite pointless), which means that it can only serve one request at a time. To say the least, this will not give you very good performance.
There are two ways around this: either you run several Ruby application servers and put a load balancer or reverse proxy in front of them, e.g. Nginx or Apache in front of a pack of Mongrels or Thin servers (the number of processes you run reflects the number of requests you will be able to handle in parallel). Or you run Passenger, which is an Apache or Nginx module that manages a pool of applications that can dynamically grow and shrink as the load changes. The first option gives you more configuration options, but the second option is easier to manage. Which one you want depends on your use case.
There are of course other solutions too, but they are for more specific use cases. You can, for example, write a very performant application and deploy it with Thin -- but it requires that you write an event driven application. You can't deploy a Rails app and expect the same performance.
Before Phusion Passenger allowed Rails hosting with Apache and nginx, deploying a rails app was scary and difficult. Apache is a very mature web server which scales easily and is configurable to meet many needs. (nginx is not as mature but is very efficient, also very configurable and a great alternative to Apache for rails hosting.) Webrick and Mongrel are great for development, but unless you are an expert, it is difficult to set them up for production use.
You can technically, but you don't usually want to, because that will impose a fair bit of overhead when serving static files like css or images.
There are any number of ways you can deploy a Rails app without involving Apache, but Apache is the most popular server around, the most mature server around and among the most stable and scalable. WEBrick and Mongrel both have their own merits, but Apache is just the default assumption for Web servers and the path of least resistance in most cases.

Recommendations (and Differences) between different Ruby on Rails Production Web Servers

Very soon I plan on deploying my first Ruby on Rails application to a production environment and I've even picked a webhost with all the managed server and Capistrano goodness you'd expect from a RoR provider.
The provider allows for Mongrel, Thin, Passenger & FastCGI web servers, which seems very flexible, but I honestly don't know the differences between them. I have looked into them some, but it all gets a bit much when they start talking about features and maximum simultaneous requests - and that this data seems to vary depending on who's publishing it.
I have looked at Passenger (on the surface) - which does seem very appealing to me - but I was under the impression that Passenger wasn't the actual webserver, and instead was more like a layer on top of Apache or nginx and managed spawned instances of the application (like a Mongrel cluster).
Can anyone please set me straight with the differences in layman's terms so as I can choose wisely (because anyone who's seen Indiana Jones and the Last Crusade knows what happens if you choose poorly).
Short answer
Go with Apache/Nginx + Passenger. Passenger is fast, reliable, easy to configure and deploy. Passenger has been adopted by a large number of big Rails applications, including Shopify.
(source: modrails.com)
The long answer
Forget about CGI and FastCGI. In the beginning there were no other alternatives so the only way to run Rails was using CGI or the faster browser FastCGI. Nowadays almost nobody runs Rails under CGI. The latest Rails versions no longer provides .cgi and .fcgi runners.
Mongrel has been a largely adopted solution, the best replacement for CGI and FCGI. Many sites still use Mongrel and Mongrel cluster, however Mongrel project is almost dead and many projects already moved to other solutions (mostly Passenger).
Also, a Mongrel based architecture is quite hard to configure because it needs a frontend proxy (thin, ngnix) and a backend architecture composed of multiple Mongrel instances.
Passenger has been gaining widespread attention since it was released. Many projects switched from Mongrel to Passenger for many reasons, including (but not limited to) easy deployment, maintainability and performance. Additionally, Passenger is now available for both Apache and Ngnix.
The simplest way to use Passenger is the Apache + Passenger configuration. One Apache installation and multiple Passenger processes.
If you need better performance and scalability, you can use Ngnix as a frontend proxy and forward all Rails requests to multiple backend servers, each one composed of Apache + Passenger.
I'm not going into the technical details here, this solution is intended to be used by Rails projects with an high level of traffic.
Even more complex solutions include a combination of different levels including http proxies and servers. You can have an idea of what I'm talking about reading some internal details from GitHub and Heroku.
Right now, Passenger is the best answer for most Rails projects.
Mongrel and Thin are single ruby process servers that you would run multiple of as a cluster behind some type of proxy (like Apache or Nginx). The proxy would manage which instance of Mongrel or Thin services the requests.
Passenger creates an interface between Apache or Nginx that creates an application spawning process and then forks out processes to server up incoming requests as they come in. There are a lot of configuration options for how long those processes live, how many there can be, and how many requests they will serve before they die. This is by far the most common way to scale up and handle a high traffic application, but it is not without drawbacks. This can only be done on a *nix operating system (linux, mac os x, etc). Also, these processes spin up on demand, so if no one accesses your site for a while, they processes die and the next request has the delay of it starting back up again. With Mongrel and Thin, the process is always running. Sometimes though, your processes being new and fresh can be a good thing for memory usage etc.
If it is going to be a relatively low traffic site, Mongrel or Thin provides a simple, easy to manage way to deploy the application. For higher traffic sites where you need the smart queuing and process management of something like Passenger, it is a very good solution.
As for fastcgi, you probably want to use that as a last option.
I use Passenger + nginx. It works really, really well.
To get some instant performance boast with passenger, I recommend using ruby enterprise edition.

Resources