2026 年 7 月 22 日 · 阅读时长 12 分钟

从一场活动到一套经营系统:多组织实时交易平台的三年架构实践

本文根据我过去一段远程工作中的项目实践整理。这套系统由我从 0 开始建设,并持续迭代约 3 年。为保护业务与合作方信息,项目名称、品牌、域名、内部接口和部署标识均已泛化。

线下商业活动进入系统后,报名页和直播间只占很小一部分。平台还要处理组织搭建、员工报名、客户邀请、内容互动、商品交易、核销履约、业绩统计、奖励发放和资金结算。平台运营方、活动组织方、入驻经营方、门店、员工与消费者同时参与,每类角色看到的功能不同,最后都要回到同一套组织关系、订单状态和资金记录。

3 年迭代中,平台以「活动」作为业务主轴。活动既定义开始与结束时间,也连接组织、人员、商品、互动、订单、绩效和结算。系统采用 PHP 8 与 Laravel 8 构建模块化单体,通过 Kubernetes 部署。MySQL 保存业务事实,Redis 承担缓存、计数和短期状态,Event、Queue 与 Scheduler 分别处理即时变化、后台任务和时间驱动的状态推进。

活动是组织关系和经营周期的共同坐标

系统中的六类角色分别负责平台治理、活动组织、经营管理、线下履约、客户经营和消费参与。活动 ID 与组织归属把这些角色连接在一起。

角色主要业务
平台运营方管理租户、活动、基础配置、权限和整体运营数据
活动组织方配置活动规则、阶段任务、奖励预算和结算安排
入驻经营方管理商品、门店、员工、订单和本组织业绩
门店承接区域经营、员工归属、线下履约和到店记录
员工邀请客户、参与任务、录入订单并查看个人绩效
消费者报名、互动、参与营销活动、购买商品和领取权益

活动下面关联经营方、门店、员工和消费者,订单继续记录商品、来源员工、归属门店、经营方和活动阶段。一次邀请、浏览或交易进入系统后,可以沿着这些关系回到具体活动、组织和人员。实时排行、阶段绩效、订单归属和最终结算因此使用同一组维度,不需要各自维护一套人员关系。

组织关系解决「这笔业务属于谁」,活动生命周期解决「当前允许做什么」。准备阶段完成组织、商品和内容配置,进行阶段接收互动与交易,阶段结束后计算任务和奖励,整场活动结束后进入财务结算。

支付、充值、核销、奖励和结算都会检查活动或阶段状态。消费者端、员工端和管理后台由此共享同一套时间规则,Scheduler 只负责按时间推进状态,具体业务能否执行仍由应用服务根据当前状态判断。

模块化单体让多个入口复用同一套规则

业务入口分为消费者端、员工端、实时互动端、租户运营后台和平台运营后台。它们拥有独立的路由、中间件、Controller 和展示层,共享活动、组织、订单、资金和统计模型。

接入层识别登录账号、员工身份和消费者身份,并组合活动状态、结算状态与角色权限。Form Request 处理参数校验,API Resource 统一响应结构,Controller 组织调用顺序,不直接承载复杂业务规则。

Service 处理活动、订单、任务和资金规则,Repository 负责排行、统计、筛选和导出,Eloquent Model 保存实体关系与状态。复杂查询离开 Controller 后,同一套统计口径可以同时服务运营后台、员工端和数据导出。

支付、转账、消息、实时通信、媒体存储、地图和安全校验放在适配层。领域服务只依赖稳定的业务动作,外部接口的签名、字段和返回状态留在具体实现中。模块仍运行在同一应用内,但业务入口、领域规则、数据访问与外部能力已有清晰分工。

订单把互动、交易与履约连成一组业务事实

实时互动模块包含房间、消息、商品讲解、礼物、抽奖、红包、勋章、预约和问答。运营人员调整商品状态或顺序时,领域事件通知互动端更新展示;消费者进入房间、发送互动或完成订单后,系统记录对应的活动、商品和人员归属。

商品与权益订单经过身份和活动校验、限购检查、待支付订单创建、支付请求、结果通知、统计更新,以及后续核销或退款。

支付回调先查询本地订单状态。订单已经完成时直接返回当前结果,待支付订单才继续写入支付时间、商品销量、消费者状态和业绩归属。未支付订单由延迟任务释放占用数量,使可售数量跟随订单生命周期变化。

限时抢购、助力、集赞、优惠权益、预存权益、邀请传播、到店和线下签单拥有不同的业务记录,但都会关联活动、消费者、员工、门店和经营方。玩法可以变化,组织归属与订单事实保持稳定,统计层再按活动阶段或组织层级聚合数据。

绩效结算分开记录行为、单位与金额

每场活动可以拆成多个阶段,阶段内分别配置员工任务、经营方任务、奖励预算和绩效规则。浏览、邀请、报名、售卡、互动订单、线下签单和到店等行为进入统计模型,形成个人、经营方、门店和区域排行。

阶段结束后,Scheduler 投递结算任务。系统先统计完成任务的有效奖励单位,再根据阶段奖励池计算单位价值,随后为员工和经营方生成结算结果。剩余预算返回活动资金池,可以继续用于下一阶段。

「行为记录」「任务完成」「奖励单位」和「金额结算」是四种不同事实。进行阶段可以根据行为记录展示进度和预估结果,财务结算使用阶段结束后的最终统计。奖励规则改变时,也不需要覆盖原始行为记录。

资金按用途分池,每次变化都保留流水

活动资金按业务用途分为员工奖励、经营方奖励、推广预算、互动权益和结算资金。充值进入指定资金池,活动阶段从资金池中划定预算,订单、奖励、扣减、提现和结算分别生成对应流水。

关键资金操作使用数据库事务。余额扣减时先锁定资金主体,检查可用金额,再创建业务记录和资金流水,最后更新余额与统计。金额与比例计算使用 BCMath,统一保留业务需要的精度。

check activity lifecycle and operator role
begin transaction
  lock balance or configuration row
  verify available amount and source status
  create order or settlement record
  append money log
  update balance and statistics
commit transaction
dispatch notification or external transfer

流水按员工、经营方和系统资金主体分别保存,并记录活动、阶段、业务类型和金额。余额回答当前还有多少资金,流水解释每次变化,订单和结算记录说明变化对应的业务目的。

提现与结算通过批次任务提交。每条明细拥有独立业务单号和处理状态,后台任务按批次组织请求,再持续查询处理结果。外部转账没有阻塞原始 HTTP 请求,本地记录仍能根据业务单号继续推进和核对。

Event、Queue 与 Scheduler 分担不同时间尺度的工作

同步接口完成身份校验、业务判断和关键数据写入,通知、统计、奖励、批量转账与超时释放进入后台执行。几种机制各自处理一种触发来源。

机制触发来源主要职责
Observer模型变化清理缓存和处理模型关联动作
Event / Listener业务动作传播商品、用户、订单和任务变化
Queue应用投递执行通知、统计、转账和超时任务
Scheduler时间变化推进活动阶段、结算、奖励和数据整理

队列分为高、默认和低三个优先级。交易与阶段结算使用较高优先级,普通通知和统计进入默认或低优先级,不同任务可以按业务时效分配消费资源。

关键调度命令使用单节点执行或防重叠设置,多实例部署时仍只处理一次同一批任务。Event 传播已经发生的业务动作,Queue 执行耗时工作,Scheduler 发起由时间触发的动作。三者最终都重新读取数据库状态,不把消息或缓存中的旧数据当作最终事实。

Redis 服务实时反馈,MySQL 保留统计依据

活动配置、组织名称、员工归属、商品信息和部分统计结果通过统一缓存服务访问。模型数据变化后,Observer 清理对应缓存,下一次读取再从数据库重建。

消息历史、商品计数、在线状态和短期操作次数使用 Redis 数据结构保存。原子增减适合高频计数,列表适合保留有限长度的消息记录,带有效期的键用于活动期间的临时状态。缓存键围绕活动、房间、商品和人员 ID 组织,使不同活动的数据彼此独立。

排行和结算继续以 MySQL 中的业务记录为依据。Redis 提高高频读取和实时反馈的速度,缓存失效或计数需要重建时,Repository 仍能从业务记录恢复结果。

常驻进程要求显式管理请求上下文

HTTP 服务运行在 LaravelS 与 Swoole 的常驻进程模式。框架和服务对象可以跨请求复用,减少重复启动成本,也改变了请求级状态的管理方式。

消费者和员工的登录上下文使用静态状态保存。每次请求进入身份中间件时,系统先清空上一个请求的状态,再写入当前账号和活动身份。身份信息不再依赖 PHP 进程自然退出,而是在中间件中显式重建生命周期。

常驻进程优化的是运行方式,请求隔离仍要由应用保证。登录账号、活动身份和临时业务状态都必须在请求入口初始化,不能让复用的服务对象携带上一次请求的数据。

Kubernetes 支撑直播期间动态扩容

选择 Kubernetes 的直接原因是直播期间的流量变化。活动准备阶段请求相对平稳,直播开始后,用户进入房间、刷新商品、参与互动和提交订单会在短时间内集中发生。Kubernetes 让应用实例可以按实时负载动态调整,不必长期按照直播峰值保留固定容量。

HTTP 常驻服务、Queue Worker 和 Scheduler 复用同一套 Laravel 代码,在运行时承担不同职责:HTTP 服务处理消费者端、员工端与后台请求,Worker 消费分级队列,Scheduler 触发活动状态推进、阶段结算和周期性整理任务。直播流量上升时可以增加处理请求的应用实例,活动结束后再按负载调整容量。

动态扩容要求应用能够在多个实例间保持请求隔离。登录账号与活动身份在每次请求入口重新初始化,订单、资金和活动状态保存在 MySQL,缓存与实时计数放在 Redis。关键调度任务通过单节点执行和防重叠机制避免重复触发,队列任务每次执行前重新读取数据库状态。

Kubernetes 负责容器编排和实例容量,事务、幂等和调度锁继续由应用与数据层保证。扩容改变的是并发处理能力,不改变订单状态、资金流水和阶段结算的判断规则。

从活动平台中留下的工程方法

从 0 建设到持续迭代约 3 年,这套系统先确定了一个稳定的业务坐标。活动 ID 贯穿组织、人员、互动、订单和统计,阶段状态负责时间规则,组织归属负责数据范围。新玩法可以增加自己的记录和规则,不必重新定义人员与业绩关系。

业务事实与实时反馈分别保存。订单、资金流水和行为记录留在 MySQL,Redis 负责缓存、计数和短期状态;同步请求写入关键事实,异步任务继续完成通知、统计和结算。任一后台任务重新执行时,都能根据数据库中的当前状态判断下一步动作。

模块化单体也符合当时的业务关系。多个入口需要共享事务、模型和统计口径,Service、Repository、Event 与适配层先在应用内部形成边界。业务复杂度被放进领域规则和数据关系中,没有因为入口数量增加就提前拆成多个独立服务。

一场活动由此拥有从配置、互动、交易到统计和结算的完整业务轨迹。运营后台、员工端和消费者端面对不同界面,底层使用的是同一组活动状态、组织归属、订单记录与资金流水。

延伸阅读

参考资料

Laravel 运行机制:

数据与并发控制:

CO

我是 Cooper,一名生活在中国的开发者,多年来一直在家远程工作。

主要使用 Go、PHP 和 Rust,从事移动端、Web、跨境支付与资金系统开发。目前主要采用 Vibe Coding 构建产品,并以真实运行结果完成验证与交付。