Does Ruby on Rails handle concurrent requests?
If not, how to make it so?
It's less that Ruby on Rails handles the concurrent requests as it is the server that is running Ruby on Rails that handles the concurrent requests. When I say a server that is running Ruby on Rails I am referring to Phusion Passenger, Mongrel or WEBrick in combination with Apache or Nginx for example. In most cases concurrency is achieved by launching multiple Ruby on Rails applications that each handle requests separately. While this may take more memory than a truly threaded approach it does not require that Ruby on Rails developers write thread-safe code.
You need to run a threaded server like Puma on a threaded Ruby like JRuby for that. Otherwise it's just the server creating processes instead of threads, like Pushion Passenger. Of course, you need to write thread safe code for that, which can be very hard to develop and mantain. For this reason most of the people sticks to single threaded solutions, althought Rails 4 is multithread by default and so we might see a trend change in the near future.
Related
I have read multiple documents and blogs and understood the below points
Ruby is not multithreading since it has the Global Interpreter lock since its interpreter MRI were implemented in C
Unicorn server provides multi worker facility but not multi-threading which is understandable, and Puma is multithreading and can work with JRuby happily with multithreading facility since JRuby have Java's power so JRuby have multithreading power so it can also be understandable
But if Ruby have GIL and can run only one thread at a time (as Martz's moto was to make a language more human-readable friendly, and to avoid deadlock or race condition), then how comes everywhere it mentioned that with Puma as a Rack-based Web server it runs Rails app with Multithreading power, when its crystal clear that Ruby is a Single threaded language?
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]
I recently switched to using Phusion Passenger 4.0.50 in replacement for Unicorn.
The reason is because Passenger integrates well with Nginx and can also power Node.js app. However, what I am wondering is if I should do anything about the external connections (with Postgresql, Redis, Memcached) like I did with Unicorn.
I found some code on the Passenger git such as this one. But this code seems to belong to Passenger rather than a Rails app.
As of now I am using Ruby 2.1.2, and Rails 4.1.6. Would such work to handle external connections still required? If it is, how should I do it?
Thanks.
Update:
Per this thread, it seems that normal ActiveRecord is taken cared of automatically by Passenger.
Phusion Passenger author here. Yes you must do something about external connections. The "smart spawning" concept in Phusion Passenger is exactly the same as the "preload_app on" concept in Unicorn. We have an entire section in the documentation explaining how it works and what the caveats are (specifically, about external connections): https://www.phusionpassenger.com/documentation/Users%20guide%20Nginx.html#spawning_methods_explained
The only exception is the Rails default ActiveRecord connection. We automatically reestablish that, because it counts for over 90% of the use cases.
Passenger starts multiple sepearate worker processes, each of them loading the rails application. So each webrequest is handled by a completely isolated process within one thread. This means you don't have to care about connection pools at all. For example, in case of ActiveRecord, there are 5 concurrent connections possible by default (can be adjusted) and in your case you allways have only one connection (per process)
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 new to Ruby on Rails and beginning a project soon. Having read about different Ruby implementations, I am wondering which setup to use. My project is expected to have a fair amount of traffic.
I am considering two optiosn: MRI Ruby (v 2.0) and JRuby (v 1.9). I am concerned that MRI Ruby is not multithreaded and am worried about the impact this will have on the web app. Perhaps the application server can eliminate this problem? Right now it looks like we will be using Puma as the application server.
In short, should I use JRuby because it is multithreaded on 1.9 or should I use MRI Ruby on 2.0?
TL;DR
Using either Puma or Passenger negates this issue because they handle threads on their own. I would recommend working with the newest version of Ruby and Rails possible as this will minimize the upgrade work you need to do when upgrading your app.
Here is a wonderful article which addresses your issue.
To summarize.
Puma is multithreaded-only. The open source variant of Phusion
Passenger is multi-process single-threaded. The Enterprise variant can
be configured to be either single-threaded or multithreaded.
...
Both Puma and Phusion Passenger Enterprise can be hybrid multi-process
multi-threaded. That is, running multiple multithreaded processes.
Hybrid mode allows Ruby and Python, which despite having a Global
Interpreter Lock, to fully utilize all CPU cores.[1] In Puma, the
hybrid mode is called "clustered".
[1] Only the case on MRI, not on JRuby and Rubinius. JRuby and Rubinius fully support multi-core threads in a single process.
In other words, both Puma and Passenger are able to treat any Ruby implementation as multi threaded. They do this by using a hybrid between multiple processes and multiple threads. This is only minimally heavier than simple multi-threading.
To be honest, I don't think this is an issue you need to worry about at this time. Wait to see how your server handles the site's traffic.
Honestly, if you are new to Ruby and Rails, just stick with the defaults - MRI in this case. Ruby enjoy several great implementations (MRI, JRuby, Rubinius, ...) that will run your web application without any problem. Starts with MRI, you can always decide to change later if needed.
You will be in a much better position to judge what is the best Ruby implementation and server when the work on your application will have started - more proficient on the plateform, and more aware of your specific challenges (not every application is that dependent on multi threading performance).
Enjoy the road!