ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

外卖快递网约车三选一:业务下线技术架构与执行路径

外卖快递网约车三选一:业务下线技术架构与执行路径 外卖、快递、网约车三大行业去其一。如果把这个标题放在商业战略讨论里它可能是一道行业选择题但一旦落到技术团队手里它就变成一组非常具体的任务哪条业务线的入口先切流量历史订单怎么归档消息队列要不要暂停结算任务怎么停还有哪些服务在悄悄依赖即将下线的接口。这篇文章只讲技术执行面不判断哪个行业应该被留下也不预测任何一家公司的业务走向。在真实平台中外卖、快递、网约车很少是三套完全独立的系统。它们往往共享账号、支付、地图、消息、营销、风控等基础能力。一条业务线如果确定收缩技术侧不能只删除一个 App 工程还要处理订单、结算、审核、客服、财务、数据分析之间的耦合。尤其是当初没有做业务隔离的团队“去其一”的代价会远高于想象。下面以具备三类履约业务的中台架构为例先拆解三者之间的共性和差异再说明如何用一套底座支撑多条业务线最后给出业务线下线的流量顺序、常见坑、验证方法和生产环境保障。这样无论最终保留哪条业务线至少技术侧的执行路径是清晰的。1. 先看清楚外卖、快递、网约车在系统层面的异同1.1 三类业务本质都是“强时效履约”外卖业务消费者在终端下单商户确认并出餐骑手端收到取餐任务到店取餐后按路线配送最终完成交付。快递业务没有这么直观的“即时感”但它同样会被拆成多个环节揽收、网点交接、干线运输、末端分拣、派送、签收。网约车业务介于两者之间用户在 App 下单司机接单上车开始行程到达后计费结束。从业务视角看这三种模式的商品或服务完全不同。但从系统视角看它们共享同一套骨架用户先下订单系统根据位置和资源分配履约方履约方改变订单状态支付和结算在关键节点触发最后通过消息通知相关方。订单、状态、调度、计费、消息这五个模块在每一条业务线里都存在只是实现细节不同。这就是“强时效履约系统”的本质订单不是创建完就结束而是要经过多个状态并且在每个状态节点上都有超时、取消、异常补偿等分支。设计这类系统时如果一开始就按“外卖专用系统”来写后面接入快递或网约车业务时订单状态机、计费规则、调度策略几乎都要重写。所以先理解共性和差异是后续所有架构决策的基础。1.2 用一张表拆出系统模块的共性与差异对比三类业务时可以从七个维度切入核心角色、核心实体、时效要求、路线计算、计费逻辑、安全合规、典型异常。这样能快速判断哪些模块应该共享哪些必须独立。维度外卖快递网约车核心角色消费者、商户、骑手寄件人、收件人、快递员、网点乘客、司机核心实体订单、商品、配送、结算单运单、包裹、网点、运输批次订单、行程、计费单时效要求分钟级送达小时到天级分钟级接驾路线计算骑行路径需考虑取餐顺序揽收路径、干线规划、末端排线实时路网、ETA、派单区域计费逻辑商品金额配送费包装费优惠首重续重、体积重量、时效增值起步价里程时长动态调价安全与合规食品安全、拿餐确认、售后实名寄递、违禁品识别、签收司乘安全、行程共享、监管报送典型异常超时、取消、撒餐拒收、丢件、延误取消、绕路、费用争议单看表格可能不够。举一个例子同样是“分配履约方”外卖分配的是骑手网约车分配的是司机。看似逻辑相似但骑手一次可能携带多份订单需要规划“先取哪家、再送哪家”的路径司机一次只服务一个乘客派单时判断的是实时供需、司机位置、顺路程度和服务分。这两个策略如果共用同一套实现会出现要么骑手逻辑无法表达要么司机逻辑被迫简化的问题。因此判断“哪些能复用、哪些必须隔离”比决定“用不用中台”更重要。基础服务可以统一领域规则必须分离。例如用户账号、支付、消息推送、地图服务、风控、客服工单可以做成中台订单状态机、调度策略、计费规则、物流节点不能简单合并。1.3 共性能复用差异必须靠配置和扩展点很多平台早期为了快速上线把骑手和司机都抽象成“配送员”在订单表里加一个deliverer_type字段。这种做法在业务量小时能跑但业务一多订单表里会出现大量互斥字段外卖有“商家地址”网约车有“司机评分”快递有“包裹重量”。每个字段只对某一条业务线有意义其他业务线写入时只能置空后续做数据治理非常痛苦。更合理的做法是订单主表只保留公共字段比如订单号、用户ID、业务类型、状态、金额、创建时间把业务差异放到 extension 或子表中。订单主表需要稳定新增业务类型时不需要频繁加列。扩展字段可以用 JSON 存储也可以用独立子表关键是要明确哪个业务线负责读写这些字段。下面是一个简化版订单模型只为了说明主表和扩展的关系{ orderId: 20250101120000001, bizType: TAKEOUT, status: CREATED, userId: u_10086, merchantId: m_2088, amount: 3260, currency: CNY, extension: { takeout: { shopAddress: 北京市朝阳区某商户, deliveryAddress: 北京市海淀区某小区, deliveryFee: 300, expectArriveAt: 2025-01-01 12:30:00 } }, createTime: 2025-01-01 12:00:00 }实际项目中快递运单可能还有批次、包裹列表等子表网约车订单可能还要记录行驶轨迹。主表保持简单子表和扩展表按业务线独立建设。这样下线一条业务线时删除或归档只影响自定义扩展表不会动公共表结构。2. 用“一个底座 多条业务线”承接三选一的架构2.1 共享中台的职责边界如果平台已经有多个业务线常见问题不是“没有中台”而是“中台化得不够干净”。比如订单中心既维护订单主数据又负责调度策略结算中心既算钱又对外提供满减活动消息中心既要发通知又要维护用户触达偏好。职责交叉会让下线操作变得非常痛苦因为无法判断某个模块到底影响了哪些业务。建议按数据归属划分中台边界。用户中心只维护账号身份订单中心只维护订单数据和状态事件调度中心只负责“应该由谁来履约”不关注商品和价格履约中心负责状态推进和异常处理结算中心基于订单事件计算金额和账单。服务之间通过事件或标准 RPC 通信禁止跨层直接查库。常见的共享中台模块包括用户中心统一账号、登录态、注册、实名认证。订单中心维护订单主数据、订单状态、变更事件。调度中心接收订单事件按照业务线策略分配骑手、司机或承运商。履约中心处理接单、取件、送达、签收、取消和异常上报。结算中心计费、优惠分摊、账单、佣金、提现。消息中心订单通知、App 推送、短信、站内信。风控中心设备指纹、频次限制、订单异常、支付风控。数据平台业务明细、ETL、指标计算、报表。这样划分之后“去其一”的影响范围可以被快速圈定。外卖业务线下线只关掉外卖业务线在订单中心、调度中心、履约中心上的业务开关其他服务不需要做大改动。2.2 用订单扩展点区分三类业务订单主表中的bizType是关键字段。上游在创建订单时必须把bizType传清楚后续所有模块都用它来定位业务线配置。调度策略也可以按bizType注册到 Spring 容器中public interface DispatchStrategy { DispatchResult dispatch(DispatchRequest request); } Component(TAKEOUT_DISPATCH) public class TakeoutDispatchStrategy implements DispatchStrategy { Override public DispatchResult dispatch(DispatchRequest request) { // 骑手调度、取餐顺序、骑行路线规划 return null; } } Component(RIDE_DISPATCH) public class RideDispatchStrategy implements DispatchStrategy { Override public DispatchResult dispatch(DispatchRequest request) { // 网约车派单、距离计算、实时供需 return null; } }订单状态机同样可以按bizType配置。例如使用 YAML 管理状态流转state-machine: TAKEOUT: initial: CREATED events: - name: MERCHANT_CONFIRM from: CREATED to: MERCHANT_CONFIRMED - name: DELIVERY_START from: MERCHANT_CONFIRMED to: DELIVERING - name: DELIVERY_DONE from: DELIVERING to: COMPLETED RIDE: initial: CREATED events: - name: DRIVER_ACCEPT from: CREATED to: DRIVER_COMING - name: TRIP_START from: DRIVER_COMING to: TRIP_DURING - name: TRIP_END from: TRIP_DURING to: COMPLETED状态机配置放到配置中心之后下线时只需要禁用TAKEOUT状态机快递和网约车状态机保留。如果状态机逻辑写死在代码里则无法做到按业务线单独控制。2.3 调度与履约策略不要写死在订单服务里如果订单创建服务里直接调用地图、骑手调度或快递网点查询那么订单服务和调度强耦合。后面下线外卖业务线可能连带把地图服务里的计算资源也留错了其他业务线还在用同一个地图服务肉眼很难发现。推荐做法是订单服务只负责写单通过消息或 RPC 发出“待调度”信号。调度中心根据bizType找到对应策略。实现示意// 订单创建后不直接调度只发布事件 orderCreatedEventPublisher.publish(new
返回列表