Why to use PUMA in production for your Rails App
Tags: puma, rails, server, production
Published: 2020-08-07 10:05:28

If you are still using Unicorn, Thin or Passenger open source application server in production then this post is for you.

> Point to note that Passenger Enterprise is different from Passenger open source, this post only talks about Passenger open source.

This [Blog Post](https://scoutapm.com/blog/which-ruby-app-server-is-right-for-you) has very good comparison about features provided by Unicorn, Puma & Passenger

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/n4olor4zkzcwilzrn47w.png)

> Point to note in this comparison is that PUMA is multithreaded and Passenger is multithreaded in only Enterprise edition



If you believe that multithreaded server is of no use because Ruby has GIL then you should read below snippet from [Heroku Blog](https://devcenter.heroku.com/articles/deploying-rails-applications-with-the-puma-web-server
)

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/1lntvgaa16j0l7vdxrlb.png)

Therefore Heroku [recommends](https://devcenter.heroku.com/articles/ruby-default-web-server) to use Puma in production 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/kkiikzgm5lyeg639eo3p.png)


Infact, [dev.to](https://dev.to/) (this blogging platform) is hosted on Heroku and uses Puma in production

Puma is already battle tested by Heroku, Recently Gitlab also migrated to Puma from Unicorn 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/cfver2kzioj1sqol1mzy.png)

Read about Gitlab migration journey [here](https://about.gitlab.com/blog/2020/07/08/migrating-to-puma-on-gitlab/)

> Puma really outshine other options when your application is dependent on lots of I/O operations.

### I did some benchmark to compare Passenger open source & Puma performance

#### Configuration used during benchmarking

**Passenger gem:**
- Version: 6.0.5
- Workers count: 6 (Default)

**Puma gem:**
- Version: 4.3.5
- Workers count: 4
- Threads count: 5
*5 threads per worker

**Machine:** 
macOS Catalina, Dual-Core Intel Core i5, 8GB RAM

#### Benchmarking tool and configuration

**Tool used:** https://github.com/wg/wrk
**Configuration:**
- Threads: 2
- Connections: 100
- Duration: 30 sec

#### When I/O operations are minimal

[homes.json API](https://github.com/anilmaurya/benchmark_demo_api/blob/master/app/controllers/homes_controller.rb#L5-L9) perform one DB query and return back json data

**Passenger benchmark:**

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/8fa446kosept4p241d21.png)

> 536 requests per second

**Puma benchmark:**

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/y8f9yp1eepojgrjsl40n.png)

> 883 requests per second

**Take away**
`64% increase in number of requests served per second`
`Puma can serve 10,000 more requests in 30 seconds`

#### When I/O operation increases

[homes/1.json API](https://github.com/anilmaurya/benchmark_demo_api/blob/master/app/controllers/homes_controller.rb#L12-L5) performs 2 operations,  one DB query and one network call and then return back json data
Network call is `HTTP.get('https://facebook.com')`

**Passenger benchmark:**

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/rvn03cdcx6kfi15ylqlr.png)

> 9 requests per second

**Puma benchmark:**

 ![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/x456p5ur19ju0asbwxmn.png)

> 29 requests per second

**Take away**
`Puma is 3x faster`
`Puma can serve 600 more requests in 30 seconds`

### How to set correct thread and worker count for Puma

Every Application is different therefore there is no universal Puma config which everyone can use.
You will have to try different combination of threads and workers count to find out which one is good for your application.
I created one gem https://github.com/anilmaurya/puma-benchmark which can help you in finding correct thread and worker count for your application.

### Ref
1. https://deliveroo.engineering/2016/12/21/unicorn-vs-puma-rails-server-benchmarks.html
2. https://www.toptal.com/ruby/ruby-concurrency-and-parallelism-a-practical-primer