亚马逊AWS官方博客
Amazon GameLift 高阶使用技巧(1)- flexmatch 多模式匹配的实现
在当今的对战游戏世界中,玩家之间的对抗不仅仅是技术的较量,更是策略与团队协作的综合展示。想象一下,在一场紧张刺激的比赛中,Radiant(近卫) 和 Dire(天灾)两个队伍正准备展开殊死搏斗。为了确保每位玩家都能享受到最佳的游戏体验,匹配系统的设计显得尤为重要。理想的情况下,参与者之间应具备相似的技能水平、低延迟的网络连接,以及相同队伍的人数配置,这样才能让每场比赛都充满公平竞争与乐趣。
然而,现实中找到完美匹配并非易事。为了提升游戏体验,让玩家们快速匹配到合适的队友,公平决一胜负,匹配策略尤其重要。如何合理的设计规则,如何在找不到合适的人时通过设置动态扩展规则,逐渐放宽条件都是我们需要考虑的问题。随着游戏的发展,我们可能推出更多的玩法和模式,比如生存赛、练习赛和其他新奇的模式,不同的模式,对玩家的匹配要求也不完全一样。比如
- 练习赛 侧重的是让玩家熟悉操作和技能,匹配要求可以相对宽松。
- 生存赛 则强调竞技性和挑战性,需要更高的技能匹配,确保公平竞争。
面对这样的挑战,这时候我们需要一套更灵活、更强大的匹配解决方案。市面上已经有许多成熟的解决方案,比如 GameLift FlexMatch、OpenMatch等,后续我们也会专门发布一篇对比文章,详细分析这些匹配方案的特点、优势和适用场景,帮助大家选择最适合你游戏的方案。本次主要基于Amazon GameLift FlexMatch 方案进行介绍,它能根据不同的游戏模式、玩家需求和开发目标,帮助开发者打造更为出色的匹配系统,让每位玩家都能在公平竞争中尽情享受游戏带来的乐趣与挑战。
什么是 FlexMatch?
简单来说,FlexMatch 是 Amazon GameLift 提供的一个玩家匹配服务,它允许开发者根据游戏需求自定义匹配规则。它有几个主要特点:
- 托管服务:可以和 GameLift 一起用,也能独立使用。
- 玩家分队支持:能处理各种分队逻辑,比如不同阵营或队伍配置。
- 动态扩展规则:匹配时间长了,规则会逐步放宽,提高匹配成功率。
- 重连与掉线处理:玩家掉线了也可以重新回到匹配中。
规则集是什么?
在 FlexMatch 里,规则集是一个非常强大的功能,允许开发者根据各种复杂的条件来定义和管理玩家匹配的逻辑。匹配规则是通过 JSON 文件来定义的。一个规则集通常包含:
- 自定义属性:比如技能等级(skill)、游戏模式等。
- 团队定义:比如两个阵营(Radiant vs Dire)。
- 匹配规则:确保技能水平相近、队伍人数平衡等。
- 规则扩展:等待时间太长时,可以逐步放宽匹配条件,比如技能差距从 10 扩大到 20 再到 50。
示例规则:
![]() |
![]() |
关于详细的规则集编写与使用可以参考文档建立 FlexMatch 规则集。
随着游戏模式越来越多,匹配规则会变得越来越复杂。有些开发者把所有模式的规则都放在一个规则集中,而有些开发者则选择为每个模式单独创建规则集。接下来我们将基于一个具体的例子介绍在FlexMatch 实现多模式匹配中,这两种方案的一些实用经验和注意事项。
游戏规则
假设我们需要创建一个游戏规则:两个游戏阵营 Radiant(近卫) 和 Dire(天灾), 游戏有三种模式
- 经典:每个阵营4-6人
- 生存:每个阵营1-3人
- 练习:每个阵营2-8人
玩家主要的游戏属性有三个个:延迟(LatencyInMs) + 技能值(skill)+游戏模式(GameMode)
设定的条件为:每个玩家的延迟在80ms以内,技能差值在20以内。如果超过一定的匹配时间,可以适当的放宽松一些匹配条件。
分离规则集
常规的做法,按照游戏多少种模式,设计对应数目的规则集合。然后根据玩家的选择的游戏模式,向对应的规则匹配器发送匹配要求即可。比如按照前面的设计,我们会获得下面三种规则集合:
这种设计方法带来的挑战有:
- 设计简单,但是多次匹配调用逻辑复杂
- Gamelift 对应API的调用次数翻倍,有可能会被aws api的默认额度限速
还有一个所有的游戏设计者关心的问题:多个游戏规则,等价于玩家池子被拆分了,那么自然会考虑玩家匹配时间是否会被拉长。
单一规则集
一种做法是将所有的模式混合在一个大规则里面,这样做的好处是可以保证匹配的时候会有一个比较大的匹配池子。
然而,这种设计方法的也有如下挑战:
- 多种规则混合的设计,对于掌握flexmatch语法规则有挑战
- 复杂规则集合后期难于维护,会增加匹配的时间。
- 由于ruleset中 player attribute 最多只有10个属性,而且一个hardlimit,会导致添加新的玩法时候,发现player attribute不够用的时候。
这里还有一个隐含的问题:复杂规则会通常在多个模式种选择一个,会用到or和and的逻辑(compound规则),由于statement通常会从左到右的进行评价,会不会经常在左边的条件就终止了,而导致后面的游戏模式较少的被选中?
规则集验证
为了解决上面的疑惑,最好的方式就是进行flexmatch的压测。模拟大量的玩家在单一或者分离规则集合的不同情况下的表现。不过,一个真实的 gamelift + flexmatch 的环境通常会包含以下几个模块:
- Builds/Scripts: 游戏服务器部分
- Fleet: 匹配舰队,游戏会话放置的目的地
- Queue: 匹配队列,按照价格,容量,延迟等因素来选择不同的Fleet
- Notification: 通知系统,一般通过sns的消息机制来完成
- Ruleset: 匹配规则集合
- Configuration:匹配设置, 串联前面的各个模块
在这些模块中, queue中选择fleet对应的机型,通常是很大的不可控因素。比如地理位置导致的延迟,供需关系引起的价格波动,甚至你使用的fleet数目都会对于端到端的匹配时间有很大的影响。
因此我们使用的是flexmatch standalone模式。在这种模式下,只需要考虑匹配器本身即可。来验证规则集合在不同模式下对于游戏匹配时间的影响。可以参考的架构图如下:
架构图
![]() |
压测程序
为此,我们设计了一个压测程序,项目地址为:
- https://github.com/aws-samples/sample-simulator-gamelift-flexmatch-matchmaking
主要是利用了aws cli的两个命令:start_matchmaking 和 describe_matchmaking。其设计思路很简单:通过按照一定规则程序产生的大量玩家数据,来模拟并发调用不同的规则集合,然后去监控前面返回的匹配票据状态即可。同时,可以开启匹配的AcceptanceRequired,这样就需要同时再模拟调用accept_match的接口
该程序支持json格式的配置,比如:
然后通过一条简单的命令参数即可更新和关联新的匹配规则。目前具体支持的命令行有:
Options:
-help: Show this help message
-json: Output json config
-flexmatch: Update flexmatch sets
-benchmark: Start a benchmark
批量更新配置
压测之前,我们可以通过 -flexmatch 命令来保证匹配器的设置为最新的
![]() |
开启压测
注意:为了模拟玩家因为分开池子后的减少情况,我们会在非全匹配的模式中,加倍每个请求的随机等待时间。比如原来只有1-3秒,现在变成了2-6秒。
2000个模拟玩家(没有开启acceptance):
2000个模拟玩家(开启acceptance):
可以看到,规则拆分开以后,无论是否开启acceptance, 平均的匹配时间都是有一定的程度的缩短,并不会如之前想象的那样因为池子的变小导致了匹配时间变长。这里面根据分析得出来的结论有:
- 较为复杂的匹配规则同样会更多的消耗FlexMatch服务本身的算力,除了平均时间变长以外,最大值和最小值之间的差距也会拉大。比如下面的这个规则明显就过于复杂了。
- 拆分了规则池子,看起来玩家池子变少了,可以用一些设计手段进行规避。通常,游戏设计者会让玩家选择多种游戏模式来加快匹配。利用这点,可以同时发送多个匹配到flexmatch,然后以哪一个匹配最先撮合成功为标志,主动地拒绝其他匹配即可。这样的做法已经在很多客户实际案例上使用了。下图展示了一个真实的客户案例,当它们采用了分离式规则集合以后,端到端的匹配延迟(time-to-match)看到了明显的好转。
![]() |
观察
以下是我们对于不同规则集类型的优缺点对比的汇总表格,最终我们通过使用单一规则集同时发送多个匹配到flexmatch来综合两者的优点来实现。
维度 | 单一规则集 | 分离规则集 |
玩家匹配质量 | 所有 ticket 在一个池中,匹配质量更高。 | ticket 被分成多个较小池,匹配质量下降。 |
属性需求 | 需要更多属性以对应不同模式的规则。 | 只需每种模式特定的属性,属性需求较少。 |
最小/最大人数约束 | 所有模式共享约束,规则定义更复杂。 | 每种模式有独立约束,简化了实现。 |
维护复杂度 | 需要compound组合大量 AND/OR 规则,易出错,维护复杂。 | 规则独立,简单易维护。 |
匹配耗时 | 单一规则集需判断更多复杂条件,时间更长。 | 每个规则集判断的条件较少,时间更短。 |
关于 acceptance timeout seconds设置的建议,考虑到接受event的速度,响应调用API耗时,偶尔的网络抖动等原因,可以考虑先设置为5-10秒。更详细的设置可以考虑计算同一个match id的PotentialMatchCreated事件和AcceptMatchCompleted事件之间的时间差值,从而分析为什么系统未能按预期进行自动接受/超时。还可以使用相同的策略与AcceptMatch事件结合,计算Ticket响应接受匹配请求所需的时间。可以通过观察MatchAcceptancesTimedOut指标,观察到超时的匹配数量,而进行进一步的调整。
其他相关
- flexmatch中如何开启黑名单?
游戏中黑名单是一个常见需求,在flexmatch中我们通常会用player attribute的list属性来放置玩家名单。不过它会面临100个长度的上限。因此, 对于超过百人的名单,需要多个 player attribute 来配合。
- flexmatch的standalone模式如何知道匹配结果?
在standalone模式中,由于不会真实的拉起服务器,因此是没有GameSessionInfo相关的信息。需要等待SNS的MatchMakingSucceeded的事件。比如下面的例子:
结论
FlexMatch是GameLift的一个强大且灵活的补充组件。它不仅可以适用于10人以内的小型匹配场景,也能支持上百人的大规模匹配。目前,全球有许多知名游戏公司已在其游戏中采用了这项服务。它不是强制性需求,可以根据需求选择接入,并编写出各种强大且公平的匹配方案。
然而,我们必须承认,前期的测试无法完全模拟真实的游戏环境。生产环境通常情况下是多种多样的,您需要时刻考虑机器容量规划、区域选择,甚至游戏玩法等因素。还有一个不容忽视的,就是有些游戏会把AcceptMatch当作匹配成功的必要条件。这些因素远比FlexMatch本身复杂且具体。但在这里,我们主要想向开发者展示一种优化方式:无需关注运营商和底层硬件设备,只需调整ruleset的编写方式就能达到不错的效果。