游戏服务器赛季商店库存架构设计

围绕赛季商店、限购、共享库存、个人刷新和补偿场景,设计服务端库存与购买资格架构。

赛季商店往往一开始只是配置几件商品,后来逐渐加入个人限购、全服库存、每日刷新、阶梯解锁、会员折扣、补偿兑换和跨赛季继承。最危险的是把这些规则都写在购买接口里:检查配置、检查余额、检查限购、扣钱、扣库存、发货。等活动运营需要临时补货或回滚时,团队才发现没有库存流水,也解释不了玩家为什么买不了。赛季商店库存架构要把商品定义、购买资格、库存扣减和发货流水拆开。

典型场景

某赛季末上线稀有皮肤兑换,全服限量 5000 件,每人最多 1 件,钻石玩家提前一天可买。开售瞬间大量玩家同时点击,部分玩家扣了代币但库存不足,部分玩家重复点击拿到两个订单。运营随后决定追加 1000 件库存并补偿排队失败玩家。这个场景要求库存扣减有强一致 owner,个人限购有幂等记录,失败原因可解释,补货有审计。

架构示意

flowchart LR
  P["Purchase API"] --> Q["Eligibility Service"]
  Q --> S["Stock Owner"]
  S --> L["Stock Ledger"]
  S --> O["Order State"]
  O --> D["Delivery Service"]
  A["Admin Refill"] --> S
  S --> M["Shop Metrics"]

商品配置不等于库存状态

商品配置描述商品名称、价格、开放时间、可见条件和发货内容;库存状态描述剩余数量、已售数量、冻结数量、补货记录和版本。配置可以走内容发布流程,库存状态必须走事务和流水。不要在配置表里直接改库存数量,否则补货、回滚和审计都会混乱。

购买资格先判断可见,再判断可买

玩家能看到商品,不代表能购买。可见条件用于 UI 展示,例如赛季等级达到 20 级后显示;可买条件用于交易校验,例如未超过个人限购、当前时间在窗口内、玩家所在区服有资格、库存仍有余量。服务端购买接口必须重新校验可买条件,客户端展示只作为体验优化。

共享库存需要单一扣减 owner

全服限量商品不能让每个业务服自己扣库存。可以用库存 owner 服务、数据库条件更新、分片库存桶等方式,但同一库存维度必须有明确串行点。高并发下可以先做短暂预占,再在订单支付成功后提交;也可以购买时一次性扣库存和货币。关键是库存扣减、订单状态和发货不能互相脱节。

个人限购和订单幂等要绑定

玩家重复点击、客户端重试、网关超时都会产生重复购买请求。购买接口应要求 purchaseToken 或由服务端生成幂等键,并把个人限购记录与订单绑定。若订单已成功,重复请求返回同一结果;若订单失败且库存释放完成,可以允许重新购买;若订单处理中,返回处理中状态。不要仅靠“查询玩家已拥有道具”来判断限购,因为发货可能延迟。

补货和补偿要走同一套库存流水

运营追加库存、下架商品、补偿购买失败玩家,都应进入库存和订单流水。补货记录包含操作人、原因、数量、影响商品和生效时间。补偿不应直接给玩家道具绕过订单系统,否则玩家历史和商店统计对不上。通过特殊补偿订单发货,后续查账会清晰很多。

关键设计取舍

维度架构处理重点风险
个人限购玩家维度 purchase record重复点击和延迟发货
全服库存库存 owner 串行扣减秒杀热点
每日刷新周期版本和重置任务跨时区边界
补偿兑换特殊订单类型审计和客服查询

落地检查清单

  • 商品配置与库存状态分表管理
  • 可见条件和可买条件分开建模
  • 共享库存由唯一 owner 或条件更新扣减
  • 购买请求使用幂等键并绑定个人限购
  • 补货、下架、补偿全部写库存和订单流水

一线排障与复盘建议

这个架构上线后,团队要提前准备几类排障入口。第一是按玩家、业务单号或场景 id 查询完整链路,能看到请求进入、状态变化、关键版本、外部依赖结果和最终响应。第二是按时间窗口查看异常分布,区分是全局配置错误、单分片容量问题,还是少量玩家边界条件触发。第三是保留人工修复入口,但修复入口必须写审计流水,记录修复前状态、修复后状态、操作人、审批单和影响范围。没有审计的手工修复,短期能救火,长期会破坏系统可信度。

容量评估也要贴近玩法节奏,而不是只看平均在线。运营开活动、赛季结算、跨服匹配、周常刷新和主播带队都会让请求集中到很短窗口。压测脚本应模拟重复点击、弱网重试、服务超时、实例重启和消息乱序,不要只跑顺滑路径。对于玩家资产、资格、奖励、处罚这类敏感链路,压测结果里要额外检查幂等流水和最终状态,不只是吞吐量。

上线前可以采用影子模式:生产请求仍走旧逻辑,新架构旁路计算结果并记录差异。差异样本要由服务端、策划和客服一起看,因为有些差异来自旧逻辑 bug,有些来自新规则理解错误。等差异收敛后,再按小区服、低风险玩法或内部账号灰度。灰度期间观察错误码、超时、回滚次数、人工工单和玩家反馈,确认系统在真实噪声下仍然可解释。

库存维度建模

库存不是只有商品 id 一个维度。赛季商店常见库存维度包括 global、server、region、player_segment、vip_tier 和 personal。全服限量皮肤使用 global,区服礼包使用 server,地区活动使用 region,回流玩家礼包使用 player_segment。库存 key 应显式包含这些维度,例如 seasonId:itemId:stockScope:scopeId,避免后续新增地区库存时重构表结构。

个人限购也要有周期维度。每赛季一次、每周一次、每日一次、活动期间三次,都是不同 limitCycle。购买记录写入时要保存 cycleId 和 ruleVersion。运营改限购规则后,旧订单按旧版本解释,新订单按新版本校验。否则玩家会遇到“昨天还能买,今天规则变了但系统说你已超限”的争议。

故障案例:补货覆盖已售数量

某活动商店把库存配置成 totalStock 字段,购买时用 soldCount 判断剩余。运营补货时直接把 totalStock 从 5000 改为 6000,但发布系统把整行配置覆盖,部分分片的 soldCount 缓存被重置。结果少量玩家在库存售罄后仍买到商品。

改造后,补货不再修改原始 totalStock,而是写 stock_ledger:initial +5000,refill +1000,purchase -1。当前可售库存由流水聚合或库存状态机维护。配置发布不会覆盖库存运行态。运营后台看到的是“初始库存、补货库存、已售、预占、剩余”,而不是一个容易误解的总数字段。

高并发购买策略

限量商品开售时,可以使用短预占队列降低数据库冲突。玩家请求先进入库存 owner,owner 按顺序扣减库存并生成 orderId;货币扣减失败时释放库存。若货币扣减成功但发货失败,订单进入补偿,不释放库存。对于价值较低的商品,也可以采用数据库条件更新:remaining > 0 时 decrement,失败则售罄。选择哪种方式取决于商品价值和并发规模。

无论哪种方式,客户端都应能处理“处理中”。不要因为前端想要即时反馈,就把服务器流程压成一个不可恢复的同步函数。玩家看到短暂排队可以接受,扣钱后没有商品才不可接受。

活动结束与清理

赛季商店关闭后,不要立刻删除库存和订单。需要保留一段售后窗口,用于处理延迟发货、退款、补偿和客服查询。关闭状态也要分层:hide 表示不再展示,purchase_closed 表示不能新买,settlement_closed 表示补偿也截止。很多事故发生在活动关闭后,因为后台任务还在处理旧订单,而配置已经不可见。

清理任务应先确认没有 processing 订单、没有未释放预占、没有待发货补偿,再归档库存流水。归档后仍保留摘要统计,方便运营复盘本赛季商品消耗和玩家购买路径。

上线验收指标

赛季商店库存上线后,验收要看库存不变量:初始库存加补货减购买减作废,必须等于当前剩余加预占。个人限购记录必须能解释每个拒绝购买的玩家,订单状态必须能解释每个扣款玩家。运营后台展示的库存数字要和服务端校验使用同一来源,不能一个读配置,一个读运行态。

压测脚本要模拟开售瞬间并发、玩家重复点击、货币扣减失败、发货服务超时、运营补货、活动关闭时仍有订单处理中。回滚策略是关闭新购买入口,保留订单补偿和库存释放任务。不要直接回滚代码导致处理中订单无人接管。限量商品宁愿显示排队或暂停售卖,也不能让库存变成负数。

团队协作边界

赛季商店需要运营、商业化、服务器和客服共享同一套库存口径。运营看到的剩余库存,必须等于购买接口判断的库存;客服看到的限购次数,必须等于服务端拒绝玩家时使用的记录。若后台页面为了展示方便另算一套数字,事故时会制造更多争议。

商品上线前应有发布清单:库存维度、限购周期、价格版本、发货内容、补货权限、关闭时间和售后窗口。每一项都对应服务端状态,不只是活动文案。

常见误区

第一个误区是把库存写在商品配置里,运营补货时覆盖运行态。第二个误区是用玩家是否拥有道具判断限购,忽略订单处理中和发货失败状态。第三个误区是活动结束就清理数据,导致售后窗口无法补偿。赛季商店本质是资产交易系统,不能只按活动页面的思路设计。

数据保留建议

赛季商店的订单、库存流水和补货记录至少保留到售后窗口结束后。玩家常在活动结束后才反馈未到账或买错商品,如果运行态已经清理,只能人工猜测。归档时保留商品版本、价格、库存维度和发货结果,方便下个赛季复盘。

补充一点:商店复盘不要只看销售额,也要看售罄时间、失败订单、补货次数、客服工单和未领取补偿。库存架构的好坏,往往体现在活动结束后的售后成本上。

另外,库存告警应提前触发,而不是等商品售罄后才通知运营补货。

库存预警还要区分自然售罄和异常失败,避免误判运营效果。

总结

赛季商店越接近活动核心,越不能只是一个配置驱动购买接口。库存、资格和订单拆开后,运营玩法可以更灵活,资产问题也更容易解释。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页