队伍匹配(组队)
Category
system / 玩法系统。节点定位:队伍是撮合的原子单位——四种撮合形态(房间制 / 撮合池 / 段位分桶 / 等待队列+降级)的比对与选型,落点到跨服分片。
Definition
组队匹配与单人匹配的差别是结构性的:队伍是撮合的原子单位。队长代理进出、成员锁定与就绪确认、队伍分的计算(取平均还是最低),三件事让组队撮合比单人撮合多出一层状态机。
Problem
队长代理进出、成员锁定与就绪确认、队伍分口径,任何一件没定清楚,撮合形态选得再对也落不了地。冷门时段没人填房、房主不点开始全员干等、严格段位池永远配不上——这些事故各自指向不同形态的短板。先确定玩法要社交还是效率,再选形态;形态定了,队伍状态放哪(内存池还是实体系统)才有着落。
Algorithm
经典模式:房间制(房主建房)
最直观的形态:房主创建房间 → 设定玩法/人数/门槛 → 邀请或招募 → 满员就绪 → 开局。
房间状态机:WAITING → READY → STARTING → DESTROYED
成员事件:join / leave / ready / unready / kick / transfer_host- 优点:社交可见(好友互邀、围观加入)、失败处理简单(人不齐就不开)、玩家对「匹配慢」有掌控感
- 缺点:撮合效率取决于人数自然填充,冷门时段房间空转;房主不点开始就全员干等——需要房主超时移交(如 60 秒无操作自动移交或自动开局)
- 规模上限:单房间单进程内存态即可,房间数等于撮合复杂度上界
变体一:撮合池(组队整体进池)
组队后整队进入撮合池,由池侧完成配对。核心是距离度量:两个队伍可不可以配,定义一个标量距离再找近邻。
- 经典距离:
d = |队伍平均分差| + λ·|人数缺口| + μ·延迟地域差,池内两两扫描取最小 d 是 O(N²),N 是池内队伍数 - 降复杂度:只与「最近进入的 M 支队伍」比较(滑动窗口),或先按人数+玩法过滤再算分差——池的实际规模被过滤条件压到可扫描量级
- 配对后动作:双向确认(都同意才开局,防止被安排的挫败感)或直接开局(快但公平性弱)
变体二:按段位分桶
把连续分段切桶(如每 100 分一桶),队伍只与相邻桶的对手配对——撮合从全池扫描退化为桶内扫描:
- 桶内撮合 O(k²)(k 为桶内队伍数),跨桶不扫——复杂度与池总量解耦
- 桶边界处理:队伍分数跨过边界时跨桶匹配优先级低于桶内,避免「就差 5 分互为对手却永不相遇」
- 分桶是段位体系的基础设施:竞技组排(教程第 11 讲匹配系统一讲的分段 K 口径同样适用)基本都以它打底
变体三:等待队列 + 超时降级
等待时间是撮合的第二维度:等得越久,约束越松。降级阶梯(每级有明确触发时间):
T0 严格条件:段位差 Δ0、同地域、同人数
T0+10s 放宽段位:Δ = Δ0 + α·t(线性放宽)或跳桶放宽
T0+30s 放宽地域/延迟:允许跨区,提示「网络可能波动」
T0+60s 机器人补位 / AI 队友:保证秒开,标注人机(合规与体验口径见教程第 18 讲)
T0+90s 拆队降级:整队不齐时允许单人补位进残局池- 降级必须单向且可感知:放宽了就别收回,界面同步提示当前匹配条件——「明明等了 40 秒还在严格条件」是体验事故
- 超时驱动统一挂定时器(见文末引擎结合点):每个等待实体一条超时任务,到点进下一级阶梯
分布式方案:跨服撮合池
单服池容量有限,跨服撮合的常见结构:
- 撮合服务独立进程:全服队伍进中心池,撮合结果下发给对局所在服开房——撮合逻辑单点、对局计算分布
- 分片池:按段位×地域分片,每片一个撮合 worker,队伍按目标片路由——扩展靠加片,热点片(低段位人多)需要再分层
- 状态归属:池是纯内存态,撮合服务重启只丢「正在等待」的队伍(客户端重试即可),不落库是它比排行榜简单的地方
对比表
| 维度 | 房间制 | 撮合池 | 段位分桶 | 等待队列+降级 |
|---|---|---|---|---|
| 撮合延迟 | 取决于自然填充 | O(N²) 或窗口近似 | 桶内 O(k²),快 | 快(超时必开) |
| 公平性 | 房主定门槛 | 距离度量可控 | 段位对齐好 | 随时间放宽,公平递减 |
| 社交性 | 强(互邀/围观) | 弱(盲配) | 弱 | 弱 |
| 失败处理 | 人不开就不开 | 配不上退回池 | 桶空则跨桶 | 降级兜底,必成功 |
| 跨服扩展 | 房间分布即可 | 需撮合服务独立/分片 | 天然按桶分片 | 阶梯配置中心化 |
| 实现复杂度 | 低 | 中 | 中 | 中高(阶梯状态) |
| 热门/冷门时段 | 冷门空转 | 池深决定质量 | 桶空触发跨桶 | 冷门靠降级保体验 |
取舍
社交型玩法(MMO 副本、开黑语音房)选房间制,玩家要的是「和谁玩」,撮合效率是次要项。竞技型玩法(MOBA 组排、射击 5v5)要的是公平与等待的平衡,用「分桶 + 池化 + 降级阶梯」,房间制的自由度反而破坏段位严肃性。休闲和轻竞技宁要段位宽、不要等待长——等待时长对流失的影响大于单局公平的微小损失。
一条红线:同玩法不要同时提供「严格段位池」与「无门槛房」,段位体系会被旁路刷分。这属于教程第 18 讲的滥用面,撮合侧要把跨池分数流通封死。
适用规模
单服千级同时等待,撮合池全扫描或分桶都绰绰有余,先做房间制也够。万级到十万级必须分桶 + 分片池,撮合服务独立进程,降级阶梯配置化。跨服/全区全服用中心撮合服务 + 按段位地域分片,队伍状态可丢(不落库),对局状态在对局服。
Used By
skynet:撮合服务天然是一个 actor——池的读写在服务内串行,无锁(见 Skynet 源码解析 第 6 节);降级阶梯的定时触发挂时间轮
skynet.timeout(同篇第 7 节);跨服撮合可走其 cluster 组件(同篇第 5 节)Pitaya:撮合逻辑放独立 service、经集群 RPC 跨节点调用(消息分发与服务发现)
KBEngine / BigWorld:队伍本体可挂实体系统(KBEngine 的实体与 mailbox、BigWorld 的 cell/base 分工),撮合器仍建议独立于对局进程
撮合质量的线上口径(胜率回归、等待 P95)按教程第 11 讲的匹配质量双指标落地,防震荡按同讲陷阱表执行
Colyseus(commit
e620123):撮合 API 的房间中心形态——joinOrCreate先查后建(packages/core/src/MatchMaker.ts:201、:216、:230),按过滤条件加锁(packages/core/src/matchmaker/driver.ts:24-26),跨进程席位预约走remoteRoomCall(MatchMaker.ts:962)
Related
关系链:玩法形态(社交/竞技)→ 队伍作为撮合原子单位 → 撮合形态(房间/池/分桶/队列)→ 跨服分片 → 降级阶梯兜底。逐段回答「为什么需要下一个」:
- 定了队伍原子单位才谈撮合形态:队伍分口径决定距离度量,就绪状态机决定房间制的实现量。
- 形态定了才谈跨服:单服形态的失败处理是「退回重等」,跨服形态的失败处理是「分片路由」,两者不是同一个问题。
- 阶梯兜底放最后:它解决的是「池空/人少」的体验问题,不该用来掩盖前面形态选错的问题。
姊妹节点:PVP 匹配(单人竞技的评分与窗口,队伍分的计算口径与其评分体系衔接)、排行榜(段位分桶的桶宽即榜单的分数粒度)。
Reference
- 本页为工程经验归纳,无单一外部出处;撮合质量双指标与防震荡陷阱表见教程第 11 讲《匹配系统》
- 术语对照:Party Matchmaking(组队匹配)、Matchmaking Pool(撮合池)、Skill Bucket(段位分桶)、Degradation Ladder(降级阶梯)