亚马逊AWS官方博客

用 AWS Lambda MicroVMs 快速部署多人游戏服务器:让 Colyseus 实时服务”无服务器化”

摘要:用 AWS Lambda MicroVMs 快速部署多人游戏服务器


一、引言

实时多人游戏服务器需要长连接、常驻进程和服务端主动广播——这三件事恰好是传统无服务器计算最不擅长的。本文面向云架构师与游戏后端工程师,演示如何把一个 Colyseus 多人游戏服务器部署到 AWS Lambda MicroVMs 上,既保留”有状态常驻服务器”的能力,又拿回无服务器”按需付费、闲时几乎零成本”的优势。

2026 年 6 月底,AWS Lambda 推出了由 Firecracker 驱动的 MicroVMs:每个实例都是一个带完整操作系统、可常驻最长 8 小时、空闲自动挂起、有流量近秒级恢复的隔离沙箱。它的官方适用场景里明确包含 game servers。本文配套一个完整、可运行的开源示例(MIT-0,全部 3D 内容为程序化几何体、无任何第三方美术资源),你可以直接克隆、部署、验证。

二、方案概览

实时多人游戏服务器(本文用 Colyseus)有三个硬需求,恰好踩在传统 AWS Lambda 函数的三个限制上:

多人游戏需要 AWS Lambda 函数 AWS Lambda MicroVMs
WebSocket 长连接 请求/响应模型 ✅ 入站 endpoint 原生支持 WebSocket
进程常驻、内存里维护房间状态 无状态,最长 15 分钟 ✅ 保留内存/磁盘/进程,最长 8 小时
服务端按 tick 主动广播 被动触发 ✅ 进程持续运行
没人玩时不烧钱 不适用 ✅ 空闲自动挂起(快照),流量自动恢复
游戏间相互隔离 不适用 ✅ 每实例独立 Firecracker VM
无需自建负载均衡 不适用 ✅ 每实例一个专属 HTTPS endpoint

整体架构如下:每个游戏房间对应一个独立的 MicroVM,Colyseus 服务端常驻其中,所有房间状态、玩家连接、tick 广播都在 MicroVM 内完成。浏览器客户端通过一个轻量的 HTTP Proxy 获取鉴权 token 并完成匹配,游戏数据则通过 WebSocket 直连 MicroVM。

这里的 HTTP Proxy 是一个纯粹的 token 管理与匹配路由层,它不参与游戏逻辑,只做三件事:

  1. 签发 token——调用 CreateMicrovmAuthToken 为客户端生成短期凭证
  2. 代理匹配请求——注入鉴权头,把 Colyseus 的 matchmake 请求转发到目标 MicroVM
  3. 路由多游戏——同一个 Proxy 可以管理多种游戏类型,每种游戏指向不同的 MicroVM 镜像或实例池

[图1:运行时架构]

Colyseus 房间完全托管在 MicroVM 内;HTTP Proxy 仅负责 token 管理与匹配路由,可同时服务多种游戏。

为什么连接要分成两条通道?这是把浏览器客户端接到 MicroVM 时最关键的工程点,本文第 5 节会详细拆解。

三、先决条件

  • 一个 AWS 账户,凭证已配置在环境中(profile 或环境变量),且位于 MicroVM 可用区域。
  • 区域限制:MicroVMs 仅在 us-east-1、us-east-2、us-west-2、eu-west-1、ap-northeast-1 提供,且仅支持 ARM64。本示例默认 us-west-2。
  • IAM 权限:lambda-microvms:*、构建产物桶上的 s3:*、构建角色上的 iam:*、以及 sts:GetCallerIdentity。
  • Node.js 20+ 与 npm;PATH 上有 zip。
  • 本地无需 Docker——镜像由 CreateMicrovmImage 在服务端基于 server/Dockerfile 构建。

克隆示例并安装依赖:

git clone <your-fork>/sample-host-colyseus-on-awslambda-microvm
cd sample-host-colyseus-on-awslambda-microvm
npm run install:all

四、把 Colyseus 打包成可在 MicroVM 运行的常驻服务

MicroVM 期望镜像里有一个监听其入站端口(默认 8080)的常驻进程。示例的 server/src/index.ts 在同一个 HTTP 服务器上同时承载 Colyseus 的匹配/WebSocket 与 MicroVM 的生命周期 hook:

import { Server } from '@colyseus/core';
import { WebSocketTransport } from '@colyseus/ws-transport';
import { createServer } from 'http';
import { GameRoom } from './rooms/GameRoom.js';

const PORT = Number(process.env.PORT) || 8080;
const HOOK_PREFIX = '/aws/lambda-microvms/runtime/v1/';
const ROOM_NAME = process.env.ROOM_NAME || 'game';

const httpServer = createServer((req, res) => {
  // 生命周期 hook(/run /ready /validate /resume /suspend /terminate):
  // 本示例无按实例的初始化/清理逻辑,一律以 200 应答,让 Lambda 放行流量
  // 并能干净地挂起/恢复实例。
  if ((req.url || '').startsWith(HOOK_PREFIX)) {
    let body = '';
    req.on('data', (c) => (body += c));
    req.on('end', () => { res.writeHead(200); res.end('{}'); });
    return;
  }
  res.writeHead(404);
  res.end('not found');
});

// Colyseus 的传输层附着到同一个 HTTP 服务器,处理匹配与 WebSocket 升级。
const gameServer = new Server({ transport: new WebSocketTransport({ server: httpServer }) });
gameServer.define(ROOM_NAME, GameRoom).enableRealtimeListing();

httpServer.listen(PORT, () => console.log(`[colyseus] listening on ${PORT}`));

这里有三点值得强调:

  1. 生命周期 hook 必须应答——MicroVM 通过它们判断实例是否就绪、何时可安全挂起/恢复;真实游戏可在 /suspend 时持久化房间状态、在 /resume 时重新加载。
  2. Colyseus 与 hook 共用一个 HTTP 服务器、共用 8080 端口,因此一个 MicroVM 入站 endpoint 就能同时承载匹配(HTTP)与游戏(WebSocket)。
  3. 所有房间逻辑都在 MicroVM 内运行——状态同步、碰撞检测、tick 广播全部由 Colyseus 在 MicroVM 内完成,外部 Proxy 完全不参与游戏计算。

配套的 server/Dockerfile 用 Node.js 基础镜像直接以 tsx 运行 TypeScript。由于 MicroVMs 仅支持 ARM64,基础镜像需支持 arm64(node:22-alpine 满足):

FROM public.ecr.aws/docker/library/node:22-alpine
WORKDIR /app
COPY package.json ./
RUN npm install
COPY . .
ENV PORT=8080
EXPOSE 8080
CMD ["npx", "tsx", "src/entry.ts"]

五、用 CLI 一键部署到 MicroVM

示例的 deploy/ 目录封装了一个 CLI,把整套 AWS API 调用串成一条流水线。运行:

npm run deploy

它依次完成:确保 Amazon S3 构建产物桶与 IAM 构建角色存在 → 打包上传 server/ → 调用 CreateMicrovmImage(服务端 Docker 构建,约 1–2 分钟)→ 调用 RunMicrovm 拉起实例并等待 RUNNING → 把实例坐标写入 config.json。

[图2:部署时序]

镜像构建与实例运行分两步;config.json 只存实例坐标,不存 token。

核心的 RunMicrovm 调用如下,其中 idlePolicy 是成本的关键开关:

import { LambdaMicrovmsClient, RunMicrovmCommand } from '@aws-sdk/client-lambda-microvms';

const client = new LambdaMicrovmsClient({ region: 'us-west-2' });

const run = await client.send(new RunMicrovmCommand({
  imageIdentifier: imageArn,
  imageVersion,
  ingressNetworkConnectors: [allIngress],       // 开放入站,拿到专属 endpoint
  egressNetworkConnectors: [internetEgress],
  idlePolicy: {
    maxIdleDurationSeconds: 1800,   // 空闲 30 分钟后挂起(快照保留内存/磁盘)
    suspendedDurationSeconds: 3600, // 挂起满 1 小时后终止
    autoResumeEnabled: true,        // 有入站流量时自动恢复
  },
  maximumDurationInSeconds: 28800,  // 8 小时硬上限
}));
// run.microvmId, run.endpoint —— endpoint 形如 *.lambda-microvm.us-west-2.on.aws

构建角色的坑:镜像构建角色的信任主体必须是 lambda.amazonaws.com,而非 microvms.lambda.amazonaws.com(后者会被拒为非法 service principal)。该角色只需对产物桶有 s3:GetObject 权限。

部署完成后,构建客户端并启动同源静态服务器:

npm run build:client   # 产出 client/dist(config.json 随之带入)
npm run static         # http://localhost:3000:静态托管 + /_mm 代理 + /_mm/token

打开 http://localhost:3000,再开一个标签页,即可看到两个玩家在同一房间内实时同步。

六、连接机制:让浏览器接上 MicroVM

这是整套方案的核心难点。MicroVM endpoint 要求每个请求都在 X-aws-proxy-auth 头里携带一个 JWE token,目标端口则按优先级由 X-aws-proxy-port 头、lambda-microvms.port.{N} 子协议或默认 8080 决定。问题在于:浏览器无法给所有类型的请求都附加自定义头。因此客户端需要两条独立的连接通道——上文 Figure 1 已完整描绘这一流程,这里直接展开代码实现。

6.1 通道一:HTTP 匹配走同源代理

浏览器直接 fetch 跨域的 MicroVM endpoint 会触发 CORS 预检 OPTIONS。预检请求带不了 X-aws-proxy-auth 头,于是被 endpoint 以 403 拒绝。解决办法是把匹配请求改走同源的 /_mm/* 代理,由服务端注入鉴权与端口头——既无预检,也无跨域:

// scripts/dev-static-server.mjs —— 同源匹配代理(关键片段)
const options = {
  method: req.method,
  headers: {
    'X-aws-proxy-auth': mvm.token,             // 服务端注入:浏览器拿不到也无需关心
    'X-aws-proxy-port': String(MICROVM_PORT),  // 选择目标端口 8080
    'Content-Type': req.headers['content-type'] || 'application/json',
  },
};
const up = httpsRequest(`https://${mvm.endpoint}/${mmPath}${search}`, options, (upRes) => {
  res.writeHead(upRes.statusCode || 502, { 'Content-Type': upRes.headers['content-type'] });
  upRes.pipe(res);
});

6.2 通道二:WebSocket 直连、子协议鉴权

WebSocket 升级没有 CORS 预检,因此可以直连 MicroVM endpoint。但浏览器 WebSocket API 不能设请求头,于是 token 与端口改走 子协议——这正是 AWS 为此场景预留的机制:

// client/src/network/microvm.ts —— 在 colyseus.js 捕获原生 WebSocket 之前
// 提前 patch window.WebSocket,对发往 endpoint 的连接注入子协议。
new WebSocket(endpointUrl, [
  'lambda-microvms',
  `lambda-microvms.authentication.${token}`,  // token 走子协议
  'lambda-microvms.port.8080',                // 端口走子协议
]);

这里的顺序至关重要:客户端必须在 colyseus.js 之前导入并执行该 patch,否则 colyseus.js 会先捕获原生 WebSocket 引用,子协议注入就失效了。

6.3 Token 运行时刷新,绝不烘焙

token 最长 60 分钟过期,把它写进构建产物是个隐患。所以 config.json 只存 { endpoint, microvmId, region },不含 token。客户端在连接前向 /_mm/token 拉取一个新鲜的 { endpoint, token },服务端用 CreateMicrovmAuthToken 现签并按 microvmId 缓存、提前约 5 分钟刷新。这样,即使 MicroVM 长时间运行或被重启,客户端也永远不会拿到失效 token 而 403。

6.4 演示效果

打开一个浏览器 ,开发环境是 localhost:3000, 选择 multiplayer , 然后选择 Create Room

[图3]

第一个玩家进入游戏

[图4]

打开另外一个浏览器 ,选择同样的房间就可以看见其他玩家,Colyseus 房间服务器会自动同步技能和玩家位置等状态。

[图5]

[图6]

七、最佳实践

  • 鉴权:token 仅在运行时签发,作用域限定到具体 MicroVM + 端口 + 过期时间;切勿把 token 写入前端包或 config.json。
  • 挂起/恢复重连:空闲挂起会断开所有活跃 WebSocket。客户端应监听断连并自动重连(重连时重新拉取 token);服务端可利用 /suspend、/resume hook 持久化与恢复房间状态。
  • 8 小时上限轮换:单实例最长 8 小时,长寿命房间需要到点迁移或重启策略。
  • 按房间人数选实例尺寸:多人游戏是广播型流量,带宽随实例尺寸线性变化且进出共享。一个 8 人房 @20Hz 状态同步要据此估算,避免小尺寸实例的带宽成为瓶颈。
  • 多游戏支持:同一个 HTTP Proxy 可以管理多种游戏——在 config.json 中维护 gameType → {microvmId, endpoint} 映射表,匹配请求根据 gameType 参数路由到对应的 MicroVM。每种游戏可以使用不同的镜像、不同的实例尺寸、不同的 idlePolicy。
  • 不要用 Lambda Function URL 暴露代理:生产环境应将 HTTP Proxy 置于 Amazon API Gateway 或 Application Load Balancer + Amazon CloudFront 之后。

八、成本考量

MicroVM 的计费跟随占空比,而非”是否拥有机器”:

  • 运行中——按秒计费。
  • 空闲挂起——超过 maxIdleDurationSeconds(本例 30 分钟)后拍快照,仅付极低的快照存储费;入站流量自动恢复。
  • 已终止——零成本。

因此,对长尾型游戏(大部分时间无人、偶尔被唤醒)极其划算——这正是”一键生成、按需唤醒”类平台的典型形态。对持续高并发的热门游戏,常驻实例摊薄后可能更便宜;请按预期房间人数选择实例尺寸。

九、清理资源

验证完成后,务必终止实例以停止计费:

npm --prefix deploy run terminate  # 调用 TerminateMicrovm,停止该实例计费

如需彻底清理,还可删除构建生成的 MicroVM 镜像、Amazon S3 产物桶中的构建包,以及 IAM 构建角色。注意:删除镜像前必须先终止所有在跑的 MicroVM,否则会报 Cannot delete MicroVM image with running MicroVMs。

十、结语

本文展示了如何把 Colyseus 多人游戏服务器完整托管到 AWS Lambda MicroVMs 上:所有房间逻辑、状态同步、tick 广播都在 MicroVM 内运行;外部只需一个轻量的 HTTP Proxy 负责 token 管理与匹配路由。这一架构天然支持多游戏——同一个 Proxy 可以同时服务不同类型的游戏,每种游戏对应独立的 MicroVM 镜像和实例池。

这一组合让多人游戏服务器第一次同时拥有了两样东西:常驻服务器的能力与无服务器的成本曲线——没人玩时几乎零成本,有人玩时秒级拉起。多人游戏只是一个具体例子,同类负载还包括交互式开发环境、AI 代码沙箱、运行用户脚本的有状态服务等。

你可以克隆配套示例(MIT-0、全程序化几何体、无第三方资源)亲自跑通端到端流程,并在此基础上扩展:接入客户端无缝重连、为 Proxy 增加多游戏路由逻辑,或将 Proxy 迁到 Amazon API Gateway。开始构建吧。

➡️ 下一步行动:

相关产品:

相关文章:

十一、参考资料

*前述特定亚马逊云科技生成式人工智能相关的服务目前在亚马逊云科技海外区域可用。亚马逊云科技中国区域相关云服务由西云数据和光环新网运营,具体信息以中国区域官网为准。

本篇作者

粟伟

亚马逊云科技资深解决方案架构师,专注游戏行业。开源项目爱好者,致力于云原生应用推广、落地。具有 15 年以上的信息技术行业专业经验,担任过高级软件工程师,系统架构师等职位,在加入亚马逊云科技之前曾就职于 Bea、Oracle、IBM 等公司。

贺杨

AWS解决方案架构师,具备17年IT专业服务经验,工作中担任过研发、开发经理、解决方案架构师等多种角色。在加入AWS前,拥有多年外企研发和售前架构经验,在传统企业架构和中间件解决方案有深入的理解和丰富的实践经验

陈昊

陈昊,AWS 合作伙伴解决方案架构师,有将近 20 年的 IT 从业经验,在企业应用开发、架构设计及建设方面具有丰富的实践经验。目前主要负责 AWS (中国)合作伙伴的方案架构咨询和设计工作,致力于AWS 云服务在国内的应用推广以及帮助合作伙伴构建更高效的AWS云服务解决方案。


AWS 架构师中心:云端创新的引领者

探索 AWS 架构师中心,获取经实战验证的最佳实践与架构指南,助您高效构建安全、可靠的云上应用