6.6 KiB
PVP Match Via RPC, Battle Via Redis
目标
本次调整先不解决 login 更新期间的排队保活和补偿问题,只收敛到一个更简单、可控的方案:
- 匹配请求走
logic -> login的同步 RPC - 对战过程仍走
logic本地战斗 + Redis 转发战斗指令 login不可用时,logic直接返回“匹配服务不可用”- 前端通过轮询重新发起 / 更新匹配请求,不在后端保留离线补偿队列
这个方案的核心是:先把“能否立即判断匹配服务可用”做好,不继续依赖 Redis PubSub 做匹配入口。
当前现状
现有匹配入口
- 前端
2458进入 logic/controller/fight_巅峰.go - 当前
JoINtop直接调用 logic/service/fight/pvp/service.go 的JoinPeakQueue JoinPeakQueue当前实现是本地建localQueueTicket,并通过 Redispublish发queue_join
现有跨服协调
logic侧订阅 PVP Redis topic 的入口在 common/rpc/func.go- PVP 匹配状态当前存在
logic/service/fight/pvp/service.go的 manager 内存里:queueslastSeenlocalQueuessessionsuserSession
现有 RPC 能力
logic启动时通过 common/rpc/rpc.go 建立到login的 RPC clientlogin的/rpc/*入口绑定在 modules/base/middleware/middleware.gologin侧 RPC server 由 common/rpc/rpc.go 暴露
当前问题
Redis PubSub 适合“广播消息”,不适合“同步判断服务是否可用”。
如果继续让匹配入口走 PubSub:
logic无法在请求当下知道login是否真能处理login更新、重启、未订阅时,匹配请求可能直接丢失- 前端即使轮询,也只是重复投递,不能精确表达“当前匹配服务可用/不可用”
收敛后的职责划分
login
login 只负责匹配控制面:
- 接收
logic发来的同步匹配 RPC - 判断当前匹配服务是否可用
- 维护匹配队列
- 找到对手后,记录 match 结果
- 再通过 Redis 或其他异步方式通知对应
logic开始 Ban/Pick / Battle
logic
logic 只负责:
- 接收前端匹配请求
- 同步 RPC 到
login - RPC 失败时立即返回“匹配服务不可用”
- RPC 成功时返回“排队中”
- 收到 match 结果后负责真正
fight.NewFight(...) - 对战期间继续使用现有 Redis topic 转发战斗指令
Redis
Redis 只保留在“对战消息面”:
match_foundban_pick_submitbattle_commandpacket_relaysession_close
也就是说:
- 匹配入口走 RPC
- 对战过程走 Redis
推荐目标链路
1. 前端加入/更新匹配
前端定期轮询 logic 的加入/更新接口。
logic 处理流程:
- 校验玩家当前战斗状态
- 同步调用
login的匹配 RPC - 如果 RPC 成功:返回排队中
- 如果 RPC 失败:清理本地匹配状态,返回匹配服务不可用
2. login 完成匹配
login 维护排队队列和匹配结果,匹配成功后:
- 确定 host / guest 所在
logic - 通过 Redis 通知两个
logic - host
logic开战 - guest
logic设置远端代理并进入 Ban/Pick 或战斗态
3. 对战期间
继续复用当前 logic/service/fight/pvp/service.go 内的 Redis 指令转发模式:
- 战斗操作通过 Redis topic 转发
- host
logic维持真实战斗对象 - guest
logic维持 remote proxy
失败语义
本阶段不做补偿,不做离线保队列。
login 不在线
如果 logic -> login RPC 调用失败:
- 本次匹配直接失败
logic清理本地匹配状态- 返回前端“匹配服务不可用”
前端轮询停止
如果前端不再轮询:
- 视为用户不再持续请求匹配
logic不负责继续保活- 是否从
login队列移除,由login的超时策略决定
login 更新中
如果 login 正在更新:
logic的同步 RPC 会失败- 前端当前轮询会收到“匹配服务不可用”
- 等
login恢复后,前端下一轮再发起匹配
这是本阶段明确接受的行为,不在后端做补偿。
最小实现建议
一、先增加 RPC 健康/匹配接口
在 common/rpc/rpc.go 增加面向 logic -> login 的 RPC 方法。
建议最小接口:
MatchJoinOrUpdate(PVPMatchJoinPayload) errorMatchCancel(userID) error
如果需要单独健康检查,也可以加:
MatchPing() error
但在最小方案里,MatchJoinOrUpdate 自身就可以承担健康检查职责。
二、logic 的匹配入口改为同步 RPC
改造 logic/controller/fight_巅峰.go 和 logic/service/fight/pvp/service.go:
- 入口不再直接发布
queue_join - 先发 RPC 到
login - 成功才更新本地匹配状态
- 失败直接返回错误
- 取消匹配时通过
MatchCancel做 best-effort 清理
三、保留 Redis 对战链路
logic/service/fight/pvp/service.go 之后的 Redis 消费、match result 处理、Ban/Pick、战斗 relay 不需要一次性重写,可以继续保留。
调整重点是:
- 不再让匹配入口依赖 PubSub
- 让对战过程继续走 Redis
对前端的要求
前端不要无脑重复“新 join”,而是按“轮询更新匹配状态”处理。
建议行为:
- 首次点击匹配时发一次加入
- 匹配中每隔
3~5s轮询一次更新 - 如果返回“匹配服务不可用”,前端退出匹配态并提示
- 如果返回“已匹配/进入 Ban/Pick”,前端切换到对应界面
本阶段不做的事
以下内容明确不在这次最小改造内:
login更新期间的排队保活- 持久化消息补偿
login重启后的队列恢复- Redis Stream 化
- 多
login实例协调 - 匹配服务自动拉起目标
logic
后续可选增强
如果后面要继续提高可用性,可以再逐步演进为:
- 匹配入口仍走 RPC
login内部把队列落 Redis- 加入 ticket 和续租机制
- login 更新时支持恢复匹配状态
但这不是当前阶段的目标。
最终收敛结论
当前阶段建议明确成一句话:
匹配走 RPC,对战走 Redis。
对应业务语义:
- 需要立即判断服务可用性的时候,用 RPC
- 需要跨服转发战斗消息的时候,用 Redis