Is Thin concurrent if used with Rails / ActiveRecord? - ruby-on-rails

our Rails 4 app is running in in a thin -s 16 ... multiprocess server with Apache as frontend and its reverse proxy handling the internal requests. All works fine and well, the performance is OK for our number of users.
Because everything works just out of the box, I didn't really bother about how Thin actually works. I did stumble about all the Fibers and EventMachine goodness recently though and read up a lot on it.
Thin is using EventMachine for handling Rack requests. So by design it would be able to handle multiple requests in parallel with one ruby process. Unfortunately, while the Thin documentation is functional enough in making you able to run the server in a few minutes' worth of work, it is rather quiet about the internal workings.
Am I correct in assuming that all talk about "concurrency" is moot as soon as I run Thin with Rails? ActiveRecord, the DB drivers, the template processing, etc. are likely not EM enabled, not using Fibers etc., hence will block the single process anyways, while at the same time using most of the server-side processing time in DB-heavy applications.
All my research seems to lead to this conclusion; unfortunately the Thin website/docs say nothing about it. Frankly I am baffled how the word "concurrent" is even entering the picture here...
Can someone clear that up for me? Am I missing some fundamental piece of information, or is the "concurrency" touted on http://code.macournoyer.com/thin/ meant in regards to manually crafted Rack servers which don't use Rails or other "heavy" middlewares?
Thanks!

You are right, when using with Rails it will not be concurrent. Any call to db driver / file system will block the entire ruby interpreter. It may be partially changed in Rails 5, but for now you just need to run a lot of worker processes.

Related

Why rails 5 using puma instead of webrick for development purpose?

I tried to find out the difference between the Puma and Webrick, but didn't get it or satisfied with it.
So could any one please share information regarding it.
By default WEBrick is single threaded, single process. This means that if two requests come in at the same time, the second must wait for the first to finish.
The most efficient way to tackle slow I/O is multithreading. A worker process spawns several worker threads inside of it. Each request is handled by one of those threads, but when it pauses for I/O - like waiting on a db query - another thread starts its work. This rapid back & forth makes best use of your RAM limitations, and keeps your CPU busy.
So, multithreading is achieved using Puma and that is why it is used as a default App Server in Rails App.
This is a question for Ruby on Rails developers rather than broad audience, because I don't understand reasons any other that putting development environment closer to production where Puma is a solid choice.
To correct the current answer however, I must say that Webrick is, and always has been, a multi-threaded web server. It now ships with Ruby language (and also a rubygem is available). And it is definitely good enough to serve Rails applications for development or for lower-scale production environments.
On the other hand it is not as configurable as other web servers like Puma. Also it is based on the old-school new thread per request design. This can be a problem under heavy load which can lead to too many threads created. Modern web servers solve this by using thread pools, worker processes or combination of the two or other techniques. This includes Puma, however for development spawning a new thread per request is totally fine.
I have no hard feelings for any of the two, both are great Ruby web servers and in our project we actually use them both in production. Anyway, if you like using Webrick for RoR development, you indeed can still use it:
rails server webrick
Rails 6.1 Minor update:
rails server -u webrick [-p NNNN]

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.

If Node.js is single threaded, what is Rails?

If we say Node.js is single threaded and therefore there is just one thread that handles all the requests, what is Rails?
As I understand, Node.js is both the application and the server, but I am lost on what Rails would be? How does Rails handle requests in terms of threads/processes?
Rails can be single-threaded, it can be multi-threaded, it can be multi-process (where each process is single-threaded), or it can be multi-process where each process is multi-threaded.
It really all depends upon the app server you're using, and it kind of depends upon which Ruby implementation you're using. MRI Ruby supports native threads as of 1.9, but it still maintains what's known as a global interpreter lock. The GIL prevents the Ruby interpreter from running in multiple threads at a time. In most cases that's not really a big deal though, because the thing threads are helping with the most is waiting for I/O. If you're using either JRuby or Rubinius, they can actually run Ruby code in multiple threads at a time.
Check out the different app servers and what they offer in terms of concurrency features. Unicorn is a common one for deploying multi-process/single-threaded applications. Puma is a newer app server that's capable of running multi-threaded applications, and I believe they're either adding (or maybe have added by now, I'm not sure) the ability to run multi-process as well. Passenger seems to be able to work in every model I've listed above.
I hope this helps a little. It should at least give you some things to Google for to find more information.

Thin vs Unicorn on Heroku

Just wanted to get people's opinions on using Unicorn vs Thin as a rails server. Most of the articles/benchmarks I found online seem very incomplete, so it would nice to have a centralized place to discuss it.
Unicron is a multi-processes server, while thin is an event based/non-blocking server. Event-based servers are great... if your code is asynchronous/non-blocking - vanilla rails is blocking. So unless you use non-blocking rails libraries, I really don't see the advantage of using Thin. Even worse, in a non-blocking server, if your i/o loop is blocking you're going to block the entire loop and not be able to handle any more requests until the blocking call returns. Blocking libraries are going to slow thin down!
Why did Heroku choose Thin as their default server (for cedar)? They are smart guys, so I'm sure they had a reason.
Bellow is a link that suggests replacing Thin with 4 Unicorn workers - this makes perfect sense to me.
4 Unicron workers on Heroku
Thin is easy to configure - not optimal, but it just works in the Heroku environment.
Unicorn can be more efficient, but it needs to be configured: How many workers? Preload App? What do you pick?
I have released Unicorn Heroku apps with workers set to 3, 5 and 8 - just based on how big each app is - how much code, how much memory is used and how much traffic you get all go into picking this number, and you need to monitor over time to make sure you got the number right, and your app isn't running out of memory.
Preload false - this will make your app start slower, but when Unicorn restarts a worker, this is 'safer' with network connections (memcache, postgres, mongo etc)
Preload true - this is better, but you need to handle server re-connections correctly in the pre and post fork code.
Thin has none of these issues out of the box, but you only get process of execution.
Summary: It's really hard to configure Unicorn out of the box to work well (or at all) for everyone, whereas Thin can just work to get people running with fewer support requests.
Recently (only a few months ago) the folks behind Phusion Passenger add support to Heroku. Definitely this is an alternative you should try and see if fits your needs.
Is blazing fast even with 1 dyno and the drop in response time is palpable.
A simple Passenger Ruby Heroku Demo is hosted on github.
The main benefits that Passengers on Heroku claims are:
Static asset acceleration through Nginx - Don't let your Ruby app serve static assets, let Nginx do it for you and offload your app for the really important tasks. Nginx will do a much better job.
Multiple worker processes - Instead of running only one worker on a dyno, Phusion Passenger runs multiple worker on a single dyno, thus utilizing its resources to its fullest and giving you more bang for the buck. This approach is similar to Unicorn's. But unlike Unicorn, Phusion Passenger dynamically scales the number of worker processes based on current traffic, thus freeing up resources when they're not necessary.
Memory optimizations - Phusion Passenger uses less memory than Thin and Unicorn. It also supports copy-on-write virtual memory in combination with code preloading, thus making your app use even less memory when run on Ruby 2.0.
Request/response buffering - The included Nginx buffers requests and responses, thus protecting your app against slow clients (e.g. mobile devices on mobile networks) and improving performance.
Out-of-band garbage collection - Ruby's garbage collector is slow, but why bother your visitors with long response times? Fix this by running garbage collection outside of the normal request-response cycle! This concept, first introduced by Unicorn, has been improved upon: Phusion Passenger ensures that only one request at the same time is running out-of-band garbage collection, thus eliminating all the problems Unicorn's out-of-band garbage collection has.
JRuby support - Unicorn's a better choice than Thin, but it doesn't support JRuby. Phusion Passenger does.
Hope this helps.
Heroku does not use intelligent routing - it will randomly assign jobs to dynos regardless of whether the dyno is busy. Thus, if your dyno cannot handle multiple jobs at once, you will get latency (perhaps massive latency) even if you are paying for lots of other dynos that are free. " That's right — if your app needs 80 dynos with an intelligent router, it needs 4,000 with a random router. "
http://news.rapgenius.com/James-somers-herokus-ugly-secret-lyrics
Heroku says they are working on this, and their plan is to make it easier to use Unicorn. They basically said "Oops, we didn't notice that this was a problem for a few years... and now that we look, it's definitely a problem for Thin... so I guess you need to use a different program than the one we've been pushing all this time."
http://news.rapgenius.com/Jesper-joergensen-routing-performance-update-lyrics
From the official Heroku explanation (second link above):
"Rails, in fact, does not yet reliably support concurrent request handling. This leaves Rails developers unable to leverage the additional concurrency capabilities offered by the Cedar stack, unless they move to a concurrent web server like Puma or Unicorn.
Rails apps deployed to Cedar with Thin can rather quickly end up with request queuing problems. Because the Cedar router no longer does any queuing on behalf of the app, requests queued at the dyno must wait until the single Rails process works its way through the queue. Many customers have run into this issue and we failed to take action and provide them with a better approach to deploying Rails apps on Cedar."
Also of interest is that their performance tools, including New Relic, have not been reporting time spent in the dyno queue.
http://news.rapgenius.com/Lemon-money-trees-rap-genius-response-to-heroku-lyrics
Oops.

Thin + Nginx Production ready combination for RubyOnRails Application

I have recently installed Nginx + Thin on my deployment server, but i am not sure how this will perform in last requests & responses situation. lets say 1000/req per sec.
so the speed on thin is good with 10-100 req /per sec
I wanted to know on higher volumes of data being processed on the request/response cluster.
Guide me on this :-)
Multiple thin processes and nginx are capable of providing lots of speed, depending on what your application is doing. So, the problem will be your application code, the speed of your application server, and your database server.
Scaling Rails has been recently covered in depth by the Scaling Rails Screencasts. I recommend you start there. My 5 step program to scaling Rails would be:
First step is to have the tools to look at what is slow in your application. Do not spend time optimizing everything in your application when you don't know what the problem is.
The easiest way to be able to handle lots of requests/second is with page caching.
If you can't do that, cache everything possible (fragment caching, use memcached to cache data, etc), to speed up your application.
After that, optimize your application as best as possible, make SQL queries fast, index everything, etc.
If you still need more speed, throw more hardware at the problem. Get a big, powerful database server, a bunch of app servers, and proxy your requests across them. You can start here, too, but it will only delay the optimization process.
If you have a single server I think that the main key is, apart from everything already mentioned, is don't skimp on the specs of it. Trying to get too much to run on too little is just a recipe for disaster.
It is also a good idea to get monit or God monitoring your thin instances, I started out with God, but it leaked memory pretty bad on Ruby 1.8.6 so I stop using it in favour of monit. Monit is written in C I believe and has a tiny memory footprint so I'd recommend that one.
If all that seems like a bit much to keep nginx and thin playing nicely you may want to look into an all in one solution like Passenger or LiteSpeed. I have very little experience with these so can offer no substancial advice for them.

Resources