Live data from Hacker News

Puma, a fast concurrent web server for Ruby

puma.io

41–50 of 86 posts

Re: Puma, a fast concurrent web server for Ruby

#41
post #40

Earlier quoted context omitted.

I 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/READM...

Your 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…

That 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.

Re: Puma, a fast concurrent web server for Ruby

#42
post #36

I 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.

All 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.

You 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'.

Re: Puma, a fast concurrent web server for Ruby

#43
post #42
post #36

Earlier quoted context omitted.

All 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.

You 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'.

Oh, 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.

Re: Puma, a fast concurrent web server for Ruby

#44
post #42
post #36

Earlier quoted context omitted.

All 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.

You 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'.

(In which case it installs and fires up a copy of nginx behind the scenes).

Re: Puma, a fast concurrent web server for Ruby

#45

Can 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…

I'm one of the authors behind Phusion Passenger ( 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) sin…

How does Passenger deal with blocking I/O from applications if it is single threaded? Does the entire event loop block while doing I/O?

Re: Puma, a fast concurrent web server for Ruby

#46

I'm one of the authors behind Phusion Passenger ( 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-Pa... The comparison covers things like concurrency models, I/O models, security, clustering, multi-app support,…

You'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...

Re: Puma, a fast concurrent web server for Ruby

#47
post #37

Can 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…

I'm looking at the 'Puma' section in Jesse Storimer's book "Working With TCP Sockets" and that seems to be the general idea behind it... uses a thread pool for concurrency, monitors persistent connections with an evented reactor. I'm not affiliated with the author, but this was such a nice book to get an intro to webservers and their architectures/tradeoffs from. Really fueled my love of sockets :)

Thanks for reminding me about Jesse's book(s), I knew there was something I was meant to do!

Re: Puma, a fast concurrent web server for Ruby

#49

Can 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…

I'm one of the authors behind Phusion Passenger ( 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) sin…

Thanks for the update. I'm likely going to try and deconstruct and rebuild some of it to really get my head around evented architectures -- will try and blog it. Years of threads had me in bliss until this non-blocking renaissance came along :)

Re: Puma, a fast concurrent web server for Ruby

#50
post #40

Earlier quoted context omitted.

I 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/READM...

Your 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…

It 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.

Post reply on HN