9 ms·
Puma, a fast concurrent web server for Ruby
- itsmeduncan 13y agoWe (ShopKeep) are using Puma for our thin web-services around our platform. Specifically, we send all of our data to a two nodes load-balanced running Puma for our analytics aggregation. It's pretty amazing how a single instance running Puma replaces an entire cluster of Unicorn workers. p.s. We are also hiring Ruby, and iOS folks. Contact information is in my profile.
- gavingmiller 13y agoCan anyone who's used Puma on Heroku comment on how it compares to Unicorn?
- enoptix 13y agoMuch better memory usage and (for us at least) better concurrency. We could only run 4 unicorn workers on a single dyno. But with Puma we run 16 threads with ease.
- cpursley 13y agoThanks, this is all very relevant at the moment. Trying to optimize page load times for a Heroku Rails app. Web server is one of the bottlenecks.
- nixme 13y agoHave you tried running 3 or even 4 puma workers (each with 8-16) threads on a dyno? That way you can get more concurrency on CPU-bound requests in addition to IO-bound concurrency (assuming MRI).
- jrochkind1 13y agoI tried that in my attempt at benchmarking a standardized app on heroku, and, yep, it works great: https://github.com/jrochkind/fake_work_app/blob/master/README.md https://github.com/jrochkind/fake_work_app/blob/master/READM...
- nlh 13y agoI switched from Unicorn to Puma for my relatively low-load Heroku-based Rails app and have seen nothing but improvements across the board. Less memory usage, lower response times, overall better performance. It's working very well. Note: I'm an amateur and I know I'm not nearly optimized across many areas -- the app could be better, I'm not using JRuby (where multi-threaded shines, or so I read), so this is from a pretty novice perspective. But from here, Puma has been great.
- hhenn 13y agoWhat did you use for profiling? Their newrelic add-on?
- cmelbye 13y agoPuma works great on Heroku. Rubinius, on the other hand, doesn't. It was incredibly slow, the app took more than a minute to boot up which caused Heroku to think it crashed. However, you can still use Puma with MRI 1.9.3 or something else and it'll still work great.
- jrochkind1 13y agoI attempted to do some generic benchmarking of just this question and found Puma way outperformed Unicorn under heavy load if your request processing are largely io-bound. Didn't get much attention when I tried to post it to HN when I did it a couple months ago: https://github.com/jrochkind/fake_work_app/blob/master/README.md https://github.com/jrochkind/fake_work_app/blob/master/READM...
- tinco 13y agoYour application is not fair at all. It looks like your sleep mimics I/O boundedness, but in reality it does nothing but set an arbitrary request length. In a real world application I/O requests contend for resources with eachother. Sleep calls don't contend with each other at all. This means that application servers can just keep stacking concurrent requests with perfect performance. If there was actually I/O being done that took 250ms, then you would find that it was the real bottleneck, and it would be the dominant factor in your benchmark, with the differences between app servers all but disappearing.
- FooBarWidget 13y agoThat benchmark is fair if you consider the context: I/O bound workoads. On those kinds of workoads, your app spends a large amount of time waiting for I/O. While waiting, it does not use any CPU. This is very well simulated using sleep calls.
- jrochkind1 13y agoIt is not clear to me that my application fails at realistically simulating I/O (I agree with FooBarWidget below) (and I'm not sure where the word 'fair' comes from or what it means here, that's your word not mine), but I tried to provide as much code and information about exactly what I tested so you could decide for yourself, so fair enough. (I agree that with real I/O, there wouldn't be _exactly_ (eg) 50ms of waiting in every request; it would differ from request to request, and might slow down under heavier load. That's true, but I don't think it matters for what I was trying to test -- I was not trying to test how well a given rdbms can handle load, for instance; I was trying to standardize that, to test the app's performance. My simulation assumes an (eg) 50ms _average_ iowait time, by just assigning every request 50ms of wait. Or instead of 50ms, whatever average iowait you wanted to posit and test, and I tested a few. It is indeed a simulation, but I think it captures the significant things for what we wanted to measure). However! I would very much welcome seeing the results from a test done by you (or anyone else), with an application that simulates (or actually does) I/O in a way that you believe is more realistic and leads to more instructive results. It certainly would be interesting to see if it led to different results than my tests, or not. I suspect it would not (because I think my app is realistically simulating the parts that matter, naturally! but I've been wrong before!) Feel free to fork my code to do so, if my code is a useful starting point for you. Please do share your results! Of course, you could also run tests with some actual real world app as well, instead of an app simulating a real world load in a standardized way like I used, and see what those results look like. I'd certainly welcome seeing that too! There's certainly plenty of different sorts of tests that could be done. I'd love it if people started doing some of them and sharing their results. I tried to contribute my best effort to that.
- justkez 13y agoI've been enjoying using Puma in clustered mode for some production sites, but falling back to Thin for Server Sent Events (new EventSource()) - does anyone know if this is ever likely to come to Puma, or is there a fundamental reason that the Puma process model can't support SSE?
- andrewhavens 13y agoSounds more like a problem with your implementation. I'm pretty sure Puma can handle SSE just fine. Your implementation probably depends on EventMachine which is not baked in like it is with Thin.
- justkez 13y agoI'm doing: content_type "text/event-stream" stream(:keep_open) { |out| settings.connections << out } From Sinatra, which I assume is then deferring to EventMachine, courtesy of Thin. I'll see if there's a way of forcing EM directly in to the Stream setup...thanks for the pointer.
- FooBarWidget 13y agoI'm one of the authors behind Phusion Passenger (https://www.phusionpassenger.com/ https://www.phusionpassenger.com/), a polyglot web server for Ruby, Python and Node.js. We recently wrote a demo demonstrating SSE on Phusion Passenger (https://github.com/phusion/passenger-ruby-server-side-events-demo https://github.com/phusion/passenger-ruby-server-side-events...). During writing of this demo, we found out that sinatra-contrib's streaming code relies on EventMachine. That means that sinatra-contrib's streaming only works on EventMachine-based servers, like Thin and on Goliath. Based on my knowledge about Puma, I'm pretty sure SSE works fine on Puma as well. The Phusion Passenger SSE demo uses the Rack socket hijacking API (which we've blogged about: http://blog.phusion.nl/2013/01/23/the-new-rack-socket-hijacking-api/ http://blog.phusion.nl/2013/01/23/the-new-rack-socket-hijack...) to implement SSE. This approach should work on Puma as well because it supports the Rack socket hijacking API too.
- sad 13y ago
- j4mie 13y agoI'm not a Rubyist, but if I'm reading the section of the README that describes the design [1] correctly, the closest Python equivalent (architecturally speaking) is Waitress [2]. [1] https://github.com/puma/puma#built-for-speed--concurrency https://github.com/puma/puma#built-for-speed--concurrency [2] http://docs.pylonsproject.org/projects/waitress/en/latest/design.html http://docs.pylonsproject.org/projects/waitress/en/latest/de...
- purephase 13y agoI've been using Puma in dev/QA and it's impressive. I'm planning on trying it out in production but have a lot invested in Unicorn at the moment. For example, I have monit confs that kill workers once they reach a certain memory threshold and I'll have to figure out how to do that with Puma.
- sleepyhead 13y agoAnyone used Puma on Heroku? Is it as simple as [1] or is there more configuration required [2] as is the case with Unicorn [3]? [1] http://blog.steveklabnik.com/posts/2013-02-24-using-puma-on-heroku http://blog.steveklabnik.com/posts/2013-02-24-using-puma-on-... [2] http://www.subelsky.com/2012/10/setting-up-puma-rails-on-heroku.html http://www.subelsky.com/2012/10/setting-up-puma-rails-on-her... [3] https://devcenter.heroku.com/articles/rails-unicorn https://devcenter.heroku.com/articles/rails-unicorn
- vicentereig 13y agoI'm actually using it in a small side-project I implemented a couple of weeks ago. (http://playas.io http://playas.io) It uses Rails 4 [0], JRuby 1.7.4, postgresql with full text search, one dyno and 10 workers. It is not the first time I'm using JRuby and Puma, I must say I'm pretty happy with it. I had enough with the official documentation, just tweaking the DB pool to fit in the Rediscloud free version constraints. [1] https://devcenter.heroku.com/articles/concurrency-and-database-connections https://devcenter.heroku.com/articles/concurrency-and-databa... [0]: You'll need to download JCE 6 Extensions to get Puma, JRuby 1.7.4 and Rails 4 running in development: http://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html http://www.oracle.com/technetwork/java/javase/downloads/jce-... [1]: Rediscloud free version gives you 10 connections.
- facorreia 13y agoLooks good. It would be nice to see it on the Web Framework Benchmarks (https://github.com/TechEmpower/FrameworkBenchmarks https://github.com/TechEmpower/FrameworkBenchmarks). Edit: someone created an issue asking for contributors: https://github.com/TechEmpower/FrameworkBenchmarks/issues/459 https://github.com/TechEmpower/FrameworkBenchmarks/issues/45...
- allr 13y agoLess memory usage then Unicorn here, though we recently moved to Passenger enterprise which is really similar: https://www.phusionpassenger.com/enterprise https://www.phusionpassenger.com/enterprise good writeup on the subject here: https://github.com/phusion/passenger/wiki/Puma-vs-Phusion-Passenger https://github.com/phusion/passenger/wiki/Puma-vs-Phusion-Pa...
- amarraja 13y agoCan someone with more webserver knowledge please explain how puma works from a high level? I know very little about web servers so the following may not even make sense! I have looked at the source, and it appears a thread pool will listen to incoming requests, and pass them to a reactor then move on to handle more requests. Another thread polls the sockets and writes the data to the response stream when ready. [Note: this all may be completely wrong!] If the way the server works as above is correct, does it mean it's possible to achieve event-loop-based levels of concurrent connections along with good old CPU concurrency as well?
- FooBarWidget 13y agoI'm one of the authors behind Phusion Passenger (https://www.phusionpassenger.com/ https://www.phusionpassenger.com/), a polyglot web server for Ruby, Python and Node.js. What you said is basically correct. And yes, it is possible to combine event loops with threads in the way you described to get CPU concurrency as well. Whether it is actually helpful depends on the use case. The Phusion Passenger core is evented (similar to Nginx and Node.js) since version 4.0. We considered a multithreaded-evented architecture as well, but it turned out to be less beneficial than we hoped because the applications themselves use plenty of CPU already, and because we rely on shared in-memory state for proper load balancing between processes, thus having a source of contention. In the end, the single-threaded evented architecture in Phusion Passenger turned out to be more than enough.
- cmbaus 13y agoHow does Passenger deal with blocking I/O from applications if it is single threaded? Does the entire event loop block while doing I/O?
- trustfundbaby 13y agoPassenger spawns copies of your application and (I think this is the default now, it wasn't before) puts your requests in a queue, so that as the app instances finish processing requests they snatch a new request off the queue. If they are all busy then the requests back up on the queue until one of them becomes available.
- JiPi 13y agoOut of curiosity, why today? I mean, this is not new at all, there is no major version that was released AFAIK... This is great to share that though, just curious why it's on HN today? :) Edit: typo fix.
- waylonrobert 13y agoAgreed. I also recall seeing it on HN before, and not that long ago.
- bretpiatt 13y agoYou may have seen a recent comment, looks like the main page was posted a year ago -- I relied on the URL duplicate checker when submitting it (it was new to me today to come across and I wanted to see thoughts from the HN community on it). I ran a the search and found the previous: A modern, concurrent web server for ruby (puma.io) 16 points by kachhalimbu 1 year ago | 2 comments | cached
- JiPi 13y agoFair enough. Just thought I might have missed something new and big! :)
- JiPi 13y agoJust keep in mind your code (and gem's code) needs to be thread safe.
- mrinterweb 13y agoI like puma, but I thought it was interesting that the left passenger out of their performance graphs. Seems odd to omit the most popular ruby application server from the results.
- JiPi 13y agoIs passenger the most popular? Is there any reliable statistics available somewhere?
- mrinterweb 13y agohttp://blog.planetargon.com/entries/2012/8/14/rails-hosting-survey-2012-results-are-in http://blog.planetargon.com/entries/2012/8/14/rails-hosting-...
- chc 13y agoAll of the servers listed here are standalone servers, while Passenger is a module for existing servers. I don't really see why you couldn't include Passenger here, but it seems like they're only comparing like to like, which I guess is fair.
- tinco 13y agoYou can use Passenger as a standalone server too, it's called Passenger Standalone. You can install it with 'gem install passenger', and run it by running 'passenger start'.
- chc 13y agoOh, so you can. I actually went and checked the Passenger site to see if my information was current since I mainly use Puma these days, but I didn't scroll down far enough to see the standalone version. But installing it as a module still seems to be the recommended method, so I can see still see why it isn't included in a list of servers that are meant to be proxied to.
- gmac 13y ago
- Bharath1234 13y agoWell. I have just come across this one which says Unicorn to be the best performing one. Apparently, Puma proves wrong even with multiple workers. https://gist.github.com/pbyrne/5218411 https://gist.github.com/pbyrne/5218411
- Bjoern 13y agoInteresting goes against directly what they claim on their own page. Its tested on a four core machine. I'm suspecting the 16 default threads were the problem, since Unicorn only ran with 4 processes not 16. http://puma.io/ http://puma.io/
- deleted 13y ago[deleted]
- dsrw 13y ago1 puma worker vs 4 unicorn workers isn't a fair test on a multi core machine under MRI.
- chucknelson 13y agoAny reason why thin is not in the comparison? Is it not very fast compared to the others in the chart?
- FooBarWidget 13y agoI'm one of the authors behind Phusion Passenger (https://www.phusionpassenger.com/ https://www.phusionpassenger.com/), a polyglot web server for Ruby, Python and Node.js. We've recently written a comprehensive comparison between Puma and Phusion Passenger, which you can read here: https://github.com/phusion/passenger/wiki/Puma-vs-Phusion-Passenger https://github.com/phusion/passenger/wiki/Puma-vs-Phusion-Pa... The comparison covers things like concurrency models, I/O models, security, clustering, multi-app support, documentation, memory usage, performance and more. Although the comparison is between Puma and Phusion Passenger, a lot of the points are relevant to a Unicorn-Puma comparison as well.
- nwienert 13y agoYou've done a great job posting Passenger links all over this thread. I find it in poor taste come into a semi-related post and repeatedly spam links to your product over and over...
- speleding 13y agoMy first thought upon reading the article was: "I wonder how this compares to Passenger?". I find it very helpful to get an authoritative link from the Passenger guys themselves in this thread. Since Passenger is by now pretty much the default way to run a Ruby stack I don't think any one here doesn't know who they are and so they really do not need to spam. They are just contributing to the discussion and I appreciate that.
- Legion 13y agoOne linking post is fine. Three comments full of Passenger links is pushing good taste.
- _neil 13y agoIs Passenger really the default for most people? I tried it once and honestly prefer just dropping thin or unicorn behind nginx. And with this discussion, I'll probably be trying out puma in the near future.
- FatalBaboon 13y agoI'm running Puma on my RaspberryPi for a pet Rails app and it's incredibly fast. Would recommend.
- perssontm 13y agoIs it just me beeing blind, or does it not support https?
- trustfundbaby 13y agoI'm pretty sure it supports https
- FooBarWidget 13y agoIt supports https through Nginx. HTTPS terminates at Nginx.
- WayneDB 13y agoPuma is not for me, but Ragel seems very interesting.