日期:2026-07-13
我们这个项目服务的是某省级国资集团。集团旗下有数十家二级单位、数百个三级网点,过去各地分散采购,既管不住价格,也沉淀不下数据。集团下定决心把采购需求统一上收,搭建一套集团级集采商城——也就是我们在 XpShop 集团物资采购电子商城这套底座上做二次实施,对外挂了一层"新普MALL"式的多终端入口(PC 采购门户、小程序、门店/业务员代客端)。
难点不在"能不能下单",而在"集中发力的那一刻"。国资采购有个很典型的特征:询价期集中、报量式爆发。每到季末、年中、年度预算节点,几百家单位会在同一个窗口期涌入报量,形成秒杀式的瞬时写峰。同时,订单不是落库就完事,还要对接既有 ERP 做预算占用、对接财务系统做审批与付款,这条链路牵一发动全身。我们接手时,客户最担心的三件事是:大促别把库打爆、审批别和订单对不上、老 ERP 别被我们拖死。
落到具体业务里,有四类高频且棘手的场景:
一是集中询价期的秒杀式报量。一个标段放出限时询比价,几百家单位几乎同一秒点击"确认报量",后端要在极短时间内完成库存预占、价格校验、订单落库。
二是多级审批流与订单落库的强一致诉求。一笔采购要走过"部门初审→财务复核→集团终审"多级链路,审批通过后才真正生成履约订单。业务方希望"审批过就是订单在",但技术上审批系统和订单系统是两套存储。
三是与 legacy ERP 的异步对账。集团的 SAP/用友类系统年代久远,接口吞吐有限,不能承接实时高频写,只能走批量/异步。
四是门店/业务员代客下单移动端的弱网重试。一线业务员在仓库、工地上用手机代客下单,网络时断时续,重复提交、失败重试是常态。
① 大促瞬时写峰:订单分库分表 + Redis 预扣库存。 我们把订单表按 tenant_id + 年月 做 range 分片,再按 order_id 哈希打散到 16 个物理库,单库压力从百万级降到可控区间。库存不做实时落库扣减,而是先走 Redis 预扣:用一段 Lua 脚本保证"查询余量—扣减—返回"的原子性,只有预扣成功才允许进入下单事务。落库后由后台任务异步回写库存账。预扣失败(余量为 0)直接快速失败,把无效流量挡在数据库之外。
② 多级审批流与订单落库的一致性:最终一致 + 补偿。 我们没有去追求跨系统的强事务(那会让审批系统被订单系统绑死),而是把"审批通过"作为事件源。审批中心在终审通过时发一条可靠事件到消息队列,订单中心消费事件生成履约订单;若订单落库失败,进入补偿队列定时重试,并把失败状态回写到审批单的"履约回执"字段,保证两端可核对。业务上"审批已过但订单暂未生成"的短暂窗口是允许的,但绝不能出现"审批没过却出了订单"。
③ 与 legacy ERP 对接用消息队列削峰。 订单履约后产生出库、预算占用、对账明细等事件,全部先落到我们自己的 MQ(Kafka 类),再由对账适配器按 ERP 能承受的速率(限流 + 批量聚合)推送。ERP 接口抖动甚至短暂宕机,都不会反压到商城主链路,对账差异由补偿任务兜底。
④ 移动端弱网重试:幂等键 + 本地队列。 代客端每次下单携带客户端生成的 request_id,服务端用唯一索引做幂等拦截;弱网下客户端把下单请求写入本地离线队列,恢复网络后按序重发,服务端重复 request_id 直接返回首次结果,杜绝重复成单。
案例片段(已脱敏):Redis 预扣库存的 Lua 脚本(简化版)
lua -- KEYS[1]=库存key ARGV[1]=扣减数量 ARGV[2]=订单token local stock = tonumber(redis.call('GET', KEYS[1])) if not stock or stock < tonumber(ARGV[1]) then return -1 -- 库存不足,快速失败 end redis.call('DECRBY', KEYS[1], ARGV[1]) redis.call('HSET', KEYS[1]..':locks', ARGV[2], ARGV[1]) -- 记录预占 return stock - tonumber(ARGV[1])压测数据(脱敏示意,4C8G 单分片):单分片预扣 QPS 约 1.2 万,P99 延迟 8ms;全链路订单创建在 1.6 万 QPS 下 P99 约 210ms,未出现超卖。
上线后的大促实战给了我们一份比较直接的答卷(均为脱敏示意值):
回过头看,这套方案里真正值得带走的几条经验是:
先保幂等,再保性能。 弱网、重试、MQ 重投都会带来重复请求,幂等键是底座而非补丁。把 request_id/事件去重做扎实,后面加缓存、加分片才不会埋雷。
对账用补偿而非强事务。 跨老系统(尤其是 legacy ERP)别幻想强一致,用"可靠事件 + 异步对账 + 补偿任务"把一致性收敛到最终一致,系统反而更稳、更解耦。
库存的写峰要挡在数据库前。 Redis 原子预扣 + 快速失败,是应对秒杀式报量性价比最高的第一道防线。
审批是事件源,订单是下游。 让审批通过驱动订单生成,而不是让订单写死在审批事务里,既保住了业务语义,又解耦了两个系统的演化节奏。
结语: 政企集采的"难",往往不在技术新颖,而在如何在老旧链路、强合规和多级组织之间,找到一条既扛得住峰值、又能对账清楚的务实路径。这套分片 + 预扣 + 事件补偿的组合拳,后来也被我们复用到其他几个省级集团的集采项目里。