复购见单系统架构设计与规则引擎实战:从订单草稿到支付履约全链路

发布时间:2026/9/23 7:19:02
复购见单系统架构设计与规则引擎实战:从订单草稿到支付履约全链路
1. 复购见单系统的业务定位与整体设计思路1.1 什么是复购见单它到底解决什么问题复购见单系统说白了就是一套围绕“老客户再次下单”这个动作做全链路管理的业务系统。它跟普通商城订单系统的最大区别在于普通订单系统关注的是“从浏览到支付”的一次性转化而复购见单系统关注的是“这个客户上次买了什么、这次该在什么时间点、以什么价格、通过什么渠道再次触达并成交”。我在实际接触这类项目时最常见的业务背景是快消品、保健品、母婴、宠物用品这类有明确消耗周期的品类。客户买完一单之后系统需要根据商品的使用周期、客户的购买习惯、历史客单价等维度自动生成一张“待确认订单草稿”然后通过业务员、社群、短信或小程序推送给客户客户确认后直接进入支付与履约环节。整个过程的核心不是“卖新客”而是“让老客在正确的时间点再次下单”。这套系统能做的事情包括自动计算复购周期、生成订单草稿、触发触达任务、管理业务员跟单、处理支付回调、驱动仓储履约。适合谁来参考我认为三类人最需要一是正在做私域电商或社群团购的技术负责人二是需要给业务团队搭建跟单工具的产品经理三是想理解订单中台设计思路的后端开发。哪怕你目前只是用表格在管理复购看完这套架构思路也能帮你理清下一步该往哪个方向演进。1.2 为什么不用普通订单系统硬扛复购场景很多人第一反应是我直接在现有订单系统里加一个“复购提醒”不就行了我试过这条路走不通。普通订单系统的数据模型是围绕“用户主动下单”设计的订单状态机是“待支付、已支付、待发货、已发货、已完成”这一条线。而复购见单的核心是“系统先替客户拟一张单客户再确认”这个“草稿态”在普通订单系统里没有位置。更关键的是复购见单需要一套独立的规则引擎来决定“什么时候该给谁推什么商品”。这个规则不是简单的定时任务它要综合客户等级、上次购买时间、商品消耗周期、当前库存、促销活动、业务员归属等多个变量。如果把这些逻辑硬塞进订单系统订单表会被各种冗余字段撑爆后续维护成本极高。所以我的设计思路是复购见单系统独立于交易订单系统但它通过标准接口与订单系统、支付系统、履约系统打通。它自己维护一套“复购计划”和“订单草稿”的数据确认后再把正式订单推给交易系统。这样职责清晰规则引擎可以独立迭代不会影响主交易链路的稳定性。1.3 整体架构分层与核心模块划分这套系统我一般会分成四层来设计。最上面是接入层负责接收来自小程序的客户确认、业务员的跟单操作、运营后台的规则配置。第二层是业务服务层这里面包含三个核心服务规则引擎服务、订单草稿服务、复购计划服务。第三层是基础能力层包括客户画像、商品中心、库存查询、优惠计算这些被复用的能力。最下面是数据层除了常规的关系型数据库还需要一个缓存层来支撑规则引擎的高频计算。核心模块我重点说三个。规则引擎是整个系统的大脑它决定了复购触发的时机和内容。订单草稿服务是系统的双手它负责把规则引擎的计算结果落地成一张可确认、可修改、可支付的草稿单。支付与履约衔接模块是系统的腿它负责在客户确认后把草稿转成正式订单并驱动后续流程。这三个模块的边界一定要划清楚否则后期改一个规则可能要动三个服务的代码。2. 核心架构中的关键技术选型与规则引擎设计2.1 规则引擎为什么不能用if-else硬编码我见过太多项目一开始用if-else写复购逻辑前三个月没问题到第六个月规则数量超过五十条之后代码就变成了没人敢动的“屎山”。复购场景的规则变化非常频繁这个月做“买三送一”下个月改成“第二件半价”不同客户等级看到的复购周期还不一样。如果用硬编码每次调整都要发版业务部门根本等不起。规则引擎的核心价值在于把“业务规则”从“代码逻辑”里抽离出来。我们用一套DSL领域特定语言来描述规则比如“如果客户等级是VIP且距上次购买超过30天且商品A库存大于10则生成商品A的复购草稿”。运营人员在后台配置这段规则引擎实时加载执行不需要重启服务。这就把迭代周期从“按周发版”缩短到了“按分钟配置”。选型上我倾向于用轻量级的规则引擎而不是重型BRMS。原因很简单复购场景的规则复杂度还没到需要完整决策表和工作流的程度引入重型引擎反而增加学习和运维成本。用开源的表达式引擎加上自定义的规则编排层足够覆盖百分之九十的场景。2.2 规则引擎的执行模型与性能考量规则引擎的执行模型我设计成“事实加载、规则匹配、动作执行”三段式。事实加载阶段引擎从客户画像、订单历史、商品库存等数据源拉取当前客户的相关数据组装成一个事实对象。规则匹配阶段引擎遍历所有激活的规则用Rete算法或者简单的条件索引来找出命中的规则。动作执行阶段命中的规则会产出“生成草稿”“发送通知”“更新计划”等动作指令。性能上最大的坑是事实加载。如果每个客户都去查一遍完整的订单历史数据库压力会非常大。我的做法是提前把复购相关的关键指标上次购买时间、累计购买次数、平均客单价、常购商品列表预计算好存到缓存里。规则引擎只读缓存不直接查库。预计算任务在每天凌晨跑一次增量部分通过消息队列实时更新。这样单次规则匹配的耗时可以控制在十毫秒以内。还有一个细节规则匹配的顺序很重要。如果有“互斥规则”比如“已生成草稿的客户不再重复生成”必须把这类规则放在最前面执行命中后直接短路返回避免无效计算。我在规则表里加了一个“优先级”字段数值越小越先执行运营配置时也能直观看到执行顺序。2.3 订单草稿服务的数据模型设计订单草稿服务的数据模型是整个系统里最容易设计错的地方。我踩过的坑是一开始把草稿表设计得跟正式订单表几乎一样结果发现草稿需要频繁修改客户改数量、改地址、换商品每次修改都产生大量历史版本表膨胀得很快。后来我改成“草稿主表草稿明细表草稿变更日志表”的结构。主表只存最核心的字段草稿ID、客户ID、状态、创建来源、过期时间。明细表存商品行变更日志表记录每一次修改的前后值。这样主表很轻查询快明细表可以按需加载变更日志用于审计和问题排查。草稿的状态机我设计了六个状态待生成、待确认、已确认、已转单、已过期、已取消。这里有个关键点草稿必须有“过期时间”。我一般设置七十二小时超过时间未确认的草稿自动过期释放占用的库存预占额度。没有过期机制的话大量僵尸草稿会拖垮库存系统。注意草稿转正式订单的动作必须做幂等。客户可能在网络抖动时重复点击确认如果没有幂等控制会生成两笔正式订单。我的做法是在转单接口用“草稿ID客户ID”做唯一键数据库层面加唯一索引兜底。2.4 支付与履约衔接的接口设计支付与履约衔接这块核心原则是“草稿确认后异步转单支付结果回调驱动履约”。具体流程是客户在草稿页点击确认草稿服务把草稿状态改为“已确认”然后发一条消息到订单创建队列。订单服务消费消息创建正式订单返回订单号给草稿服务草稿状态改为“已转单”。客户接着对正式订单发起支付支付网关回调支付结果履约系统根据支付成功事件开始拣货发货。这里有个容易忽略的点草稿确认和支付之间可能有时间差。客户确认了草稿但过了两小时才支付这期间库存可能被其他人买走。我的处理方式是草稿确认时做“软预占”只记录预占数量不实际扣减正式订单创建时做“硬预占”实际锁定库存支付成功后才真正扣减。如果支付超时硬预占自动释放。这套机制需要在库存服务里支持预占额度的生命周期管理。接口设计上我坚持用“事件驱动补偿对账”的模式。支付成功事件、履约完成事件都通过消息队列异步通知复购系统复购系统更新客户的复购计划比如把下次复购时间往后推一个周期。同时每天跑一次对账任务比对复购系统的草稿状态和订单系统的实际状态发现不一致的自动修复或告警。3. 实操过程与核心环节实现3.1 环境准备与技术栈选型动手搭建之前先把技术栈定下来。我的推荐组合是后端用Spring Boot或者Go的Gin框架规则引擎用Aviator或者QLExpress这类轻量表达式引擎数据库用MySQL 8.0缓存用Redis消息队列用RocketMQ或者Kafka。为什么这么选Spring Boot生态成熟招人容易Aviator性能好且语法简单运营学两天就能上手写规则MySQL 8.0的JSON字段支持让草稿明细的扩展字段很好处理Redis用来做规则事实缓存和分布式锁消息队列保证转单和履约通知的可靠性。部署上规则引擎服务和订单草稿服务建议独立部署不要混在一个进程里。规则引擎是CPU密集型草稿服务是IO密集型混在一起会互相影响。我一般给规则引擎分配4核8G草稿服务2核4G起步后续根据草稿量水平扩展。3.2 规则配置与复购计划生成实操规则配置的实操我拿一个真实场景举例。假设我们要给“购买过婴儿奶粉的客户在购买后第25天推送复购草稿”。在后台配置界面运营人员需要填几个东西规则名称、适用客户群、触发条件、执行动作。触发条件用表达式写就是customer.tags.contains(奶粉客户) daysSince(customer.lastPurchaseTime) 25 customer.lastPurchaseTime ! null。执行动作选择“生成订单草稿”草稿商品选择“客户上次购买的奶粉SKU”数量默认1有效期72小时。配置保存后规则引擎会把这个规则加载到内存。每天凌晨的定时任务扫描所有符合条件的客户批量生成复购计划。这里有个性能优化点不要一条一条生成用批量接口一次处理五百个客户。我实测下来单机每分钟能处理两万个客户的计划生成。复购计划生成后并不是立刻推送给客户。我设计了一个“触达队列”计划先生成到队列里由触达服务根据客户偏好有的客户喜欢短信有的喜欢小程序推送和发送时间窗口避免半夜打扰来实际发送。触达结果会回写到计划表业务员可以在后台看到“已触达待确认”的客户列表方便跟进。3.3 订单草稿的生成、确认与转单全流程草稿生成的动作由规则引擎触发后草稿服务会做几件事。第一校验客户当前是否有未过期的草稿有则跳过避免重复。第二调用商品中心获取最新价格和库存如果库存不足则标记草稿为“库存不足”状态不推送给客户。第三调用优惠计算服务把客户可用的优惠券和促销活动算进去生成最终价格。第四写入草稿主表和明细表状态设为“待确认”。客户在小程序看到草稿后可以修改数量、更换收货地址、使用或取消优惠券。每次修改都走草稿更新接口更新明细并写变更日志。客户点击确认后草稿状态变为“已确认”同时触发转单流程。转单流程我详细说一下。草稿服务发消息到order.create主题消息体包含草稿ID和客户ID。订单服务消费消息先查草稿详情然后调用库存服务做硬预占预占成功后创建正式订单订单状态为“待支付”。订单创建成功后订单服务发消息到order.created主题草稿服务消费后把草稿状态改为“已转单”并记录订单号。如果库存预占失败订单服务发order.create.failed消息草稿服务把草稿状态回滚为“待确认”并通知客户库存不足。提示转单过程中的消息一定要设置重试和死信队列。我遇到过消息队列抖动导致转单消息丢失的情况后来加了本地消息表定时补偿才彻底解决。3.4 支付回调与履约驱动的实现细节支付回调这块核心是保证“支付成功事件”被可靠地传递到复购系统和履约系统。我的做法是支付网关回调支付服务支付服务更新支付单状态后往payment.success主题发消息。复购系统订阅这个消息根据订单号找到对应的草稿更新客户的复购计划把下次复购时间设置为当前时间加上商品消耗周期。履约系统也订阅这个消息开始生成拣货单和发货单。这里有个细节支付成功消息可能重复投递。复购系统在处理时必须做幂等用订单号做唯一键处理过的直接忽略。履约系统同理。我一般会在消息消费端加一张“已处理消息表”记录消息ID和处理时间消费前先查表处理完再写表。虽然多了一次数据库操作但能避免重复发货这种严重问题。履约完成后履约系统发fulfillment.completed消息复购系统订阅后更新复购计划的“上次履约时间”并触发下一次复购周期的计算。这样就形成了一个完整的闭环购买、计算周期、生成草稿、确认、支付、履约、再计算周期。4. 常见问题与排查技巧实录4.1 规则引擎不生效的排查思路规则引擎不生效是最常见的问题我整理了一套排查顺序。第一步确认规则是否处于“启用”状态很多问题是运营配置完忘了点启用。第二步检查规则的生效时间范围有的规则设置了“仅在工作日生效”周末测试自然不触发。第三步看事实数据是否正确加载可以在规则引擎的管理后台查看“最近一次事实快照”确认客户标签、购买时间这些字段有没有值。第四步检查规则表达式的语法Aviator引擎对空值处理比较严格customer.lastPurchaseTime ! null这种判空一定要加。如果以上都没问题那就看规则优先级。我遇到过两条规则互斥高优先级的规则先命中并短路了低优先级的永远不执行。这时候需要调整优先级或者修改短路逻辑。还有一个隐蔽的坑规则引擎缓存了旧版本的规则配置更新后没有刷新缓存。我的做法是配置保存后主动发一条缓存失效消息引擎收到后重新加载。4.2 草稿重复生成与状态不一致的处理草稿重复生成通常有两个原因。一是规则引擎在多个节点上并行执行同一个客户被两个节点同时处理。解决办法是在生成草稿前用Redis分布式锁锁住客户ID锁的过期时间设为规则执行的最大耗时。二是触达队列的消息重复消费客户确认后又收到一条同样的草稿推送。这个在消费端做幂等就能解决。状态不一致的问题更麻烦。我遇到过草稿显示“已转单”但订单系统里查不到订单的情况。排查下来是转单消息发送成功但订单服务消费失败消息进了死信队列没人处理。后来我加了一个对账任务每十分钟扫描一次“已确认超过三十分钟但未转单”的草稿重新触发转单。同时死信队列配置告警有消息进入立刻通知值班人员。下面这张表是我总结的常见问题速查表可以直接拿去用。问题现象可能原因排查动作解决方案规则不触发规则未启用或不在生效时间检查规则状态和生效时段启用规则或调整时段规则不触发事实数据为空查看事实快照修复数据源或加判空草稿重复生成并发执行无锁查生成日志的时间戳加分布式锁草稿重复生成消息重复消费查消息消费记录消费端加幂等草稿已确认未转单转单消息丢失查死信队列补偿任务重新转单支付成功未履约支付消息未消费查支付消息消费位点重置位点或补偿库存预占未释放过期草稿未清理查过期草稿表定时任务清理并释放4.3 高并发场景下的性能瓶颈与优化复购见单系统的高并发场景通常出现在大促期间大量客户同时收到复购推送并集中确认。这时候最大的瓶颈是数据库。草稿表的写入和更新会非常频繁我一般会做几个优化。第一草稿主表和明细表分库分表按客户ID哈希单表控制在五百万行以内。第二草稿的查询走Redis缓存只有写操作才落库。第三转单接口做限流用令牌桶算法控制每秒转单量超出的请求排队等待。规则引擎的性能瓶颈在事实加载。大促期间客户标签和订单历史变化快预计算任务可能跑不过来。我的做法是把预计算改成增量模式只计算当天有订单变化的客户全量计算放在凌晨低峰期。另外规则引擎可以水平扩展多个节点消费同一个客户分片用一致性哈希保证同一客户总是路由到同一节点。还有一个容易被忽略的点消息队列的堆积。大促期间转单消息和支付消息的量可能是平时的几十倍如果消费端处理不过来消息会堆积。我一般会提前扩容消费者实例并且给消息设置过期时间超过二十四小时未消费的消息直接丢弃并记录避免无限堆积拖垮队列。4.4 数据一致性与对账机制的建设经验复购见单系统涉及多个服务的数据变更强一致性很难做到我的策略是“最终一致性对账兜底”。核心思路是每个服务在本地事务里写业务数据的同时往本地消息表写一条待发送消息然后由定时任务扫描本地消息表发送到消息队列。消费端处理成功后回写消息状态。这样即使消息队列故障消息也不会丢。对账机制我设计了三个维度。第一是草稿与订单的对账比对草稿状态和关联订单状态是否匹配。第二是支付与履约的对账比对支付成功的订单是否都生成了履约单。第三是复购计划与客户实际购买行为的对账检查计划的下次复购时间是否合理。对账任务每天凌晨跑发现差异生成告警工单人工介入处理。这套对账机制上线后我们遇到过一次线上问题支付服务升级导致部分支付成功消息格式变了复购系统解析失败。因为对账任务第二天早上发现了差异并告警我们在客户投诉之前就修复了。如果没有对账可能要等到客户打电话来问“为什么付了钱没发货”才发现。4.5 业务员跟单与客户触达的实操心得最后说一个偏业务侧的实操心得。复购见单系统不只是技术系统它还要服务业务员的跟单工作。我在设计业务员后台时重点做了几个功能。第一是“今日待跟进”列表按客户预计复购时间排序业务员打开就知道今天该联系谁。第二是“草稿状态看板”业务员能看到自己名下客户的草稿是待确认、已确认还是已过期方便针对性跟进。第三是“一键提醒”功能业务员点击后给客户发一条模板消息提醒客户确认草稿。触达时机上我实测下来效果最好的是“早上十点和晚上八点”两个时间段。早上十点客户刚上班不久晚上八点客户在家休息这两个时间点的草稿确认率明显高于其他时段。另外触达文案要带具体商品名称和优惠金额比如“您上次购买的XX奶粉已为您预留确认立减20元”比“您有新的复购订单待确认”的点击率高出一倍多。业务员跟单还有一个关键指标是“草稿确认率”。我一般会按业务员维度统计这个指标确认率低的业务员需要培训话术或者调整客户分配。技术系统能做的就是提供数据支撑让管理动作有依据。这套系统跑顺之后我们客户的复购率提升了将近三成业务员的跟单效率也明显提高不用再靠Excel表格手动记录了。