Phusion Passenger on Nginx – Internal Overview

So, working with nginx and passenger has been really simplified. There is an excellent screen cast about how exactly how to get it working. ( What I was really interested in finding out was, what happens under covers.

It turns out that this is the core of what passenger does is irrespective of whether its running via Apache or Nginx. This was interesting as, I believe this is one step we take for granted!

When passenger_enabled is ‘on’, the Rails (railz in Passenger terminology) or the Rack, the processes are not exec’ed but forked! This is HUGE – unlike mongrel or thin. Processes have a different process id but they are child processes – ie. They share all the parents file descriptors. NOW, since we can fork on demand, it makes a huge difference when we are trying to balance the load on servers and reap them on lower load.

There are different types of ways the server is spawned:

  • conservative

  • smart

  • smart lv2 (default)

The conservative method of spawning is the same as what happens with mongrel and thin – the processes are independent. Not recommended at all as this kills the performance.

Smart and smart lv2 are the pre-cached spawners. In the smart way, the framework is spawned and all applications of this framework are spawned. Slightly heavy considering that we do not deploy like this usually.

Smart lv2 is the best of the lot and does a cached application loading – this reduces the load time when the application is requested even for the first time. This is the one we shall dissect.

Questions which arose:

  1. Where is the ruby process?

  2. How much memory does it take?

  3. What is the load time?

If its a smart spawn, I would assume that since one process is forked for every framework application, there should be only one ruby process for rails and one for rack. Need to really investigate this 😉

If its a smart-lv2 spawner, I assumed that there should be at least one ruby process for every application we spawn – however, this is not the case somehow. At all times, I see only one ruby process – how? I created 2 applications and tried to start them from a single nginx server – still only one ruby process – that too consuming 6MB in resident memory. What’s going on here??

Now, I created 2 basic scaffolds, one for each application and invoked the routines – voila, here is my answer! I see 4 ruby processes of 21MB each for 2 applications. So, this explains it – its not rocket science.

Initially, since there are no HTTP requests processed – just the basic application and welcome to rails page, only a single application got spawned. Hence it was only 6MB. When there are some HTTP rails requests, the rails apps were spawned. To verify this:

  • I killed the nginx process and the ruby child processes disappeared – expected.

  • I restarted nginx and invoked form browser. Only the welcome page – no ruby process spawned

  • I invoked a rails request on 1 of the apps – 2 ruby processes (21mb) spawned.

  • I invoked a rails request on the second apps – 2 more ruby processes surfaced. Passenger-status shows 2 domains and 1 PID (probably implies 1 process and 1 child worker thread?)

Now, the question remains – when are the processes reaped – is there always 2 instances of the app in memory – which is still huge as each consumes 21mb! Now, I was trying find out if and when the instances get reaped – Still doing some investigation on this.

More later!

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.