Scalability
This document is a work-in-progress.
To scale Colyseus into multiple processes or servers, you'll need to have Redis, MongoDB, and a dynamic proxy.
Redis¶
Download and install Redis. Use the RedisPresence
:
import { Server, RedisPresence } from "colyseus";
const gameServer = new Server({
// ...
presence: new RedisPresence(),
});
const colyseus = require("colyseus");
const gameServer = new colyseus.Server({
// ...
presence: new colyseus.RedisPresence(),
});
The presence
is used to call room "seat reservation" functions from one process to another, and allows the developer to take advantage of the some data sharing functions across rooms. See Presence API.
Each Colyseus process also registers its own processId
and network location to the presence
API, which is later used by the dynamic proxy service. During graceful shutdown, the process unregisters itself.
MongoDB¶
Download and install MongoDB. And install the mongoose
package:
npm install --save mongoose
Use the MongooseDriver
:
import { Server, RedisPresence } from "colyseus";
import { MongooseDriver } from "colyseus/lib/matchmaker/drivers/MongooseDriver"
const gameServer = new Server({
// ...
driver: new MongooseDriver(),
});
const colyseus = require("colyseus");
const MongooseDriver = require("colyseus/lib/matchmaker/drivers/MongooseDriver").MongooseDriver;
const gameServer = new colyseus.Server({
// ...
driver: new MongooseDriver(),
});
You can either pass the MongoDB connection URI to the new MongooseDriver(uri)
constructor, or set a MONGO_URI
environment variable.
The driver
is used to store and query available rooms for matchmaking.
Running 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. The Colyseus processes should NOT be exposed publicly. Only the dynamic proxy is.
The PM2 process manager is highly recommended for managing multiple Node.js app instances.
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);
npm install -g pm2
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 start
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).
Dynamic proxy¶
The @colyseus/proxy is a dynamic proxy that automatically listens whenever a Colyseus process goes up and down, allowing the WebSocket connections to go to the right process and server where a room has been created on.
The proxy should be bound to port 80
/443
as it is the only public endpoint you'll have for your application. All requests must go through the proxy.
npm install -g @colyseus/proxy
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¶
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}