返回项目

PROJECT FILE 03 · HIGH CONCURRENCY

大营销抽奖平台

抽奖只是用户看到的一次点击,系统真正承担的是峰值流量、有限库存与重复请求同时到来时的确定性。

Backend Architecture2024SHIPPED

抽奖不是一个随机函数

用户看到的是一次点击和一个奖品;系统实际先决定这次请求该走哪条规则,再决定哪个节点有权结束流程。这个项目要解决的,不是把奖品随机出来,而是让这条决策路径能被配置、复核和演示。

先看责任链,而不是先看规则树

责任链的顺序不写在 Java 的 if 里。工厂按 strategy.rule_models 列内的顺序装配节点,最后固定追加 rule_default;列为 NULL 时,就只装配默认节点。实验种子里的真实配置值是:

strategy_id = 100006
rule_models = NULL
=> rule_default

strategy_id = 100007
rule_models = "rule_blacklist"
=> rule_blacklist -> rule_default

strategy_id = 100008
rule_models = "rule_weight"
=> rule_weight -> rule_default

因此,责任链不是“黑名单、权重、默认”这样一条被写死的流程。配置把谁放在前面,谁就先判断;非默认节点一旦命中便短路,后面的节点和规则树都不会运行。把顺序留在数据里,活动策略才可以变化,而执行语义仍然有可查的来源。

只有默认路径会进入规则树

未被责任链接管的请求才进入规则树,真实节点顺序是 rule_lock → rule_stock → rule_luck_awardrule_lock 先处理奖品的解锁条件;命中可用奖品后,rule_stock 尝试扣减库存。库存扣减成功时,它以 TAKE_OVER 结束树的遍历并保留该奖品。

库存不足时的行为尤其不能靠直觉补全:rule_stock 不返回一个“库存不足”的业务错误,而是返回 ALLOW,继续走到 rule_luck_award 取得兜底结果。对调用方而言,这次抽奖仍然成功;路径中发生过的库存降级并不出现在响应里。

结果不能反推出路径

同一个 awardId 并不等于同一条执行路径。兜底奖品 101 同时出现在基础奖池、黑名单命中、规则树兜底和库存不足降级等语义不同的结果中。只看最终奖品,既无法判断责任链是否短路,也无法判断规则树在哪个节点改道。

这也是实验室把“返回结果”和“执行轨迹”分开的原因:前者是接口能够给出的终点,后者需要根据配置和规则节点逐步演算。正文只保留这些可以核验的事实;完整的调参与轨迹观察留在独立实验室。

把可靠性落到可解释的边界

库存、配额和发奖仍然需要各自的事务与补偿机制,但它们必须建立在同一件事上:每一次分支都知道自己依据了什么配置、何时终止、何时继续。责任链和规则树把这件事从抽象的“高并发能力”收束为可以审阅的决策边界。