ColyseusJS 轻量级多人游戏服务器开发框架 - 中文手册(系统保障篇)

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 MongoDB,独享型 2核8GB
推荐场景:
构建全方位客户视图
简介: ColyseusJS 轻量级多人游戏服务器开发框架 - 中文手册(系统保障篇)

监控面板 (@colyseus/monitor)



@colyseus/monitor 是一个方便的工具,允许您查看和检查服务器生成的当前房间列表。

特性


  • 列出所有活动房间
  • 强制安排一个特定的房间
  • 检查一个特定的房间
  • 查看房间的状态
  • 为客户端发送/广播消息
  • 强制断开客户端连接


微信图片_20220611162744.gif

安装


安装模块:


npm install --save @colyseus/monitor


将它包含在你的项目中:


// ...
import { monitor } from "@colyseus/monitor";
// ...
app.use("/colyseus", monitor());


使用密码限制访问面板


您可以使用 express 中间件在 monitor 路由上启用身份验证,例如 express-basic-middleware


npm install --save express-basic-auth


使用 express-basic-auth 创建用户和密码。


import basicAuth from "express-basic-auth";
const basicAuthMiddleware = basicAuth({
    // list of users and passwords
    users: {
        "admin": "admin",
    },
    // sends WWW-Authenticate header, which will prompt the user to fill
    // credentials in
    challenge: true
});
app.use("/colyseus", basicAuthMiddleware, monitor());


设置自定义房间列表列


app.use("/colyseus", basicAuthMiddleware, monitor({
  columns: [
    'roomId',
    'name',
    'clients',
    { metadata: "spectators" }, // display 'spectators' from metadata
    'locked',
    'elapsedTime'
  ]
}));


如果未指定,则默认的房间列表列为:['roomId', 'name', 'clients', 'maxClients', 'locked', 'elapsedTime']


负载测试 / 压力测试 (@colyseus/loadtest)


当您想对服务器进行实战测试并了解它在实时环境中的性能时,@colyseus/loadtest 工具非常有用。


微信图片_20220611162816.png


安装


安装 @colyseus/loadtest 模块:


npm install --save-dev @colyseus/loadtest


用法


colyseus-loadtest 命令需要一些参数才能工作:

  • script: 该工具将要使用的自定义脚本
  • --endpoint: 你服务器端点 (默认使用 ws://localhost:2567)
  • --room: 您要连接的房间名称
  • --numClients: 您想连接到 room 的客户端数量。


示例


这是一个脚本文件示例。基于每个连接客户端的房间生命周期事件,您可以实现一个 "bot" 来与 room 交互。


// script.ts
import { Room, Client } from "colyseus.js";
export function requestJoinOptions (this: Client, i: number) {
    return { requestNumber: i };
}
export function onJoin(this: Room) {
    console.log(this.sessionId, "joined.");
    this.onMessage("*", (type, message) => {
        console.log("onMessage:", type, message);
    });
}
export function onLeave(this: Room) {
    console.log(this.sessionId, "left.");
}
export function onError(this: Room, err) {
    console.error(this.sessionId, "!! ERROR !!", err.message);
}
export function onStateChange(this: Room, state) {
}


把 50 个客户端连接到一个 "battle" 房间


npx colyseus-loadtest script.ts --room battle --numClients 50 --endpoint ws://localhost:2567


认证 + 社交 (@colyseus/social)


本节介绍 @colyseus/social 的配置和用法。

@colyseus/social 是一个实验性模块,提供通用后端服务,以加快您的多人游戏开发体验。该 API 公开征求建议和改进。

如果要实现自己的身份验证方法,请参见 Room » onAuth()


安装


  1. 下载和安装 MongoDB
  2. 安装 @colyseus/social 模块。


npm install @colyseus/social
npm install express-jwt


  1. Importexpose@colyseus/social 提供的 Express 路由。


import express from "express";
import socialRoutes from "@colyseus/social/express"
const app = express();
app.use("/", socialRoutes);
app.listen(8080);


const express = require("express");
const socialRoutes = require("@colyseus/social/express").default;
const app = express();
app.use("/", socialRoutes);
app.listen(8080);


服务器端配置


环境变量


  • MONGO_URI: MongoDB 连接 URI
  • JWT_SECRET: 用于身份验证的安全 secret 字符串。
  • FACEBOOK_APP_TOKEN: Facebook App Token ("appid|appsecret")


服务器端 API


@colyseus/social 模块提供了 MongoDB models 和 token 验证功能供您使用。


import { User, FriendRequest, verifyToken } from "@colyseus/social";


实现 onAuth 去检索当前用户


import { User, verifyToken } from "@colyseus/social";
class MyRoom extends Room {
  async onAuth(client, options) {
    // verify token authenticity
    const token = verifyToken(options.token);
    // query the user by its id
    return await User.findById(token._id);
  }
  onJoin(client, options, user) {
    console.log(user.username, "has joined the room!");
  }
}


Hooks


hooks.beforeAuthenticate

beforeAuthenticate 钩子在用户登录或注册之前被触发。


import { hooks } from "@colyseus/social";
hooks.beforeAuthenticate((provider, $setOnInsert, $set) => {
    // assign default metadata upon registration
    $setOnInsert.metadata = {
      coins: 100,
      trophies: 0
    };
});


hooks.beforeUserUpdate

beforeUserUpdate 钩子在用户通过 save() 方法更新自己的信息之前被触发。


import Filter from "bad-words";
const filter = new Filter();
hooks.beforeUserUpdate((_id, fields) => {
  if (fields['username'] && filter.isProfane(fields['username'])) {
    throw new Error("no_swearing_allowed");
  }
})


客户端 API


登录

  • Anonymous
  • Email + Password
  • Facebook


匿名


await client.auth.login();


Email + 密码


await client.auth.login({
  email: "user@example.com",
  password: "12345"
});


Facebook


//
// Make sure you have the Facebook SDK installed and configured first
// - https://developers.facebook.com/docs/javascript/quickstart
// - https://developers.facebook.com/docs/facebook-login/web
//
FB.login(function(response) {
  if (response.authResponse) {
    client.auth.login({ accessToken: response.authResponse.accessToken });
  }
}, { scope: 'public_profile,email,user_friends' });


更新用户数据


您可以从客户端修改 usernamedisplayNameavatarUrllanglocationtimezone,然后调用 save() 方法。


client.auth.username = "Hello world!"
await client.auth.save();


注销


client.auth.logout();


获取朋友列表


const friends = await client.auth.getFriends();
friends.forEach(friend => {
  console.log(friend.username);
});


获取在线朋友列表


const friends = await client.auth.getOnlineFriends();
friends.forEach(friend => {
  console.log(friend.username);
});


获取朋友请求的列表


const friends = await client.auth.getFriendRequests();
friends.forEach(friend => {
  console.log(friend.username);
});


接受朋友的请求


await client.auth.acceptFriendRequest(friendId);


拒绝朋友请求


await client.auth.declineFriendRequest(friendId);


发送朋友请求


await client.auth.sendFriendRequest(friendId);


阻止用户


await client.auth.blockUser(friendId);


取消阻止用户


await client.auth.unblockUser(friendId);


调试


  • Inspector (--inspect flag)
  • Debug 消息


Inspector


可以使用 Node.js 中的内置 inspector 来调试应用程序。

阅读更多关于 调试 Node.js 应用程序.


在生产环境中使用 inspector


在生产中使用 inspector 时要小心。使用内存快照和断点将直接影响用户的体验。

1. 连接到远程服务器:


ssh root@remote.example.com


2. 检查 Node 进程的 PID


ps aux | grep node


3. 将 inspector 附加到进程上


kill -usr1 PID


4. 创建一个从本地机器到远程 inspector 的 SSH tunnel


ssh -L 9229:localhost:9229 root@remote.example.com


您的生产服务器现在应该出现在 chrome://inspect 上。


Debug 消息


服务器提供了一些调试消息,您可以通过设置 DEBUG 环境变量来逐个启用这些消息。

要启用所有日志,可以使用以下命令运行服务器:


DEBUG=colyseus:* node server.js


请参阅下面所有可用的调试类别和示例输出。


colyseus:patch


记录向所有客户端广播补丁的字节数和时间间隔。


colyseus:patch "chat" (roomId: "ryWiL5rLTZ") is sending 28 bytes: +57ms


colyseus:errors

在服务器端发生意外(或内部预期)错误时记录日志。


colyseus:matchmaking

每当房间 spanweddisposed 时都要记录。


colyseus:matchmaking spawning 'chat' on worker 77218 +52s
colyseus:matchmaking disposing 'chat' on worker 77218 +2s


部署



  • 部署在 Heroku
  • 部署在 Nginx 上(推荐)
  • 部署在 Apache
  • 使用 greenlock-express
  • Docker


Heroku


Heroku 仅用于原型设计。部署 colyseus-examples 项目:

https://heroku.com/deploy?template=https://github.com/colyseus/colyseus-examples


Nginx (推荐)

建议在生产环境中使用 pm2nginx


PM2

在您的环境中安装 pm2


npm install -g pm2


然后使用它启动你的服务器:


pm2 start your-server.js


Nginx 配置


server {
    listen 80;
    server_name yourdomain.com;
    location / {
        proxy_pass http://localhost:2567;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_read_timeout 86400s;
        proxy_send_timeout 86400s;
    }
}


使用 SSL 配置 Nginx

建议从 LetsEncrypt 获取证书。


server {
    listen 80;
    listen 443 ssl;
    server_name yourdomain.com;
    ssl_certificate /path/to/your/cert.crt;
    ssl_certificate_key /path/to/your/cert.key;
    location / {
        proxy_pass http://localhost:2567;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_read_timeout 86400s;
        proxy_send_timeout 86400s;
    }
}


Apache


下面介绍如何使用 Apache 作为 Node.js Colyseus 应用程序的代理(Thanks tomkleine!)

安装所需的 Apache 模块:


sudo a2enmod ssl
sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod proxy_html
sudo a2enmod proxy_wstunnel


虚拟主机配置:


<VirtualHost *:80>
    ServerName servername.xyz
    # Redirect all requests received from port 80 to the HTTPS variant (force ssl)
    RewriteEngine On
    RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [R=301,L]
</VirtualHost>
<VirtualHost *:443>
    ServerName servername.xyz
    # enable SSL
    SSLEngine On
    SSLCertificateFile          /PATH/TO/CERT/FILE
    SSLCertificateKeyFile       /PATH/TO/PRIVATE/KEY/FILE
    #
    # setup the proxy to forward websocket requests properly to a normal websocket
    # and vice versa, so there's no need to change the colyseus library or the
    # server for that matter)
    #
    # (note: this proxy automatically converts the secure websocket (wss)
    RewriteEngine On
    RewriteCond %{HTTP:UPGRADE} ^WebSocket$           [NC,OR]
    RewriteCond %{HTTP:CONNECTION} ^Upgrade$          [NC]
    RewriteRule .* ws://127.0.0.1:APP-PORT-HERE%{REQUEST_URI}  [P,QSA,L]
    # setup the proxy to forward all https requests to http backend
    # (also automatic conversion from https to http and vice versa)
    ProxyPass "/" "http://localhost:APP-PORT-HERE/"
    ProxyPassReverse "/" "http://localhost:APP-PORT-HERE/"
</VirtualHost>


greenlock-express


如果您希望在服务器上快速配置 SSL,而不需要配置反向代理(reverse-proxy),Greenlock 是一个很好的工具。


当使用 greenlock-express 时,你不应该在它背后配置任何反向代理,比如 Nginx 或 Apache。


npm install --save greenlock-express


请先遵循 greenlock-express 的 README 部分。

下面是处理开发环境(development)和生产环境(production)的推荐方法:


import http from "http";
import express from "express";
import { Server } from "colyseus";
function setup(app: express.Application, server: http.Server) {
  const gameServer = new Server({ server });
  // TODO: configure `app` and `gameServer` accourding to your needs.
  // gameServer.define("room", YourRoom);
  return app;
}
if (process.env.NODE_ENV === "production") {
  require('greenlock-express')
    .init(function () {
      return {
        greenlock: require('./greenlock'),
        cluster: false
      };
    })
    .ready(function (glx) {
      const app = express();
      // Serves on 80 and 443
      // Get's SSL certificates magically!
      glx.serveApp(setup(app, glx.httpsServer(undefined, app)));
    });
} else {
  // development port
  const PORT = process.env.PORT || 2567;
  const app = express();
  const server = http.createServer(app);
  setup(app, server);
  server.listen(PORT, () => console.log(`Listening on http://localhost:${PORT}`));
}


Docker


先决条件:

  • package.jsonpackage-lock.json 在项目中。
  • 设置 npm start 命令,使其启动服务器。

步骤:

Step 1 安装 Docker

Step 2 在 colyseus 项目的根目录中创建 Dockerfile


FROM node:12
ENV PORT 8080
WORKDIR /usr/src/app
# A wildcard is used to ensure both package.json AND package-lock.json are copied
COPY package*.json ./
RUN npm ci
# run this for production
# npm ci --only=production
COPY . .
EXPOSE 8080
CMD [ "npm", "start" ]


Step 3 在同一目录中创建 .dockerginore 文件


node_modules
npm-debug.log

这将防止您的本地模块和调试日志被复制到您的 Docker 镜像中,并可能覆盖安装在镜像中的模块。


Step 4 进入 Dockerfile 所在的目录,运行以下命令构建 Docker 镜像。-t flag 可以让你标记你的 image,这样以后使用 docker images 命令更容易找到:


docker build -t <your username>/colyseus-server .


Step 5 你的 image 现在将由 Docker 用以下命令列出:


docker images


输出:


# Example
REPOSITORY                      TAG        ID              CREATED
node                            12         1934b0b038d1    About a minute ago
<your username>/colseus-server    latest     d64d3505b0d2    About a minute ago


Step 6 使用以下命令运行 Docker 镜像:


docker run -p 8080:8080 -d <your username>/colyseus-server


使用 -d 运行镜像将以 detached 模式运行容器,使容器在后台运行。-p flag 将公共端口重定向到容器内的私有端口。


Step 7 完成后,现在可以使用 localhost:8080 连接到服务器

更多信息:

  • Official Node.js Docker Image
  • Node.js Docker Best Practices Guide


高可用,可扩展


这个文档是一个正在进行的工作。

要将 Colyseus 扩展到多个进程或服务器,你需要有 RedisMongoDB 和一个动态代理(dynamic proxy)。


Redis


下载并安装 Redis。使用 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(),
});


presence 用于从一个进程到另一个进程调用房间 "seat reservation" 功能,并允许开发人员跨 rooms 利用一些数据共享功能。请参阅 Presence API。


每个 Colyseus 进程还将自己的 processId 和网络位置注册到 presence API,稍后 dynamic proxy 服务将使用该 API。在 graceful shutdown 期间,进程注销自己。


MongoDB


下载并安装 MongoDB。安装 mongoose 软件包:


npm install --save mongoose


使用 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(),
});


您可以将 MongoDB 连接 URI 传递给 new MongooseDriver(uri) 构造函数,或者设置 MONGO_URI 环境变量。

driver 用于存储和查询可用于 matchmakingrooms


运行多个 Colyseus 进程


要在同一台服务器上运行多个 Colyseus 实例,需要每个实例监听不同的端口号。建议使用 300130023003 等端口。Colyseus 进程不应公开。只有 dynamic proxy 是。


强烈推荐使用PM2进程管理器来管理多个 Node.js 应用程序实例。

PM2 提供了一个 NODE_APP_INSTANCE 环境变量,其中包含每个进程的不同编号。使用它来定义端口号。


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


使用以下 ecosystem.config.js 配置:


// 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",
        }
    }]
}


现在你已经准备好开始多个 Colyseus 进程了。


pm2 start


"PM2 和 TypeScript":建议在运行 pm2 start 之前通过 npx tsc 编译 .ts 文件。或者,你可以为 PM2 安装TypeScript 解释器(pm2 install typescript),并设置 exec_interpreter: "ts-node"(read more)。


动态代理


@colyseus/proxy 是一个动态代理,它会自动监听 Colyseus 进程的上下变化,允许 WebSocket 连接到创建了房间的正确进程和服务器上。


代理应该绑定到端口 80/443,因为它是应用程序惟一的公共端点。所有请求都必须通过代理。


npm install -g @colyseus/proxy


环境变量


配置以下环境变量以满足您的需求:

  • PORT 是代理将运行的端口。
  • REDIS_URL 是你在 Colyseus 进程中使用的同一个 Redis 实例的路径。


运行代理


colyseus-proxy
> {"name":"redbird","hostname":"Endels-MacBook-Air.local","pid":33390,"level":
相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
4天前
|
存储 人工智能 自然语言处理
ChatMCP:基于 MCP 协议开发的 AI 聊天客户端,支持多语言和自动化安装 MCP 服务器
ChatMCP 是一款基于模型上下文协议(MCP)的 AI 聊天客户端,支持多语言和自动化安装。它能够与多种大型语言模型(LLM)如 OpenAI、Claude 和 OLLama 等进行交互,具备自动化安装 MCP 服务器、SSE 传输支持、自动选择服务器、聊天记录管理等功能。
51 14
ChatMCP:基于 MCP 协议开发的 AI 聊天客户端,支持多语言和自动化安装 MCP 服务器
|
6天前
|
弹性计算 运维 Serverless
产品测评 | ECS的健康保障新助手——云服务诊断
本文评测了阿里云的云服务诊断工具,该工具旨在帮助运维工程师和开发者快速定位和解决云资源问题。工具提供了“健康状态”和“诊断”两大核心功能,能够实时监控云资源状态,排查如网站无法访问、ECS故障等多种问题,并给出修复建议。该工具显著提升了排障效率,但在文档清晰度、功能描述准确性及部分功能实现上仍有改进空间。总体而言,该工具值得推荐给其他用户或团队使用。
|
16天前
|
安全 云计算
服务器系统资源不足怎么办
服务器系统资源不足怎么办
25 4
|
22天前
|
弹性计算 监控 数据库
制造企业ERP系统迁移至阿里云ECS的实例,详细介绍了从需求分析、数据迁移、应用部署、网络配置到性能优化的全过程
本文通过一个制造企业ERP系统迁移至阿里云ECS的实例,详细介绍了从需求分析、数据迁移、应用部署、网络配置到性能优化的全过程,展示了企业级应用上云的实践方法与显著优势,包括弹性计算资源、高可靠性、数据安全及降低维护成本等,为企业数字化转型提供参考。
42 5
|
26天前
|
安全 开发工具 Swift
Swift 是苹果公司开发的现代编程语言,具备高效、安全、简洁的特点,支持类型推断、闭包、泛型等特性,广泛应用于苹果各平台及服务器端开发
Swift 是苹果公司开发的现代编程语言,具备高效、安全、简洁的特点,支持类型推断、闭包、泛型等特性,广泛应用于苹果各平台及服务器端开发。基础语法涵盖变量、常量、数据类型、运算符、控制流等,高级特性包括函数、闭包、类、结构体、协议和泛型。
25 2
|
28天前
|
缓存 监控 数据库
提高服务器响应速度是提升用户体验和系统性能的关键
提高服务器响应速度是提升用户体验和系统性能的关键
34 3
|
2月前
|
监控 Java Linux
Linux系统之安装Ward服务器监控工具
【10月更文挑战第17天】Linux系统之安装Ward服务器监控工具
64 5
Linux系统之安装Ward服务器监控工具
|
11天前
|
存储 Oracle 安全
服务器数据恢复—LINUX系统删除/格式化的数据恢复流程
Linux操作系统是世界上流行的操作系统之一,被广泛用于服务器、个人电脑、移动设备和嵌入式系统。Linux系统下数据被误删除或者误格式化的问题非常普遍。下面北亚企安数据恢复工程师简单聊一下基于linux的文件系统(EXT2/EXT3/EXT4/Reiserfs/Xfs) 下删除或者格式化的数据恢复流程和可行性。
|
1月前
|
关系型数据库 API 数据库
后端开发的艺术:从零到一构建高效服务器
在数字化时代,后端开发是支撑现代互联网应用的基石。本文旨在探讨后端开发的核心概念、关键技术以及如何构建一个高效的服务器。我们将从基础的编程语言选择开始,逐步深入到数据库设计、API开发和性能优化等关键领域。通过实际案例分析,我们将揭示后端开发的复杂性和挑战性,同时提供实用的解决方案和最佳实践。无论你是初学者还是有经验的开发者,这篇文章都将为你提供宝贵的见解和启发。
|
1月前
|
存储 安全 关系型数据库
Linux系统在服务器领域的应用与优势###
本文深入探讨了Linux操作系统在服务器领域的广泛应用及其显著优势。通过分析其开源性、安全性、稳定性和高效性,揭示了为何Linux成为众多企业和开发者的首选服务器操作系统。文章还列举了Linux在服务器管理、性能优化和社区支持等方面的具体优势,为读者提供了全面而深入的理解。 ###