Scalability
Colyseus Cloud
If you find configuring this overwhelming, consider using Colyseus Cloud to easily deploy and host your Colyseus servers.
How does Colyseus achieve scalability?¶
- Increasing the number of processes will increase the amount of rooms that can be created.
- Rooms are equally distributed across the available processes.
- Each Room belongs to a single Colyseus process.
- Each process has a maximum amount of players it could handle. (The exact amount depends on many factors. See our FAQ.)
- Client connections are directly associated with the process that created the room.
There are two strategies available for scaling:¶
- Recommended: Making every Node.js process accessible to the internet via a public URL. This way clients can connect directly to the process that created the room.
- Previous recommendation (not a recommendation since 0.15): Use
@colyseus/proxy
behind every Node.js process that redirects client traffic to the correct process.
Redis is required
Redis is required for both strategies. Make sure to have it running on your server.
Step 1: Use a shared Presence
and Driver
¶
The presence
is used to call room "seat reservation" functions from one process to another. See Presence API.
The driver
is responsible for keeping a shared cache of available rooms, and room querying by any of the active Colyseus processes.
Step 2: Making your Colyseus processes accessible to the internet¶
Recommendation: Using a Load Balancer¶
Since version 0.15, you can configure each Colyseus process to use its very own public address, so clients can connect directly to it.
const server = new Server({
// ...
presence: new RedisPresence(),
driver: new RedisDriver(),
// use a unique public address for each process
publicAddress: "server-1.yourdomain.com"
});
You can have a regular load balancer sitting behind all the Colyseus processes. The load balancer must be the initial entrypoint for all connections.
Previous recommendation: Using a Dynamic Proxy¶
Proxy is not a recommendation on version 0.15
Please check the load balancer recommendation above.
Install the @colyseus/proxy.
The Dynamic Proxy automatically listens whenever a Colyseus process goes up and down. It is responsible for routing the client requests to the correct Colyseus process.
All client requests must use the proxy as endpoint. Using this solution, clients do not communicate directly with the server, but through the proxy.
The proxy should be bound to port 80
/ 443
on a production environment.
Environment variables
Configure the following environment variables to meet your needs:
PORT
is the port the proxy will be running on.REDIS_URL
is the path to the same Redis instance you're using on Colyseus' processes.
Running the proxy
npx colyseus-proxy
> {"name":"redbird","hostname":"Endels-MacBook-Air.local","pid":33390,"level":30,"msg":"Started a Redbird reverse proxy server on port 80","time":"2019-08-20T15:26:19.605Z","v":0}
Step 3: Spawning multiple Colyseus processes¶
To run multiple Colyseus instances in the same server, you need each one of them to listen on a different port number. It's recommended to use ports 3001
, 3002
, 3003
, and so on.
- If you're using a load balancer (recommendation), each Colyseus process MUST have its own public address.
- If you're using
@colyseus/proxy
(not recommended), the Colyseus processes should NOT be exposed publicly. But only internally for the proxy.
The PM2 process manager is recommended for managing multiple Node.js app instances, although not mandatory.
PM2 provides a NODE_APP_INSTANCE
environment variable, containing a different number for each process. Use it to define your port number.
import { Server } from "colyseus";
// binds each instance of the server on a different port.
const PORT = Number(process.env.PORT) + Number(process.env.NODE_APP_INSTANCE);
const gameServer = new Server({ /* ... */ })
gameServer.listen(PORT);
console.log("Listening on", PORT);
Use the following ecosystem.config.js
configuration:
// ecosystem.config.js
const os = require('os');
module.exports = {
apps: [{
port : 3000,
name : "colyseus",
script : "lib/index.js", // your entrypoint file
watch : true, // optional
instances : os.cpus().length,
exec_mode : 'fork', // IMPORTANT: do not use cluster mode.
env: {
DEBUG: "colyseus:errors",
NODE_ENV: "production",
}
}]
}
Now you're ready to start multiple Colyseus proceses.
PM2 and TypeScript
It's recommended compile your .ts files before running pm2 start
, via npx tsc
. Alternatively, you can install the TypeScript interpreter for PM2 (pm2 install typescript
) and set the exec_interpreter: "ts-node"
(read more).