1. 外卖系统核心架构解析
在餐饮数字化浪潮中,外卖系统已成为连接商家与消费者的关键基础设施。作为参与过多个百万级订单量系统设计的开发者,我将以订单与配送模块为切入点,拆解高并发场景下的典型解决方案。这套系统需要同时满足:300ms内完成订单创建、99.99%的分布式事务成功率、每秒5000+的峰值订单处理能力。
1.1 订单系统核心组件
订单系统的本质是状态机管理,典型状态流转包括:
code复制待支付 → 已支付 → 接单中 → 制作中 → 待取餐 → 配送中 → 已完成
每个状态变更都需要触发相应事件:
- 支付成功事件:触发库存扣减
- 商家接单事件:触发骑手调度
- 订单完成事件:触发结算分账
我们采用领域驱动设计(DDD)划分限界上下文:
- 订单上下文:处理订单生命周期
- 配送上下文:管理骑手调度
- 库存上下文:控制商品库存
- 支付上下文:处理交易流程
1.2 配送系统关键技术
配送系统的核心是实时调度算法,需考虑:
- 骑手实时位置(通过WebSocket推送)
- 餐厅出餐速度预测(基于历史数据)
- 路径规划(集成高德/百度地图API)
- 负载均衡(避免单个骑手接单过多)
典型的技术栈组合:
java复制// 伪代码示例:骑手匹配算法
public Rider matchRider(Order order) {
List<Rider> candidates = riderService.findNearby(
order.getRestaurant().getLocation(),
3, // 3公里范围内
System.currentTimeMillis() - 1800_000 // 30分钟内活跃
);
return candidates.stream()
.min(Comparator.comparingDouble(r ->
calculateDeliveryScore(r, order)))
.orElseThrow(NoRiderAvailableException::new);
}
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 高并发订单处理方案
2.1 订单创建优化
在促销活动期间,我们遇到过创建订单接口RT(响应时间)飙升的问题。通过以下优化手段将TP99从1200ms降至280ms:
-
异步化处理:
- 支付成功后立即返回,后续操作通过消息队列处理
- 使用RocketMQ事务消息保证数据一致性
-
缓存策略:
redis复制# 商品库存缓存方案
SET inventory:1001 50 EX 60 # 商品ID 1001 库存50,60秒过期
DECR inventory:1001 # 原子操作减少库存
- 数据库优化:
- 订单表按用户ID分片(user_id % 16)
- 热点数据使用SSD存储
- 建立组合索引(user_id + create_time)
2.2 分布式事务实践
订单创建涉及多个服务调用,我们采用Saga模式保证最终一致性:
- 支付服务:扣款
- 库存服务:预占库存
- 优惠券服务:核销优惠券
补偿机制设计示例:
java复制// 补偿订单创建
public void compensateOrderCreation(Long orderId) {
try {
paymentService.refund(orderId);
inventoryService.revertDeduction(orderId);
couponService.restoreCoupon(orderId);
orderService.cancel(orderId);
} catch (Exception e) {
// 告警并记录异常,人工介入处理
alertService.notifyAdmin(e);
}
}
3. 配送系统实战细节
3.1 实时调度实现
骑手调度系统的核心指标是ETA(预计到达时间)准确率。我们通过以下方式提升:
-
多维度预测模型:
- 基础ETA = 路径规划时间
- 调整因子:
- 天气系数(雨雪+15%)
- 时段系数(晚高峰+20%)
- 骑手历史准时率
-
动态权重分配算法:
python复制def calculate_priority(order):
base = 100
if order.is_vip: base += 30
if order.wait_time > 30: base += (order.wait_time - 30) * 2
return base - order.distance * 1.5
3.2 轨迹数据处理
骑手轨迹数据采用时空索引存储:
sql复制-- PostgreSQL时空索引示例
CREATE TABLE rider_tracks (
rider_id BIGINT,
geom GEOMETRY(POINT, 4326),
timestamp TIMESTAMPTZ,
SPGIST(geom, timestamp)
);
优化手段:
- 轨迹点抽稀(Douglas-Peucker算法)
- 异常点过滤(速度>30m/s视为GPS漂移)
- 停留点识别(连续5分钟移动<50米)
4. 典型问题排查实录
4.1 订单重复创建
现象:用户点击多次导致重复订单
解决方案:
- 前端防重:提交按钮置灰
- 后端防重:Redis原子锁
java复制// 基于用户ID的防重锁
String lockKey = "order:lock:" + userId;
Boolean locked = redisTemplate.opsForValue()
.setIfAbsent(lockKey, "1", 5, TimeUnit.SECONDS);
if (!locked) throw new ConcurrentOrderException();
4.2 配送超时预警
监控方案:
- 实时计算ETA偏差:
sql复制SELECT order_id,
(actual_time - predict_time) AS delay
FROM deliveries
WHERE status = 'DELIVERING'
AND actual_time - predict_time > 300; -- 延迟5分钟以上
- 自动触发补偿:
- 优先推送附近空闲骑手
- 计算最优接驳点
- 发送优惠券补偿用户
5. 性能优化关键指标
经过多次压测优化,系统达到以下指标:
| 场景 | QPS | 平均RT | 错误率 |
|---|---|---|---|
| 订单创建 | 5,200 | 238ms | 0.01% |
| 支付回调 | 12,000 | 85ms | 0.001% |
| 骑手位置更新 | 8,000 | 45ms | 0.05% |
| 订单状态查询 | 15,000 | 62ms | 0.005% |
优化技巧:
- 支付回调接口使用本地缓存订单数据
- 骑手位置更新采用UDP协议
- 查询接口实现多级缓存(Redis → 内存缓存 → DB)
6. 扩展思考与实践
在实际运营中,我们发现两个值得深入的方向:
- 智能调度升级:
- 引入强化学习模型,训练指标包括:
- 骑手收入均衡度
- 平均配送时长
- 订单取消率
- 使用Ray框架实现分布式训练
- 订单预测系统:
python复制# 使用Prophet预测订单量
from prophet import Prophet
model = Prophet(
seasonality_mode='multiplicative',
yearly_seasonality=False
)
model.fit(train_df)
forecast = model.make_future_dataframe(periods=24, freq='H')
这套系统上线后,某连锁餐厅的订单处理效率提升40%,配送超时率下降65%。关键经验是:在分布式环境下,宁可牺牲部分强一致性,也要保证系统可用性。我们通过完善补偿机制和监控告警,将异常订单的人工处理量控制在0.3%以下。
