1. 跑腿系统核心架构全景图
跑腿系统的技术架构就像城市交通网络,需要同时处理订单流转、人员调度和实时交互三大核心流程。典型的分布式架构包含以下核心模块:
- 用户终端:微信小程序+H5双端适配(覆盖率98%的跑腿场景)
- 业务中台:采用Spring Cloud Alibaba全家桶
- 调度引擎:基于Geohash的网格化调度算法
- 实时通信:WebSocket+MQTT双通道保活
- 数据层:TiDB+Redis+Elasticsearch铁三角组合
这套架构在日均10万订单量级下,API响应时间能稳定控制在200ms以内。特别要说明的是,我们放弃了传统的微服务拆分模式,而是采用"业务域垂直划分"策略,把订单、配送、支付等强关联服务部署在同一Pod内,通过Service Mesh实现内部通信,这样减少了30%的网络开销。
2. 订单生命周期全链路解析
2.1 智能订单分发机制
当用户在小程序提交订单时,系统会经历这样的处理链条:
-
预检阶段:
- 通过LBS获取用户坐标(WGS84坐标系)
- 调用风控服务检查异常订单模式
- 预计算基础服务费(基于动态定价模型)
-
智能匹配阶段:
java复制// 伪代码展示核心匹配逻辑 List<Courier> matchCouriers(Order order) { // 1. 获取5km内空闲骑手 Set<String> geoHashes = GeoHashUtil.getAdjacent(order.getLat(), order.getLng(), 5); List<Courier> candidates = courierDao.queryActiveInGeoHashes(geoHashes); // 2. 过滤具备接单资质的骑手 candidates = filterByQualification(candidates, order.getType()); // 3. 基于多维度评分排序 return sortByScore(candidates, order); }
评分模型包含7个维度:距离系数、历史接单率、准时率、交通工具类型、当前负载、用户评价、特殊技能(如能搬运大件物品)。每个维度都经过Z-Score标准化处理,最终加权得出匹配度分数。
2.2 状态机引擎设计
订单状态流转采用状态机模式,这是核心状态定义:
mermaid复制stateDiagram-v2
[*] --> PENDING
PENDING --> PAID: 支付成功
PAID --> ALLOCATING: 开始分配骑手
ALLOCATING --> WAITING_TAKE: 分配成功
WAITING_TAKE --> DELIVERING: 骑手取件
DELIVERING --> COMPLETED: 送达确认
COMPLETED --> [*]
state 异常流程 {
PENDING --> CANCELED: 用户取消
PAID --> REFUNDING: 超时未分配
ALLOCATING --> REALLOCATING: 骑手拒单
WAITING_TAKE --> FAILED: 取件超时
}
我们采用Cola StateMachine框架实现,关键配置如下:
xml复制<states>
<state id="PENDING" desc="待支付"/>
<state id="PAID" desc="已支付"/>
<!-- 其他状态省略 -->
</states>
<transitions>
<transition event="pay_success"
source="PENDING"
target="PAID"
condition="#{riskService.check(order)}"/>
<!-- 其他转换规则省略 -->
</transitions>
3. 配送调度算法深度优化
3.1 实时路径规划方案
骑手接单后,系统会生成动态路径规划:
-
取件路径:基于实时路况的A*算法优化
- 整合高德API的实时交通数据
- 考虑电动车/步行等不同出行方式
- 加入商家备餐时间预测因子
-
配送路径:采用遗传算法批量优化
- 当骑手有多个订单时自动合并路线
- 动态权重调整(时效性vs距离)
- 禁行区域自动避让策略
实测数据显示,这套算法使平均配送时长缩短了18%,特别是在雨雪天气等异常情况下表现更为突出。
3.2 负载均衡策略
为避免骑手接单不均,我们设计了分级负载控制:
| 负载等级 | 接单上限 | 调度策略 |
|---|---|---|
| 空闲(<3单) | 5单 | 优先分配高价值订单 |
| 正常(3-5单) | 3单 | 平衡距离和收益 |
| 繁忙(>5单) | 1单 | 仅分配顺路订单 |
同时引入"热区动态扩容"机制:当某区域订单密度超过阈值时,自动触发:
- 提高该区域订单报价15%
- 向周边3km骑手推送激励通知
- 临时放宽接单限制
4. 核心业务表结构设计
4.1 订单主表关键字段
sql复制CREATE TABLE `orders` (
`id` bigint NOT NULL COMMENT '雪花算法ID',
`order_no` varchar(32) NOT NULL COMMENT '业务订单号',
`user_id` bigint NOT NULL,
`courier_id` bigint DEFAULT NULL,
`status` varchar(20) NOT NULL COMMENT '状态机状态',
`from_address` json NOT NULL COMMENT 'JSON结构存储地址组件',
`to_address` json NOT NULL,
`expect_time` datetime NOT NULL COMMENT '期望送达时间',
`actual_time` datetime DEFAULT NULL,
`distance` int DEFAULT NULL COMMENT '米为单位',
`dynamic_price` decimal(10,2) NOT NULL COMMENT '动态计算的总价',
`pay_channel` varchar(20) DEFAULT NULL,
`cancel_reason` varchar(100) DEFAULT NULL,
`version` int NOT NULL DEFAULT '0' COMMENT '乐观锁版本',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_order_no` (`order_no`),
KEY `idx_user` (`user_id`),
KEY `idx_courier` (`courier_id`),
KEY `idx_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
4.2 配送轨迹存储方案
采用时空分离的存储策略:
- 实时位置:Redis Geo存储,5秒更新一次
- 历史轨迹:MongoDB分片集群,按骑手ID分片
- 统计轨迹:每天凌晨压缩后存入HBase
轨迹点数据结构示例:
json复制{
"courierId": 123456,
"timestamp": 1659326400000,
"location": {
"type": "Point",
"coordinates": [116.404, 39.915]
},
"accuracy": 5.2,
"speed": 12.3,
"battery": 78,
"orderId": 789012
}
5. 异常处理与容灾设计
5.1 订单超时处理流程
我们建立了三级超时预警机制:
-
分配超时(5分钟未接单):
- 自动转入二级调度池
- 触发区域广播通知
- 启动溢价策略(+10%)
-
取件超时(接单后15分钟):
- 自动联系商家确认备餐状态
- 骑手APP触发强提醒
- 系统建议改派路线
-
配送超时(预计到达前10分钟):
- 向用户发送延迟通知
- 启动骑手位置共享
- 计算新的ETA并更新
5.2 分布式事务方案
对于支付-接单这个关键路径,我们采用Saga模式:
java复制// 订单服务
@SagaStart
public void handleOrderPaid(OrderPaidEvent event) {
// 1. 更新订单状态
orderService.updateStatus(event.getOrderId(), PAID);
// 2. 触发骑手匹配
dispatchService.startDispatch(event.getOrderId());
// 3. 设置超时补偿
timeoutService.setTimeoutCheck(event.getOrderId());
}
// 补偿逻辑
@SagaCompensate
public void compensateOrderPaid(OrderPaidEvent event) {
// 1. 回退订单状态
orderService.updateStatus(event.getOrderId(), PAY_FAILED);
// 2. 触发退款流程
paymentService.refund(event.getPaymentId());
}
6. 性能优化实战技巧
6.1 地理查询优化
原始方案存在的问题:
- 频繁调用Redis GEO命令导致CPU飙升
- 多边形区域判断消耗大量计算资源
优化后的方案:
- 采用Geohash预处理:
- 将城市划分为L6级网格(约1.2km×0.6km)
- 预计算商家-网格映射关系
- 建立双层缓存:
- 本地缓存:Caffeine存储热点区域骑手列表
- Redis缓存:过期时间动态调整(高峰期5s→30s)
优化效果:
- GEO查询耗时从平均45ms降至8ms
- Redis CPU使用率下降60%
6.2 订单列表查询优化
典型的分页查询场景存在深度分页问题:
sql复制-- 反例(性能差)
SELECT * FROM orders
WHERE user_id = 123
ORDER BY create_time DESC
LIMIT 10000, 20;
我们的解决方案:
- 采用游标分页:
java复制public Page<Order> queryByCursor(Long userId, Long lastId, int size) { return orderDao.query(""" SELECT * FROM orders WHERE user_id = :userId AND id < :lastId ORDER BY id DESC LIMIT :size """, Params.of("userId", userId) .add("lastId", lastId) .add("size", size)); } - 增加联合索引:
sql复制ALTER TABLE orders ADD INDEX idx_user_time (user_id, create_time, id);
7. 安全防护体系
7.1 防刷单机制
我们建立了多维度的风控规则引擎:
| 规则类型 | 检测指标 | 处置措施 |
|---|---|---|
| 频次控制 | 同一设备5分钟内下单≥3次 | 强制人脸验证 |
| 位置异常 | 下单IP与GPS距离>50km | 人工审核 |
| 价格波动 | 订单金额突增300% | 冻结支付 |
| 骑手关联 | 同一WiFi下用户与骑手 | 隔离派单 |
7.2 数据加密方案
敏感数据采用分层加密策略:
-
传输层:
- 全站HTTPS+HTTP/2
- 敏感接口额外启用国密SM2
-
存储层:
- 用户隐私数据:AES-256+GCM模式
- 支付凭证:HSM硬件加密
- 轨迹数据:脱敏后存储(保留GeoHash前4位)
-
日志处理:
java复制@LogMask public class UserDTO { @MaskField(type=MaskType.NAME) private String realName; @MaskField(type=MaskType.MOBILE) private String phone; }
这套安全体系成功防御了日均3000+次的恶意请求,保障了系统稳定运行。