使用 Amazon GameLift Servers 排查游戏会话放置问题
Troubleshoot game session placement with Amazon GameLift Servers
当游戏会话部署失败或超时时,玩家会立刻察觉:他们被困在等待大厅中,许多人因此放弃。在游戏上线日或区域容量调整后,成千上万的玩家可能同时遭遇这种情况。Amazon GameLift Servers 是一项用于部署、运行和扩展专用游戏服务器的托管服务,其游戏会话队列长期以来一直报告每次部署的结果(成功、超时或失败)。但故障排查需要从结果倒推,队列的决策逻辑并不可见。你无法得知它考虑了哪些位置、为何跳过离玩家最近的位置,以及它是在等待容量还是等待启动缓慢的游戏服务器。
在本文中,我们介绍游戏会话放置洞察,使推理过程变得可见。我们展示如何为现有队列启用洞察功能,然后逐步解答您现在可以通过单个查询回答的三个问题:为什么放置会超时、为什么某次放置耗时较长,以及为什么某次放置落在了特定位置。
游戏会话放置洞察的工作原理
在 Amazon GameLift Servers 中,游戏会话队列会根据玩家延迟、成本和容量等因素,将每个新游戏会话放置在跨一个或多个集群的最佳可用位置上。游戏会话放置洞察是详细描述队列如何处理每次放置请求的详细日志。您可以按队列选择加入,并指定日志的存放位置:
- Amazon CloudWatch Logs,即 Amazon CloudWatch 的日志存储和搜索功能。这是一个简单直接的起点,本文中的示例均使用它。
- Amazon Simple Storage Service(Amazon S3),用于低成本长期保留和分析的对象存储。
- Amazon Data Firehose,可将日志流式传输到其他分析和可观测性工具。
日志在每次放置完成后异步交付到您的账户,因此不会减慢或改变放置过程。
每次放置都会生成一系列简短的记录,从开始到结束跟随其流程。第一条记录捕获请求,包括玩家数量以及他们到各个区域的延迟情况。接下来,队列对候选的机队位置进行排名,并记录被排除的位置,然后记录每次尝试创建游戏会话的情况及其是否成功。如果队列在等待期间放宽了玩家延迟限制,该变化会生成一条独立的记录。最后一条记录显示结果:放置的状态、游戏会话落点的位置,以及时间的分配情况。
对于它考虑的每个位置,队列会记录该位置被使用或未使用的原因。例如:玩家延迟过高、位置超出容量,或更高优先级的位置先成功。每条记录还包含一段通俗语言摘要,因此通常只需阅读其时间线即可理解一次放置决策。以下示例展示了实际的记录和字段。
前提条件
要跟随操作,您需要:
- 一个 AWS 账户,其中已有一个 Amazon GameLift Servers 游戏会话队列,且该队列可放置到至少一个实例组(fleet)。
- AWS 命令行界面(AWS CLI),并已为您的账户完成配置。
- 配置日志投递的权限。Amazon GameLift Servers 使用您的凭据在您的账户中设置日志投递,因此您使用的角色需要对所用资源具备以下 API 的权限。删除权限用于干净地关闭洞察功能,并允许 Amazon GameLift Servers 回滚中途失败的设置,因此请一并授予这些权限。最后两项权限用于运行 Amazon CloudWatch Logs Insights 查询。
"gamelift:UpdateGameSessionQueue",
"gamelift:DescribeGameSessionQueues",
"gamelift:AllowVendedLogDeliveryForResource",
"logs:CreateLogGroup",
"logs:DescribeLogGroups",
"logs:PutResourcePolicy",
"logs:DescribeResourcePolicies",
"logs:PutDeliverySource",
"logs:PutDeliveryDestination",
"logs:CreateDelivery",
"logs:DeleteDelivery",
"logs:DeleteDeliveryDestination",
"logs:DeleteDeliverySource",
"logs:StartQuery",
"logs:GetQueryResults"为现有队列开启洞察
您可以为正在运行的队列开启洞察,无需更改游戏服务器或游戏客户端。要为现有队列开启洞察,请完成以下步骤:
- Add a CloudWatch Logs destination to your queue. If you omit a destination Amazon Resource Name (ARN), Amazon GameLift Servers creates a log group named
gameliftservers/queueplacementfor you.aws gamelift update-game-session-queue \ --name my-game-queue \ --add-log-delivery-destinations '[{"LogDestination":"CLOUDWATCH"}]' - Confirm the configuration. The response includes the resolved destination ARN, which you need later to turn insights off.
aws gamelift describe-game-session-queues \ --names my-game-queue \ --query "GameSessionQueues[].LogConfiguration"输出结果类似于以下内容。
DestinationArn是 Amazon GameLift Servers 为您创建的日志组:[ { "DeliveryDestinations": [ { "LogDestination": "CLOUDWATCH", "DestinationArn": "arn:aws:logs:us-west-2:111122223333:log-group:gameliftservers/queueplacement:*" } ] } ]
你还可以在创建队列时设置日志配置,并同时将日志发送到最多三个目标。队列上的新放置现在会生成洞察。以下各节中的每个查询都在 CloudWatch Logs Insights(CloudWatch Logs 的交互式查询功能)中针对 gameliftservers/queueplacement 日志组运行。使用默认目标的队列共享此日志组,因此每个查询都先按队列的 ARN 进行筛选。将 my-game-queue 替换为你的队列名称。$ 锚点可防止名为 my-game-queue 的队列也匹配到名为 my-game-queue-2 的队列。日志会在每次放置结束后不久送达,可能需要一两分钟才会出现。
为什么我的游戏会话放置操作超时?
假设玩家报告等待时间过长,且部分部署命中了队列的超时。首先找出超时的部署及其耗时分布:
filter resource_arn like /gamesessionqueue\/my-game-queue$/
| filter event_type = "placement_ended"
and data.status = "TIMED_OUT"
| display placement_id, data.duration.total_ms,
data.duration.fleet_capacity_wait_ms,
data.duration.activation_wait_ms在我们的测试中,一个 45 秒超时的队列返回了一个总耗时为 44,968 毫秒的部署。其中,42,958 毫秒用于等待容量,0 毫秒用于等待游戏服务器激活。要查看原因,请将该部署的游戏会话创建尝试与其最终结果并列列出:
filter resource_arn like /gamesessionqueue\/my-game-queue$/
| filter placement_id = "<placement-id>"
and event_type in ["game_session_creation", "placement_ended"]
| sort @timestamp asc
| fields @timestamp as time,
event_type,
data.attempt as attempt,
data.failure_reason as failure_reason,
data.status as status,
data.duration.fleet_capacity_wait_ms as capacity_wait_ms,
data.duration.activation_wait_ms as activation_wait_ms
| display time, event_type, attempt, failure_reason, status,
capacity_wait_ms, activation_wait_ms将 <placement-id> 替换为上一个查询结果中的部署 ID。
图 1:一个超时的部署。每次创建尝试均因缺乏容量而失败,且没有可测量的时间用于等待服务器激活。
结果显示,队列尝试其唯一目标六次,在每次尝试之间退避,并每次都因 DESTINATION_CAPACITY_EXCEEDED 而失败。该集群位置处于活动状态,但没有可用的空闲游戏服务器进程来承载新的游戏会话。只有在实例运行且其上的游戏服务器进程报告已准备好托管时,才能放置游戏会话。
此处的等待是容量问题,而非激活问题。解决方法是保持更大规模的空闲游戏服务器进程缓冲区,例如通过提高目标基数扩展策略中可用游戏会话的目标值来实现。如果 activation_wait_ms 是那个较大的数字,那么瓶颈将是游戏服务器自身的启动过程。在这种情况下,缩短从进程启动到向 Amazon GameLift Servers 报告就绪状态之间的时间,这是你可以控制的。
为什么我的游戏会话放置缓慢?
缓慢的放置会令玩家感到沮丧,即使成功的放置也可能需要 20 秒或更长时间。可以通过按总时间过滤已完成的放置来找出那些慢的放置:
filter resource_arn like /gamesessionqueue\/my-game-queue$/
| filter event_type = "placement_ended"
and data.status = "FULFILLED"
and data.duration.total_ms > 20000
| display placement_id, data.duration.total_ms,
data.duration.fleet_capacity_wait_ms,
data.duration.activation_wait_ms,
data.fulfilled_destination.location_name在我们的测试中,队列拥有一个舰队,其位置位于美国东部(北弗吉尼亚)区域(us-east-1)和美国西部(俄勒冈)区域(us-west-2)。其玩家延迟策略起初严格,随后逐渐放宽:前 20 秒最大延迟为 50 毫秒,之后为 100 毫秒。玩家报告到 us-east-1 的延迟为 40 毫秒,到 us-west-2 的延迟为 80 毫秒,但 us-east-1 没有可用的游戏服务器进程。查询返回的放置操作耗时 21,930 毫秒,其中 18,324 毫秒用于等待容量。要了解发生了什么,请列出该放置操作的延迟策略更改和创建尝试:
filter resource_arn like /gamesessionqueue\/my-game-queue$/
| filter placement_id = "<placement-id>"
and event_type in ["latency_policy_updated", "game_session_creation",
"placement_ended"]
| sort @timestamp asc
| fields @timestamp as time,
event_type,
data.max_player_latency_ms as max_latency_ms,
data.location_name as location,
data.result as result,
data.duration.total_ms as total_ms,
data.duration.fleet_capacity_wait_ms as capacity_wait_ms
| display time, event_type, max_latency_ms, location, result, total_ms,
capacity_wait_ms将 <placement-id> 替换为上一个查询结果中的放置 ID。
图2:一次缓慢的放置。队列一直等待最低延迟的位置,直到其延迟策略在20秒后放宽,随后将游戏会话放置在 us-west-2。
在前20秒内,严格的50毫秒策略使 us-east-1 成为唯一可接受的位置,而该位置的五次尝试均因容量不足而失败。在第20秒时,队列将策略放宽至100毫秒,从而允许 us-west-2 进入候选列表。在 us-east-1 再尝试一次后,队列最终将游戏会话放置在 us-west-2。
您的玩家等待了 20 秒,因为队列坚持寻找最低延迟的位置,而该位置没有可用容量。您有两个调整杠杆。如果较近的位置很重要,请在那里保留更多空闲的游戏服务器进程。如果您的游戏可以接受 80 毫秒的体验,请缩短严格策略的持续时间,以便队列更早扩大搜索范围。
为什么我的游戏会话部署到了那里?
有时部署会迅速成功,但落在了您未预料到的位置。在此测试中,队列在同一集群上使用了 100 毫秒的单玩家延迟策略,玩家向我们报告到 us-east-1 的延迟为 40 毫秒,到 us-west-2 的延迟为 250 毫秒。要了解队列考虑了什么以及游戏会话部署到了哪里,请比较玩家报告的延迟、评估结果和最终结果:
filter resource_arn like /gamesessionqueue\/my-game-queue$/
| filter placement_id = "<placement-id>"
and event_type in ["placement_started", "destinations_evaluated",
"placement_ended"]
| sort @timestamp asc
| fields event_type,
`data.regional_latencies_ms.us-east-1.avg` as us_east_1_ms,
`data.regional_latencies_ms.us-west-2.avg` as us_west_2_ms,
data.active_player_latency_threshold_ms as max_latency_ms,
data.filtered_out_reasons.SKIPPED_MAXIMUM_LATENCY_EXCEEDED_THRESHOLD.0.location_name as skipped_for_latency,
data.fulfilled_destination.location_name as landed_in
| display event_type, us_east_1_ms, us_west_2_ms, max_latency_ms,
skipped_for_latency, landed_in将 <placement-id> 替换为您正在调查的放置位置的 ID。
区域名称包含连字符,因此请将任何包含连字符的字段路径用反引号括起来,如区域延迟所示。
图3:为什么一个放置位置落在 us-east-1。玩家到 us-west-2 的延迟超过了队列的 100 毫秒限制,因此队列跳过了该位置。
玩家到 us-west-2 的 250 毫秒延迟超过了 100 毫秒的策略,因此队列将该位置过滤掉,并将游戏会话放置在 us-east-1。如果某个位置的放置数量远多于或少于您的预期,此类记录可以向您展示原因。要查看您的放置在整个队列中的分布情况,请按位置进行计数:
filter resource_arn like /gamesessionqueue\/my-game-queue$/
| filter event_type = "placement_ended"
and data.status = "FULFILLED"
| stats count(*) as placements, avg(data.duration.total_ms) as avg_ms
by data.fulfilled_destination.location_name同样的方法也解释了其他结果,每种情况都有其对应的viability_reason:因可行性评分过低而被跳过的 Spot 位置(SKIPPED_SPOT_INSTANCE_VIABILITY_BELOW_THRESHOLD)、因近期多次失败而被跳过的位置(SKIPPED_RECENTLY_NOT_AVAILABLE),或因请求级位置覆盖而被排除的位置(DESTINATION_NOT_IN_PRIORITY_CONFIGURATION_OVERRIDE_LOCATION_ORDER)。完整列表请参阅 Amazon GameLift Servers 开发者指南中的 事件数据字段。
将洞察与队列指标配对
Amazon GameLift Servers 已将队列指标发布到 CloudWatch。这些指标是设置警报的正确位置,因为它们能够以快速且低成本的方式告知您某事发生了变化。洞察则告诉您原因。当警报触发时,请针对该警报的时间窗口运行本文中的相应查询:
PlacementsTimedOut或PlacementsFailed正在上升:请按照“为什么我的游戏会话放置会超时?”中的步骤操作。对于失败的放置,请将筛选条件设置为状态为FAILED,而不是TIMED_OUT。”AverageWaitTime或QueueDepth正在上升,但放置仍然成功:请按照“为什么我的游戏会话放置速度慢?”中的步骤操作。”LowestLatencyPlacement正在下降,或FirstChoiceOutOfCapacity正在上升:放置结果落在了玩家最佳位置之外的地方。请按照“为什么我的游戏会话放置落在了那里?”中的步骤操作。”
清理”
如果您仅为了调查问题而开启了洞察功能,请删除日志目标。使用由 describe-game-session-queues 返回的目标 ARN:
aws gamelift update-game-session-queue \
--name my-game-queue \
--remove-log-delivery-destinations '[{"LogDestination":"CLOUDWATCH","DestinationArn":"arn:aws:logs:us-west-2:111122223333:log-group:gameliftservers/queueplacement:*"}]'移除目标需要来自前置条件的 logs:DeleteDelivery、logs:DeleteDeliveryDestination 和 logs:DeleteDeliverySource 权限。如果没有这些权限,调用仍可能成功,但会在您的账户中留下投递资源。移除目标会停止投递,但日志组及其日志仍然保留。删除日志组或设置保留期限,以避免持续的存储费用。如果您创建了跟随操作的集群或队列,也请一并删除它们。
结论
在本文中,我们展示了如何为现有的 Amazon GameLift Servers 队列启用游戏会话放置洞察功能。我们还展示了一个 CloudWatch Logs Insights 查询如何解释超时、缓慢或意外放置的游戏会话,否则你需要从结果反向推理才能理解原因。结合你已在 CloudWatch 中拥有的队列指标,洞察功能让你从“知道出了问题”进阶到“明白问题出在哪里”。
由于日志是结构化格式并投递到你自己的账户,你还可以将它们路由到 Amazon Athena 以进行长期分析,或通过 Firehose 流式传输到你现有的可观测性工具。
要开始使用,请参阅 Amazon GameLift 服务器开发者指南中的 游戏会话放置洞察。联系 AWS 代表以了解我们如何帮助您的游戏扩展规模。如果您有问题或反馈,请留下评论。
关于作者
来源:AWS for Games · 游戏技术与运营 · aws.amazon.com


