使用 Azure 容器实例 (ACI) 实现同步多人游戏
探索此使用 Azure 容器实例、事件网格和 Azure Functions 的替代解决方案,它可按需自动缩放,且按每秒使用量计费,前提是您希望以支付较高价格为代价,利用托管虚拟机实现更简单的体系结构和维护工作。
服务器需要在 Azure 容器实例之外保持持久状态。
本文将描述 GitHub 上的此示例中使用的体系结构。 请注意,此参考体系结构中的代码只是一个指南示例,在用于生产环境之前,可能还有需要优化的地方。
体系结构关系图
相关服务
- Azure 流量管理器 - 选择此服务是因为它可以根据延迟情况将玩家连接到最合适的区域。
- Azure 容器实例 - 在 Azure 中运行容器的最快且最简单的方法,无需管理任何虚拟机,也无需采用更高级别的服务。
- Azure Functions - 选择此服务是因为它是运行小部分逻辑的最简单方法。
- Azure 表存储 - 用于跟踪容器组状态的简单的键/属性存储。
- Azure 事件网格 - 选择此服务是因为它内置针对来自 Azure 服务的事件的支持。
- Azure Blob 存储 - 我们需要一个用于存储自动缩放帮助程序配置的空间。
- 资源组 - 针对 Azure 流量管理器使用一个资源组,并针对每个区域游戏服务器池各使用一个资源组(例如,一个用于北美、一个用于欧洲、一个用于拉丁美洲、一个用于亚洲等)。
部署模板
单击下面的按钮,将项目部署到您的 Azure 订阅:
此操作将触发模板部署,即系统会将 azuredeploy.json ARM 模板文件部署到您的 Azure 订阅,从而创建必要的 Azure 资源并从此存储库中提取源代码。 这可能会在您的 Azure 帐户中产生相应费用。
请查看一般指南文档,其中有一篇文章概述了 Azure 服务的命名规则和限制。
要部署项目,需要指定以下信息:
- 位置:选择将部署资源的 Azure 区域。 请确保选择 Azure 容器实例可用的位置。
- Function 名称:选择 Function App 的唯一名称。 这将确定 Function 的 DNS,请谨慎选择。
- 存储库 URL:系统将拉取相应文件来创建 Azure Functions,而此 URL 将确定包含这些文件的存储库。 您可以保留默认值,或者换成自己的 Fork。
- 分支:此值与项目的 GitHub 分支相对应。
Azure Functions 部署在免费的应用程序服务计划上,您可能需要对它进行扩展以提高性能。
项目使用托管服务标识及其与 Azure Functions 的关系来对 Azure ARM API 管理服务进行身份验证,从而创建/删除/修改所需的 Azure 容器实例。 部署脚本会自动为 Function App 创建应用程序标识,但您需要向将要托管容器实例的资源组授予此标识权限。 为此,请执行以下操作:
- 访问 Azure 门户。
- 找到要在其中创建 Azure 容器实例的资源组(这可能是托管 Function App 的同一资源组)。
- 选择访问控制 (IAM)。
- 单击添加,选择贡献者作为角色,向 Function App 分配访问权限,然后通过修改订阅/资源组下拉框来选择 Azure Functions。
- 单击保存,就完成操作了!
此外,部署完成后,您需要按照此处的说明手动添加 ACIMonitor
Function 的事件订阅 Webhook。 只需确保选择正确的资源组来监控事件(即将在其中创建容器的 Azure 资源组)。 这样一来,只要指定资源组中发生资源修改,事件网格便会立即向 ACIMonitor
Function 发送消息。 完成此操作后,部署就准备就绪了。 获取 ACIMonitor
Function 的 URL 后,您可以使用此 ARM 模板来部署事件网格订阅,这是一项可选操作。
使用门户部署事件网格订阅时,需要填写以下值:
- 名称 - 为事件网格订阅选择一个独特的名称。
- 主题类型 - 选择“资源组”(如果 Azure 容器实例将部署在不同的资源组中,请选择“Azure 订阅”)。
- 订阅 - 要用来监控 Azure 容器实例创建事件的订阅。
- 资源组 - 选择将包含您创建的 Azure 容器实例的资源组。 请确保选中订阅所有事件类型复选框。
- 订阅服务器类型 - Webhook。
- 订阅终结点 - 这将包含
ACIMonitor
Azure Functions 的触发器 URL。 - 前缀筛选器 - 将其保留为空。
- 后缀筛选器 - 将其保留为空。
最后但同样重要的是,使用新的 Azure Functions v2 运行时版本时,EventGrid 绑定扩展可能需要手动注册。 在正常情况下,扩展将自动安装(因为它注册在 extensions.csproj 文件中),但如果没有自动安装,您可以查看以下文章了解如何手动执行此操作:
分步操作
- 玩家的设备客户端连接到流量管理器,以传送要查找游戏服务器的玩家请求。
- 流量管理器连接到具有最低延迟的区域,并指向可获取可用游戏服务器的 Matchmaker。
- Matchmaker 调用
ACIList
Azure Functions 以获取来自所有容器组的公共 IP 和活动会话列表。 - 该 Azure Functions 从 Azure 表存储中获取表,而该表存储将存储所有容器组中的公共 IP、活动会话数量和状态。
- 假设没有可用的表,系统将调用
ACICreate
Azure Functions。 容器状态为 Creating。 ACICreate
Azure Functions 创建容器。- 创建或删除容器时,系统接入事件网格进行侦听。 片刻之后(几分钟),事件网格收到来自正在创建的容器的相关事件。
- 事件网格还进行了设置,可在收到事件后调用
ACIMonitor
Azure Functions,以便传递公共 IP。 ACIMonitor
Azure Functions 插入来自新创建容器的公共 IP,并将该容器的状态设置为 Running。- Matchmaker 现在为玩家获得了一台可用服务器,它将详细信息发回设备客户端,以便设备客户端直接连接到服务器。
- Matchmaker 调用
ACISetSession
Azure Functions,以更新玩家被指派连接的容器上运行的活动会话数量。 ACISetSession
Function 更新 Azure 表存储。- 到某个时刻后,将不再需要服务器。 由于玩家可能仍在使用容器实例,因此本例不会手动删除容器,而是调用
ACISetState
Azure Functions 来将容器的状态设置为 MarkedForDeletion,这样一来,新玩家就不会被安排到该容器实例。 ACISetState
Azure Functions 更新 Azure 表存储。- 时间触发的
ACIGC
Azure Functions 会时不时地运行,并删除所有具有 MarkedForDeletion 状态的容器实例。 ACIGC
Azure Functions 调用可实际删除容器实例的ACIDelete
Azure Functions。ACIDelete
Azure Functions 删除容器。
使用更具体的示例:
- 一开始没有服务器实例。
- 突然,玩家需要服务器进行连接,系统调用了
ACICreate
。 - 执行创建命令时,服务器尚未启动和运行, 状态为 Creating。
- 完成部署后(几分钟),事件网格将通过
ACIMonitor
通知您服务器实例(容器组 1)正在特定的 IP 地址(即 1.2.3.4)中运行。 系统将该实例的状态更新为 Running。 - 玩家现在可以连接到服务器实例。
- 假设现在需要另一个服务器实例。 您可以再次使用
ACICreate
,或者如果已超出横向扩展阈值,则让ACIAutoScaler
代表您使用 ACICreate 创建实例。 - 还是同样的模式,新服务器尚未准备就绪,当部署完成后,事件网格将通过
ACIMonitor
通知您服务器在另一个特定 IP 地址(即 2.3.4.5)中运行。 系统将这第二个实例(容器组 2)的状态更新为 Running。 - 玩家现在可以连接到第二个实例。
- 最后,不需要第二个实例,我们决定不使用它或者超出了扩展阈值。 由于可能有玩家仍在使用第二个实例,因此系统不会删除该实例,而是调用
ACISetScale
将服务器标记为删除,这样一来,新玩家就不会被安排到第二个实例。 现在,第二个实例的状态是 MarkedForDeletion。 - 当玩家在第二个实例中结束游戏后,系统将运行垃圾回收器
ACIGB
,并触发ACIDelete
以完全删除第二个实例。
缩放
可通过以下环境变量配置 ACIAutoScaler
Azure Functions 设置:扩展/收缩阈值、最小/最大实例数以及冷却。 下面是自动缩放器的逻辑:
- 计时触发,每隔 1 分钟运行一次,默认禁用。
- 负载为已连接的玩家数量 / 总玩家容量。
- 如果(“负载”> 80% 且实例 < 最大实例数),则调用
ACICreate
Azure Functions 以加快启动新实例。 这可以处理好扩展情形。 - 如果(“负载”< 60% 且实例 > 最小实例数),则调用
ACISetState
Azure Functions,将负载最小的实例的状态设置为 MarkedForDeletion。 这可以处理好收缩情形。 - 扩展/收缩有 10 分钟的冷却期。
Azure 容器实例可以快速实现扩展,只需几分钟,您便可以随时开始使用新容器。 例如,对于扩展 30 个运行 OpenArena 的新 Azure 容器实例的请求,从请求发出到玩家能够连接,用时不到 3 分钟。
手动创建一组容器进行测试
如果您想创建一组容器实例进行测试,可以使用此处提供的示例。 将 openarenaserver1 替换为您要创建的各个实例的唯一名称(如 openarenaserver1、openarenaserver2、openarenaserver3 等)。 您还可以替换资源组、位置和存储名称/键。
其他资源和示例
请观看 Build 上录制的使用 Azure 容器实例实现多人游戏服务器缩放 视频,了解详细信息。
定价
如果您没有 Azure 订阅,可以创建免费帐户,开始使用 12 个月的免费服务。 除非您超出这些服务的使用限制,否则无需为 Azure 免费帐户中包含的这些免费服务付费。 了解如何通过 Azure 门户或使用情况文件查看服务使用情况。
您需要承担运行这些参考体系结构时使用的 Azure 服务的费用,总金额取决于将通过分析管道运行的事件数。 请参阅参考体系结构中使用的每项服务的定价网页:
您还可以使用 Azure 定价计算器,以配置和估算您计划使用的 Azure 服务的成本。