1. 项目概述
"苍穹外卖"作为一款典型的外卖配送系统,其技术架构和业务逻辑涵盖了现代互联网产品的核心要素。这个项目涉及从用户下单到骑手配送的完整闭环,需要处理高并发订单、实时位置追踪、智能派单等复杂场景。在实际开发中,我们团队采用微服务架构解决了传统单体应用在扩展性方面的瓶颈。
特别说明:本文所述技术方案基于常见的外卖系统架构设计,具体实现可能因业务规模和技术选型有所差异。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心架构设计
2.1 微服务拆分策略
我们将系统拆分为以下核心服务模块:
- 用户服务:处理注册登录、会员权益等
- 店铺服务:管理商家信息、菜单数据
- 订单服务:处理下单、支付流程
- 配送服务:负责骑手调度和路线规划
- 评价服务:收集用户反馈
这种拆分方式使得每个服务可以独立部署和扩展,特别是在大促期间可以针对订单服务单独扩容。我们使用Spring Cloud Alibaba作为微服务框架,Nacos作为服务注册中心。
2.2 数据库设计要点
针对外卖业务特点,我们采用了多数据库混合的方案:
- 用户基础数据:MySQL主从架构
- 订单数据:MySQL分库分表(按用户ID哈希)
- 地理位置数据:Redis GEO
- 日志数据:Elasticsearch集群
订单表的设计特别注意了以下字段:
sql复制CREATE TABLE `orders` (
`order_id` varchar(32) NOT NULL COMMENT '雪花算法ID',
`user_id` bigint(20) NOT NULL,
`shop_id` bigint(20) NOT NULL,
`total_amount` decimal(10,2) NOT NULL,
`actual_amount` decimal(10,2) NOT NULL,
`delivery_fee` decimal(10,2) NOT NULL,
`delivery_address` varchar(255) NOT NULL,
`delivery_lng` decimal(10,6) NOT NULL COMMENT '经度',
`delivery_lat` decimal(10,6) NOT NULL COMMENT '纬度',
`status` tinyint(4) NOT NULL COMMENT '0-待支付 1-已接单 2-配送中 3-已完成',
`create_time` datetime NOT NULL,
`update_time` datetime NOT NULL,
PRIMARY KEY (`order_id`),
KEY `idx_user_id` (`user_id`),
KEY `idx_shop_id` (`shop_id`),
KEY `idx_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
3. 关键技术实现
3.1 高并发订单处理
在午高峰时段,系统需要处理每秒上千的订单创建请求。我们采用以下优化方案:
- 前端防抖+按钮禁用:防止用户重复提交
- 订单服务本地缓存店铺状态
- Redis预减库存(Lua脚本保证原子性)
- 消息队列削峰(RocketMQ)
- 数据库批量插入
核心的库存扣减Lua脚本:
lua复制local stock = tonumber(redis.call('GET', KEYS[1]))
if stock >= tonumber(ARGV[1]) then
redis.call('DECRBY', KEYS[1], ARGV[1])
return 1
end
return 0
3.2 实时配送系统
配送系统涉及三个核心算法:
- 骑手匹配算法:基于距离、负载、评分等多维度加权
- 路径规划算法:整合第三方地图API与自定义规则
- ETA预估算法:考虑实时路况和天气因素
我们使用Redis GEO存储骑手位置:
java复制// 更新骑手位置
redisTemplate.opsForGeo().add("rider:location",
new Point(lng, lat),
riderId.toString());
// 查找3公里内的骑手
Circle within = new Circle(lng, lat, Metrics.KILOMETERS.getMultiplier() * 3);
RedisGeoCommands.GeoRadiusCommandArgs args = GeoRadiusCommandArgs.
newGeoRadiusArgs().
includeDistance().
sortAscending();
GeoResults<RedisGeoCommands.GeoLocation<String>> results =
redisTemplate.opsForGeo().radius("rider:location", within, args);
4. 典型问题与解决方案
4.1 分布式事务问题
订单创建涉及多个服务调用:
- 扣减库存(店铺服务)
- 创建订单(订单服务)
- 生成支付单(支付服务)
我们采用Seata的AT模式解决分布式事务:
java复制@GlobalTransactional
public Order createOrder(OrderDTO orderDTO) {
// 1. 扣减库存
shopService.reduceStock(orderDTO);
// 2. 创建订单
Order order = orderMapper.create(orderDTO);
// 3. 创建支付单
paymentService.createPayment(order);
return order;
}
4.2 位置漂移问题
在实际测试中发现,某些安卓设备上报的位置存在明显漂移。解决方案:
- 服务端校验移动速度(超过120km/h视为异常)
- 采用卡尔曼滤波算法平滑轨迹
- 结合基站定位辅助校正
轨迹平滑算法核心代码:
python复制def kalman_filter(z):
# 初始化参数
x = np.matrix([[z[0]], [0]]) # 初始状态(位置,速度)
P = np.matrix([[1, 0], [0, 1]]) # 初始协方差
F = np.matrix([[1, 1], [0, 1]]) # 状态转移矩阵
H = np.matrix([1, 0]) # 观测矩阵
R = 0.1 # 观测噪声
Q = np.matrix([[0.0001, 0], [0, 0.0001]]) # 过程噪声
filtered = []
for i in range(len(z)):
# 预测
x = F * x
P = F * P * F.T + Q
# 更新
y = z[i] - H * x
S = H * P * H.T + R
K = P * H.T / S
x = x + K * y
P = (np.eye(2) - K * H) * P
filtered.append(float(x[0]))
return filtered
5. 性能优化实践
5.1 缓存策略设计
我们采用多级缓存架构:
- 客户端缓存:静态资源CDN加速
- 应用层缓存:Redis集群
- 持久层缓存:MySQL查询缓存
缓存更新策略对比:
| 策略 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| Cache Aside | 实现简单 | 可能短暂不一致 | 读多写少 |
| Write Through | 强一致性 | 写入延迟高 | 配置数据 |
| Write Behind | 写入性能高 | 可能丢失更新 | 日志类数据 |
5.2 JVM调优经验
通过压测发现的典型问题及解决方案:
-
Full GC频繁:
- 调整新生代比例:-XX:NewRatio=2
- 启用G1垃圾回收器:-XX:+UseG1GC
-
OOM问题:
- 限制HTTP请求体大小:spring.servlet.multipart.max-request-size=10MB
- 优化大对象缓存:改用off-heap存储
-
线程阻塞:
- 调整Tomcat线程池:server.tomcat.max-threads=500
- 优化锁粒度:细粒度锁替代全局锁
6. 监控与告警体系
我们建立了完整的监控链路:
- 基础设施层:Prometheus+Node Exporter
- 应用层:SkyWalking全链路追踪
- 业务层:自定义埋点+ELK
关键告警规则示例:
- 订单创建失败率 > 1%(5分钟)
- 平均响应时间 > 2s(15分钟)
- 骑手接单超时率 > 5%(30分钟)
告警分级处理策略:
| 级别 | 响应时间 | 处理方式 |
|---|---|---|
| P0 | 立即 | 电话呼叫+自动回滚 |
| P1 | 15分钟 | 企业微信通知+人工介入 |
| P2 | 1小时 | 邮件通知+次日处理 |
7. 安全防护措施
7.1 常见攻击防护
-
SQL注入:
- 强制使用预编译语句
- 定期SQL审计
-
XSS攻击:
- 全局过滤器转义特殊字符
- CSP内容安全策略
-
刷单风险:
- 设备指纹识别
- 行为模式分析
7.2 数据安全方案
-
敏感数据加密:
- 数据库字段AES加密
- 日志脱敏处理
-
权限控制:
- RBAC模型
- 接口级权限注解
-
传输安全:
- 全站HTTPS
- 敏感接口二次验证
8. 持续交付实践
我们的CI/CD流程包含:
- 代码提交触发SonarQube静态扫描
- 自动化测试(单元测试覆盖率>80%)
- 多环境发布(DEV -> STAGING -> PROD)
- 蓝绿部署减少停机时间
发布检查清单:
- [ ] 数据库变更脚本已审核
- [ ] 回滚方案已准备
- [ ] 相关团队已通知
- [ ] 监控大盘已就绪
- [ ] 流量峰值已避开
9. 项目演进方向
当前架构的改进空间:
- 服务网格化:逐步迁移到Istio架构
- 智能化升级:
- 基于机器学习的动态定价
- 用户画像精准推荐
- 多租户支持:SAAS化改造
技术债务处理优先级:
| 问题类型 | 影响程度 | 解决成本 | 优先级 |
|---|---|---|---|
| 单点故障 | 高 | 中 | P0 |
| 性能瓶颈 | 中 | 高 | P1 |
| 代码坏味 | 低 | 低 | P2 |
在实际开发过程中,我们发现文档的及时更新往往被忽视。建议建立文档与代码的关联机制,确保接口变更时文档自动同步更新。另外,在微服务拆分时,过度拆分会导致运维复杂度剧增,需要根据团队规模找到平衡点。
