Q82: 如何防止刷物品?
核心结论
刷物品问题的本质,不是“物品多了一份”,而是系统允许同一份权益被重复提交、重复结算或重复发放。
真正有效的防护通常要同时具备:
- 权威资产状态
- 原子提交
- 幂等保护
- 审计流水
如果这四件事缺一,刷物品漏洞迟早会从某条边缘链路里冒出来。
一、刷物品通常是怎么产生的
常见根因包括:
- 交易提交和回滚时序错乱
- 背包、邮件、拍卖之间状态不同步
- 重试导致重复发放
- 掉线重连窗口中的双提交
- GM 或补偿脚本重复执行
所以刷物品很少是单点 bug,更多是状态边界和提交语义出了问题。
二、最核心的原则是“同一资产变更只能有一个权威提交点”
例如:
- 背包删物由背包系统权威提交
- 邮件领取由邮件和资产发放链路统一提交
- 交易最终交换由交易系统统一提交
不能让多个模块都能各自改同一份最终资产结果。
三、幂等是防刷物品的底线能力
只要存在:
- 客户端重试
- 网络超时
- 服务重放
- 任务补偿
那同一笔物品发放或转移就必须带唯一操作 ID。
更稳妥的语义应该是:
- 这笔操作是否已经执行过
- 执行过就返回已有结果
而不是“再执行一次看看会不会重复”。
四、交易、邮件、拍卖、任务奖励是高风险区域
这些链路最容易出复制问题,因为它们都涉及:
- 状态切换
- 资产转移
- 客户端确认
- 异步通知
所以这些系统都不应只依赖“客户端按钮顺序”,而要有明确的原子提交和失败回收规则。
五、日志和流水不是附加功能,是止血工具
如果没有流水,出了问题后你通常只能看到:
- 玩家多了物品
但看不到:
- 从哪条链路来的
- 重复了几次
- 哪笔请求先成功
所以高价值物品变更应尽量保留:
- 操作 ID
- 来源系统
- 数量变化
- 前后状态
六、工程上更稳妥的做法
常见组合是:
- 资产系统单权威
- 关键链路原子提交
- 所有发放和转移带幂等 ID
- 高价值操作保留流水和对账
这样即使出现 bug,也更容易快速止损和补偿。
七、常见误区
1. 只要交易系统没问题,就不会刷物品
不对。邮件、任务、补偿、拍卖、重连都可能是入口。
2. 数据库事务就能解决一切
事务只能保护它所在边界,重试、回调和异步链路仍然可能重复执行。
3. 刷物品一定是外挂
很多真实事故其实是业务链路幂等和状态机有漏洞。
参考资料
- 在线游戏资产一致性、幂等发放和防复制实践资料
