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
- 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.
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:
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.- Passenger is serving one application, /Users/phusion/testapp.
- 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 two processes are 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 * PID: 25016 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.