Process management

Passenger manages multiple processes in order to maximize stability and performance. Learn how Passenger manages processes and learn about Passenger's process management tools.

Table of contents

  1. Loading...

Introduction

You have learned in Fundamental concepts that at its core, Passenger is a process manager. Instead of running an application inside its process space, Passenger launches the application as external processes, and manages them. Passenger load balances traffic between processes, shuts down processes when they're no longer needed or when they misbehave, keeps them running and restarts them when they crash, etc.

If you're not familiar with the concept of processes (and threads), please read About processes first. There are a number of caveats that you should know about, such as the fact that processes don't share memory with each other.

Initially, Passenger only spawns one application process. But sometimes it may decide to spawn multiple processes. Here are the reasons why this is sometimes beneficial:

  • Performance
    The more processes you run, the better the CPU core utilization, up until the hardware limit.
  • I/O concurrency
    The more processes you run, the greater the amount of available I/O concurrency. This makes your app perform better.
  • Stability
    If an application process crashes, other processes are unaffected and can take over while Passenger restarts the crashed process.
  • Keeping problems in check
    Many problems, such as leaking memory or getting stuck, can be kept in check by restarting the process where the problems occurred.

Working with a single process

When you start Passenger Standalone, it spawns one process. You can see this in action as follows. First, start Passenger Standalone:

$ passenger start

Next, open a new terminal and run passenger-status to query the process management status of the Passenger instance:

$ passenger-status
Version : 5.0.6
Date    : 2015-04-14 21:55:30 +0100
Instance: 25002
----------- General information -----------
Max pool size : 6                       1
Processes     : 1
Requests in top-level queue : 0

----------- Application groups -----------
/Users/phusion/testapp#default:         2
  App root: /Users/phusion/testapp
  Requests in queue: 0
  * PID: 25012   Sessions: 0       Processed: 1       Uptime: 9s      3
    CPU: 0%      Memory  : 14M     Last used: 3s ago

There are several things you see here:

  1. Max pool size indicates the maximum number of processes that Passenger will keep around. There is a limit because each process consumes memory, so having too many processes can crash the server. This limit is configurable through the --max-pool-size command line option. Passenger won't ever pass this limit.
  2. Passenger is serving one application, /Users/phusion/testapp.
  3. There is a single process for that application, namely PID 25012. It is not using any CPU right now, and its memory usage is 14 MB.

Notice the dash in passenger-status

The command for querying the process management status is passenger-status with a dash. Do not confuse it with passenger status (without a dash). This latter command is for checking whether a Passenger Standalone instance is running.

Stopping the server

Before continuing with this tutorial, stop the server by pressing Ctrl-C:

$ passenger start
...
(press Ctrl-C here)
Stopping web server... done!

Working with multiple processes

Preparations

Now it is time to get you familiar with running multiple processes. But first, we need to do some preparations. Passenger's multi-process feature is only compatible with packaged Meteor apps, not with regular development-mode Meteor apps. Luckily, we had already prepared a packaged sample app in Preparing a sample app. We will use that now.

Packaged sample app

Enter the packaged sample app's directory:

$ cd ~/leaderboard-packaged/bundle

Create a Passengerfile.json in this directory that tells Passenger how to start this app. Put this text in that file:

{
  "app_type": "node",
  "startup_file": "main.js"
}

MongoDB

When you run a Meteor app in development mode using meteor run, Meteor takes care of running the MongoDB database server for you. But a packaged Meteor app doesn't run MongoDB for you. Instead, it expects that you already have MongoDB running, and that you tell the app where that MongoDB instance is.

Install MongoDB: www.mongodb.org.

Run a MongoDB instance (it will run on port 27017 by default):

$ mkdir -p data log
$ mongod --dbpath data --logpath log/mongod.log --fork

Verify that MongoDB is up:

$ mongo <<<'db.version()'
MongoDB shell version: 2.4.1
connecting to: test
2.4.1
bye

(If you get an error, look in log/mongod.log to learn what went wrong.)

Environment variables

Finally, we need to set some environment variables that tell the app what its parameters are.

$ export MONGO_URL=mongodb://127.0.0.1:27017/passenger
$ export ROOT_URL=http://0.0.0.0:3000/
  • MONGO_URL tells the app where our MongoDB server is.
  • ROOT_URL tells the app what its root URL is.

Seeing multiple processes in action

The easiest way to see Passenger handling multiple processes is by passing --min-instances 2 --sticky-sessions.

  • --min-instances 2 tells Passenger to keep at least 2 processes around. The default value for this option is 1, which is why in the previous step you only saw 1 process.
  • --sticky-sessions tells Passenger to use so "sticky routing", which is necessary to make long polling in Meteor work over multiple processes. The details are a bit boring, but you can read about them if you want to. For now, just remember to always use --sticky-sessions if you have more than 1 process, otherwise bad things will happen.

Run Passenger:

$ passenger start --min-instances 2 --sticky-sessions

Switch to the second terminal again and run passenger-status again:

$ passenger-status
Version : 5.0.6
Date    : 2015-04-14 21:57:30 +0100
Instance: 25002
----------- General information -----------
Max pool size : 6
Processes     : 2
Requests in top-level queue : 0

----------- Application groups -----------
/Users/phusion/leaderboard-packaged/bundle#default:
  App root: /Users/phusion/leaderboard-packaged/bundle
  Requests in queue: 0
  * PID: 25015   Sessions: 0       Processed: 2       Uptime: 9s
    CPU: 0%      Memory  : 14M     Last used: 3s ago
  * PID: 25016   Sessions: 0       Processed: 0       Uptime: 9s
    CPU: 0%      Memory  : 14M     Last used: 3s ago

As you can see, there are now two processes, namely PID 25015 and 25016.

Processes are supervised

The cool thing about Passenger is that it restarts processes that crash! This way you have to worry less about application bugs taking the website down.

Let us try it out by killing the second process, simulating a crash:

$ kill 25016

In our example, the second process's PID is 25016. The PIDs will be different on your machine, so be sure to substitute 25016 with an appropriate value.

Wait 5 seconds, then run passenger-status. Notice that process 25016 is gone and that it has been replaced by 25017!

$ passenger-status
Version : 5.0.6
Date    : 2015-04-14 21:58:30 +0100
Instance: 25002
----------- General information -----------
Max pool size : 6
Processes     : 2
Requests in top-level queue : 0

----------- Application groups -----------
/Users/phusion/leaderboard-package/bundle#default:
  App root: /Users/phusion/leaderboard-package/bundle
  Requests in queue: 0
  * PID: 25015   Sessions: 0       Processed: 2       Uptime: 45s
    CPU: 0%      Memory  : 14M     Last used: 45s ago
  * PID: 25017   Sessions: 0       Processed: 0       Uptime: 9s       This is the newly spawned process
    CPU: 0%      Memory  : 14M     Last used: 3s ago

While a process is being restarted, Passenger will let other processes (if any) process traffic. That way, downtime is minimized in the event of a process crash.

Traffic is load balanced

Passenger load balances traffic over processes in order to improve performance and concurrency. Passenger keeps track of the number of requests that each process is handling. When a new request comes in, Passenger forwards the request to the process that is handling the least number of requests.

Processes are dynamically scaled

Passenger automatically scales the number of processes based on traffic. The more traffic, the more processes Passenger spawns, up to the --max-pool-size limit. This limit defaults to 6. Passenger also shuts down processes that haven't handled traffic for a while, in order to conserve resources. This is especially useful when you're hosting multiple apps on a server with limited resources.

You can see some of this in action by sending a large number of requests to Passenger, for example using the wrk tool. Run this to open 200 connections to Passenger in 16 threads:

$ wrk -t 16 -c 200 http://0.0.0.0:3000/

If you run passenger-status again, you should see many processes:

$ passenger-status
Version : 5.0.6
Date    : 2015-04-14 22:05:30 +0100
Instance: 25002
----------- General information -----------
Max pool size : 6
Processes     : 6
Requests in top-level queue : 0

----------- Application groups -----------
/Users/phusion/leaderboard-package/bundle#default:
  App root: /Users/phusion/leaderboard-package/bundle
  Requests in queue: 0
  * PID: 25015   Sessions: 0       Processed: 84      Uptime: 9s
    CPU: 0%      Memory  : 14M     Last used: 15s ago
  * PID: 25016   Sessions: 0       Processed: 84      Uptime: 9s
    CPU: 0%      Memory  : 14M     Last used: 15s ago
  * PID: 25017   Sessions: 0       Processed: 83      Uptime: 9s
    CPU: 0%      Memory  : 14M     Last used: 15s ago
  * PID: 25018   Sessions: 0       Processed: 83      Uptime: 9s
    CPU: 0%      Memory  : 14M     Last used: 15s ago
  * PID: 25019   Sessions: 0       Processed: 83      Uptime: 9s
    CPU: 0%      Memory  : 14M     Last used: 15s ago
  * PID: 25020   Sessions: 0       Processed: 83      Uptime: 9s
    CPU: 0%      Memory  : 14M     Last used: 15s ago

By default, Passenger shuts down processes that haven't handled traffic for 5 minutes (300 seconds). If you wait 5 minutes and run passenger-status again, you should see that only one process is still alive:

$ sleep 300
$ passenger-status
Version : 5.0.6
Date    : 2015-04-14 22:05:30 +0100
Instance: 25002
----------- General information -----------
Max pool size : 6
Processes     : 6
Requests in top-level queue : 0

----------- Application groups -----------
/Users/phusion/leaderboard-package/bundle#default:
  App root: /Users/phusion/leaderboard-package/bundle
  Requests in queue: 0
  * PID: 25015   Sessions: 0       Processed: 84      Uptime: 6m 23s
    CPU: 0%      Memory  : 14M     Last used: 6m 1s ago

Next step

Congratulations, you have almost reached the conclusion of this basics tutorial. Next, we will teach you how to get help in case you need it.

Continue »