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!
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?
Would it make a difference versus the single core into terms of performance in Ruby on rails app
and if i have multi-core how i manage rails through multi-core
if multi-core processor same idea of distributed servers
Basically, you specify that your rails app run "8 processes" at once and each will use one core. The way I do it is by using phusion passenger [in my case, with nginx] and you may get it to work like
passenger_max_pool_size 8
passenger_max_instances_per_app 8
If you want to make sure your cores are all busy [and have enough RAM] then possibly set them to size 16'ish
Multicore servers only boost performance if the rails app is running in multithreaded mode of in multiprocess mode. Ruby currently supports 'green' threads, which are lightweight and not true processor threads. Rails has support for multithreading, but gem support could be lacking and would probably be unstable for production. To make the best use of a multicore server, running a web server like unicorn or passenger, which can spawn rails processes per core, would provide you the best performance boost
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.
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.
I've been using Ruby Enterprise Edition and Passenger (for Apache, since I run Apache anyway for other things) for some time, but I'm wondering if there's a new trend about what to use on servers nowadays.
For example I've heard about Thin, Unicorn... I also know that 1.9.2 is faster than REE, but I wonder about RAM consumption. I'd rather have it consume less RAM even at the expense of some speed.
Thanks for all advice.
If you want minimal memory you should try Thin.
It does not have master worker as Unicorn or Passenger, thus uses less memory.
Suppose you have a very small app that needs to run on a small VM, then you can use 1 thin worker + nginx. I ran several rails 3.2 apps using Thin+nginx+postgres on 256MB VMs without swapping.
Unicorn is faster but it needs a master worker. It's good if you want to run on Heroku, you can set it 2 or 3 workers and be within the 512MB limit.
If your app is very big and you have too many long running requests, I would check out jRuby and Thinidad/Torquebox.
I converted a few apps from MRI+Sidekiq to jruby+Trinidad+Trinidad_Scheduler. I get about 100-200 req/sec using a pool of 50 threads in a trinidad server!
What I like about jRuby is that you can combine everything on one Rails Server. You can put together on the same JavaVM the cache_store with EHcache, Scheduling, Background processing and real multithreading.
You don't need to run redis, memcached, resque or sidekiq separately.
Im not saying they are not good, I love sidekiq and resque, but you can decrease your complexity by combining everything on one process and have high concurrency.
A more advanced and Enterprise solution is Torquebox, it has support for clustering and is super scalable. But I've had problems with my app crashing on torquebox, so i'm sticking to Trinidad for now.
The disadvantages of jRuby? MEmory! A Trinidad server will use minimum 512MB, up to 2-3GB ram.
Also, for Single Thread server, a single request from a rails app running Ruby-1.9.3 is about twice as fast as the same request on jRuby.
Another option is Puma, you can get full multithreading on MRI with puma. I myself could not get it stable enough on my apps.
So, it all depends on your requirements, memory usage, full threading and concurrency.
Apart from Passenger, have a look at Unicorn, Trinidad, Puma and Torquebox. Those seems to be the top rails servers right now.
There is an great book with an introduction of converting your Rails app to jRuby and deploy your app using several methods such as trinidad.
http://pragprog.com/book/jkdepj/deploying-with-jruby
The Torquebox Documentation is amazingly good. It's very detailed and explains really good how to use all Torquebox features.
http://torquebox.org/documentation/
I Hope that sharing my experience has helped.
Passenger is still extremely strong, especially being REE will naturally support 1.9 in the near future. The fact that your application can crash, however it won't affect anything else on your machine is an amazing feature to have. Deploying code is extremely easy because the server will continue to accept connections, which means less frustration/stress for you.
However, in terms of comparisons:
Here is a great resource is check out various comparisons(including memory consumption) with all the new servers.
It compares Thin, Unicorn, Passenger, TorqueBox, Glassfish, and Trinidad:
http://torquebox.org/news/2011/03/14/benchmarking-torquebox-round2/
Mike Lewis' link does a good job of comparing those different ruby servers. My personal experience has been with nginx/REE/Passenger and its been good. I haven't tried the others, so I can't comment on that.
However, I can speak on RAM usage. Your biggest savings of RAM will come from using 32-bit servers. In my experience (3x 3GB app servers), 64-bit REE/passenger processes took up to 2x as much RAM as their 32-bit counterparts. We saw a significant performance increase moving from 64 to 32 bit servers, everything else staying the same. Unless your application requires 64-bit, I would suggest running your application servers (not database) in 32-bit.
Passenger is still a very good choice to use so you are not behind the times or anything. It is also actively supported and has a very good development team that contributes a lot to the community. We have been using Unicorn and it has been very good. Our favorite functionality is to be able to upgrade apps/ruby/nginx without dropping a connection.