We all hear a lot about scaling issues in Rails.
I was just curious what the actual costs in handling a HTTP request is in the Rails framework. Meaning, what has to happen for each and every request which comes in? Is there class parsing? Configuration? Database Connection establishment?
That actually depends a lot on which web server you're using, and which configuration you're using, not to mention the application design itself. Configuration and design issues involved include:
Whether you're using fastcgi, old-school cgi, or some other request handling mechanism (affects whether you're going to have to rerun all of the app initialization code per request or not)
Whether you're using memcache (or an alternate caching strategy) or not (affects cost of database requests)
Whether you're using additional load balancing techniques or not
Which session persistence strategy you're using (if needed)
Whether you're using "development" mode or not, which causes code files to be reloaded whenever they're changed (as I recall; maybe it's just per-request) or not
Like most web app frameworks, there are solutions for connection pooling, caching, and process management. There are a whole bunch of ways to manage database access; the usual, default ones are not necessarily the highest performance, but it's not rocket science to adjust that strategy.
Someone who has dug into the internals more deeply can probably speak in more excruciating detail, but most apps use either FastCGI on Apache or an alternate more rails-friendly web server, which means that you only have app setup once per process.
Until the release of Phusion Passenger (aka mod_rails) the "standard" for deployment was not FastCGI but using a cluster of Mongrel servers fronted by Apache and mod_proxy (or Nginx etc).
The main issue behind the "Rails doesn't scale" is the fact that there are some quite complicated threading issues which has meant tiwht the current version of Ruby and the available serving mechanisms, Rails has not been threadsafe. This has meant that multiple containers have been required to run a Rails app to support high-levels of concurrent requests. Passenger makes some of this moot, as it handles all of this internally, and can also be run on a custom build of Ruby (Ruby Enterprise Edition) that changes the way memory is handled.
On top of this, the upcoming versions of both Ruby and Rails are directly addressing the threading issue and should close this argument once and for all.
As far as I am concerned the whole claim is pretty bogus. "Scale" is an architectural concern.
Here's a good high level overview of the lifecycle of a Rails request. After going through this, you can choose specific sections to profile and optimize.
Related
I am playing around with using Rails to underpin a kiosk. This is a terminal where there is only one local user at a time.
Under this system, a browser like Chrome would access the Rails app.
Things I assume would be helpful:
Super-fast, very lightweight Rails server (I'm using Puma).
Eliminating standard processes/assumptions that are meant for internet website contexts (caching, CDNs, middleware, etc.).
In some level of detail preferably, how should one set up a Rails app for maximum performance in a single-user kiosk?
This might sound like a non-answer, but the approach I would take is to use Rails in its default (production) configuration, and optimise performance issues as they arise in your test bed. Running Rails in production mode will likely give you more than enough performance if you have a dedicated machine for a single user (often you'll have many clients to a single Rails instance). Without testing the application, you could sink a considerable amount of time into optimisations that don't impact the user experience.
It may be worth sitting Rails behind Apache/nginx (Passenger is a well understood way to get a Rails app on Apache) to serve your static assets, but from the information provided so far I'd be surprised if performance optimisation was necessary at this stage.
A challenge that might be worth considering at this stage is how you'll deploy changes to your kiosk/set of kiosks. Will they be brought in for updates or need to have changes applied over-the-air? That will likely impact how you deploy it onto the machine, and in my experience is a harder thing to change later on.
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 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.
I am a newbie to rails. I have used feature flags when i was in java world. I found that there are a few gems in rails (rollout and others) for doing it. But how to turn a feature on/off on the fly in rails.
In java we can use a mbean to turn features on the fly. Any idea or pointers on how to do this? I dont want to do a server restart on my machines once a code is deployed.
Unless you have a way of communicating to all your processes at once, which is non-standard, then you'd need some kind of centralized configuration system. Redis is a really fast key-value store which works well for this, but a database can also do the job if a few milliseconds per page load to figure out which features to enable isn't a big deal.
If you're only deploying on a single server, you could also use a static YAML or JSON configuration file that's read before each request is processed. The overhead of this is almost immeasurable.
OK, NodeJS is all the buzz these days because it handles things in a non-blocking asynchronous way. Because of this, it is very well suited to being a server of some sort, handling requests from multiple clients concurrently. So my question is whether it would make sense, from a technical perspective, to write a general-purpose Rails app AND web server for production use. To be clear, it would take the place of (for example) Apache and Phusion Passenger. Would this setup, in theory, not be faster at handling requests and responding?
You could use Nginx, Lighttpd or Mongrel2 that are event based and probably still keep your Ruby on Rails. To my knowledge, all three of those use event I/O and don't build and tear down threads or forks on each new connection. This way, you can keep your Ruby on Rails. If you need bidirectional communication for any AJAX, then I'd suggest putting in a Node.JS Socket.IO server.
Apache is very inefficient at handling concurrent connections. If you have a high volume traffic scenario then node should do a better job than Apache at handling the connections. However, node itself is much more than just a http server, it is possible to write brand new MVC frameworks not unlike Rails for building web applications. It is perhaps not wise to write a http server in node to replace Apache / Phusion Passenger just yet. Node is young and has not yet released version 1.0.