一、外卖系统业务场景分析
1.1 核心业务流程
外卖系统是一个典型的O2O(Online to Offline)电商平台,涉及用户、商家、骑手三方角色,核心业务流程包括:
用户下单流程:
- 用户浏览商家列表和菜品
- 选择菜品加入购物车
- 选择收货地址和支付方式
- 提交订单并支付
- 等待商家接单和骑手配送
- 确认收货并评价
商家接单流程:
- 接收新订单通知
- 确认接单并开始制作
- 制作完成通知骑手取餐
- 订单完成或取消
骑手配送流程:
- 抢单或系统派单
- 到店取餐
- 配送至用户
- 完成配送
1.2 业务特点与挑战
高并发:用餐高峰期订单量激增,需要支持大量用户同时下单
实时性:订单状态、骑手位置需要实时更新
数据一致性:库存扣减、订单状态流转需要保证数据一致性
高可用:7×24小时服务,不能出现长时间宕机
可扩展性:支持业务快速扩张,能够水平扩展
二、系统架构设计原则
2.1 设计原则
微服务化:将系统拆分为多个独立的微服务,每个服务负责单一职责
高可用:多节点部署,避免单点故障
可扩展:支持水平扩展,应对业务增长
松耦合:服务间通过API或消息队列通信,降低依赖
容错性:具备熔断、降级、限流等容错机制
2.2 技术选型
后端框架:Spring Boot + Spring Cloud
数据库:MySQL(主从复制)+ Redis(缓存)+ MongoDB(日志)
消息队列:RabbitMQ/Kafka
服务注册与发现:Nacos/Eureka
配置中心:Nacos Config
服务网关:Spring Cloud Gateway
分布式事务:Seata
监控告警:Prometheus + Grafana + ELK
容器化:Docker + Kubernetes
三、系统架构分层设计
3.1 整体架构图
┌─────────────────────────────────────────────────┐
│ 客户端层 │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Web端 │ │ App端 │ │ 小程序 │ │
│ └─────────┘ └─────────┘ └─────────┘ │
└─────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ 网关层 │
│ ┌─────────────────────────────────────────────┐ │
│ │ API Gateway │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │ 认证 │ │ 限流 │ │ 日志 │ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ │ │
│ └─────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ 业务服务层 │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ 用户服务 │ │ 商家服务 │ │ 订单服务 │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ 菜品服务 │ │ 支付服务 │ │ 配送服务 │ │
│ └─────────┘ └─────────┘ └─────────┘ │
└─────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ 数据层 │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ MySQL │ │ Redis │ │ MongoDB │ │
│ └─────────┘ └─────────┘ └─────────┘ │
└─────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ 基础设施层 │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ 监控 │ │ 日志 │ │ 配置 │ │
│ └─────────┘ └─────────┘ └─────────┘ │
└─────────────────────────────────────────────────┘
3.2 微服务拆分
用户服务(user-service):
- 用户注册、登录、个人信息管理
- 收货地址管理
- 用户积分、优惠券管理
商家服务(merchant-service):
- 商家入驻、信息管理
- 店铺管理、营业状态
- 商家统计报表
菜品服务(dish-service):
- 菜品分类管理
- 菜品信息、库存管理
- 菜品评价管理
订单服务(order-service):
- 订单创建、查询、取消
- 订单状态管理
- 订单统计
支付服务(payment-service):
- 支付渠道对接(微信、支付宝)
- 支付回调处理
- 退款处理
配送服务(delivery-service):
- 骑手管理、位置追踪
- 订单分配、抢单
- 配送状态管理
消息服务(message-service):
- 短信、推送通知
- 站内信、系统公告
四、核心业务流程设计
4.1 用户下单流程
时序图:
用户 -> 网关: 提交订单
网关 -> 订单服务: 创建订单
订单服务 -> 菜品服务: 校验库存
菜品服务 -> 订单服务: 库存充足
订单服务 -> 支付服务: 生成支付订单
支付服务 -> 订单服务: 支付订单生成成功
订单服务 -> 用户: 返回支付信息
用户 -> 支付服务: 发起支付
支付服务 -> 订单服务: 支付成功回调
订单服务 -> 菜品服务: 扣减库存
菜品服务 -> 订单服务: 库存扣减成功
订单服务 -> 商家服务: 通知新订单
订单服务 -> 消息服务: 发送订单创建通知
关键代码实现:
// 订单服务 - 创建订单
@Transactional
public OrderDTO createOrder(CreateOrderRequest request) {
// 1. 校验用户信息
UserDTO user = userService.getUserById(request.getUserId());
if (user == null) {
throw new BusinessException("用户不存在");
}
// 2. 校验菜品库存
List<DishStockDTO> stockList = dishService.checkStock(request.getItems());
if (stockList.stream().anyMatch(item -> !item.isSufficient())) {
throw new BusinessException("库存不足");
}
// 3. 生成订单
Order order = buildOrder(request, user);
orderMapper.insert(order);
// 4. 生成支付订单
PaymentOrderDTO paymentOrder = paymentService.createPaymentOrder(order);
// 5. 扣减库存(异步消息)
dishService.reduceStockAsync(request.getItems());
// 6. 发送通知
messageService.sendOrderCreatedMessage(order);
return convertToDTO(order, paymentOrder);
}
4.2 支付回调处理
// 支付服务 - 支付回调
@PostMapping("/callback/{channel}")
public String paymentCallback(@PathVariable String channel,
@RequestBody String body) {
// 1. 验证签名
if (!verifySignature(channel, body)) {
return "fail";
}
// 2. 解析回调参数
PaymentCallbackParam param = parseCallbackParam(channel, body);
// 3. 处理支付结果
if (param.isSuccess()) {
// 支付成功
paymentSuccess(param.getOrderNo(), param.getTradeNo());
} else {
// 支付失败
paymentFail(param.getOrderNo(), param.getFailReason());
}
return "success";
}
private void paymentSuccess(String orderNo, String tradeNo) {
// 1. 更新支付订单状态
paymentOrderService.updateStatus(orderNo, PaymentStatus.SUCCESS, tradeNo);
// 2. 通知订单服务
orderService.paymentSuccess(orderNo);
// 3. 发送支付成功通知
messageService.sendPaymentSuccessMessage(orderNo);
}
五、数据库设计
5.1 核心表结构
用户表(user):
CREATE TABLE `user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '用户ID',
`username` varchar(50) NOT NULL COMMENT '用户名',
`password` varchar(100) NOT NULL COMMENT '密码',
`phone` varchar(20) NOT NULL COMMENT '手机号',
`avatar` varchar(200) DEFAULT NULL COMMENT '头像',
`status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '状态:0-禁用,1-正常',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_username` (`username`),
UNIQUE KEY `uk_phone` (`phone`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
商家表(merchant):
CREATE TABLE `merchant` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '商家ID',
`name` varchar(100) NOT NULL COMMENT '商家名称',
`logo` varchar(200) DEFAULT NULL COMMENT '商家logo',
`address` varchar(200) NOT NULL COMMENT '商家地址',
`phone` varchar(20) NOT NULL COMMENT '联系电话',
`business_hours` varchar(100) DEFAULT NULL COMMENT '营业时间',
`status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '状态:0-未审核,1-审核通过,2-审核拒绝,3-营业中,4-已关闭',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商家表';
菜品表(dish):
CREATE TABLE `dish` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '菜品ID',
`merchant_id` bigint(20) NOT NULL COMMENT '商家ID',
`name` varchar(100) NOT NULL COMMENT '菜品名称',
`description` varchar(500) DEFAULT NULL COMMENT '菜品描述',
`price` decimal(10,2) NOT NULL COMMENT '价格',
`stock` int(11) NOT NULL DEFAULT '0' COMMENT '库存',
`status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '状态:0-下架,1-上架',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_merchant_id` (`merchant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='菜品表';
订单表(order):
CREATE TABLE `order` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '订单ID',
`order_no` varchar(32) NOT NULL COMMENT '订单编号',
`user_id` bigint(20) NOT NULL COMMENT '用户ID',
`merchant_id` bigint(20) NOT NULL COMMENT '商家ID',
`total_amount` decimal(10,2) NOT NULL COMMENT '订单总金额',
`pay_amount` decimal(10,2) NOT NULL COMMENT '实际支付金额',
`status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '订单状态:0-待支付,1-已支付,2-商家接单,3-配送中,4-已完成,5-已取消',
`delivery_address` varchar(200) NOT NULL COMMENT '配送地址',
`remark` varchar(200) DEFAULT NULL COMMENT '备注',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_order_no` (`order_no`),
KEY `idx_user_id` (`user_id`),
KEY `idx_merchant_id` (`merchant_id`),
KEY `idx_create_time` (`create_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单表';
订单明细表(order_item):
CREATE TABLE `order_item` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '订单明细ID',
`order_id` bigint(20) NOT NULL COMMENT '订单ID',
`dish_id` bigint(20) NOT NULL COMMENT '菜品ID',
`dish_name` varchar(100) NOT NULL COMMENT '菜品名称',
`price` decimal(10,2) NOT NULL COMMENT '单价',
`quantity` int(11) NOT NULL COMMENT '数量',
`amount` decimal(10,2) NOT NULL COMMENT '总价',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`),
KEY `idx_order_id` (`order_id`),
KEY `idx_dish_id` (`dish_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单明细表';
5.2 分库分表策略
垂直分库:
- 用户库:user、user_address等表
- 订单库:order、order_item等表
- 商品库:merchant、dish等表
水平分表:
- 订单表按用户ID分表:order_0 ~ order_31
- 订单明细表按订单ID分表:order_item_0 ~ order_item_31
- 使用ShardingSphere实现分库分表
六、缓存设计
6.1 缓存策略
多级缓存架构:
- 本地缓存(Caffeine):热点数据,毫秒级响应
- 分布式缓存(Redis):共享数据,秒级响应
- 数据库:持久化存储
缓存穿透:使用布隆过滤器或缓存空值
缓存击穿:使用互斥锁或永不过期
缓存雪崩:设置不同的过期时间
6.2 缓存应用场景
用户信息缓存:
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Autowired
private RedisTemplate<String, Object> redisTemplate;
private static final String USER_CACHE_KEY = "user:";
private static final long USER_CACHE_TTL = 3600; // 1小时
@Cacheable(value = "user", key = "#id")
public UserDTO getUserById(Long id) {
return userMapper.selectById(id);
}
public UserDTO getUserByIdWithRedis(Long id) {
String key = USER_CACHE_KEY + id;
UserDTO user = (UserDTO) redisTemplate.opsForValue().get(key);
if (user != null) {
return user;
}
user = userMapper.selectById(id);
if (user != null) {
redisTemplate.opsForValue().set(key, user, USER_CACHE_TTL, TimeUnit.SECONDS);
}
return user;
}
}
菜品信息缓存:
@Service
public class DishServiceImpl implements DishService {
@Autowired
private DishMapper dishMapper;
@Autowired
private RedisTemplate<String, Object> redisTemplate;
private static final String DISH_CACHE_KEY = "dish:";
private static final long DISH_CACHE_TTL = 1800; // 30分钟
public DishDTO getDishById(Long id) {
String key = DISH_CACHE_KEY + id;
DishDTO dish = (DishDTO) redisTemplate.opsForValue().get(key);
if (dish != null) {
return dish;
}
dish = dishMapper.selectById(id);
if (dish != null) {
redisTemplate.opsForValue().set(key, dish, DISH_CACHE_TTL, TimeUnit.SECONDS);
}
return dish;
}
@CacheEvict(value = "dish", key = "#id")
public void updateDish(DishDTO dish) {
dishMapper.updateById(dish);
// 清除缓存
String key = DISH_CACHE_KEY + dish.getId();
redisTemplate.delete(key);
}
}
七、消息队列应用
7.1 消息队列选型
RabbitMQ:适合业务消息,支持多种消息模式
Kafka:适合日志、大数据处理,高吞吐量
7.2 消息应用场景
订单创建消息:
@Component
public class OrderCreatedProducer {
@Autowired
private RabbitTemplate rabbitTemplate;
public void sendOrderCreatedMessage(OrderDTO order) {
rabbitTemplate.convertAndSend(
"order.exchange",
"order.created",
order
);
}
}
@Component
public class OrderCreatedConsumer {
@RabbitListener(queues = "order.created.queue")
public void handleOrderCreated(OrderDTO order) {
// 1. 发送短信通知
messageService.sendSms(order.getUserPhone(), "订单创建成功");
// 2. 发送推送通知
pushService.pushToUser(order.getUserId(), "您有新的订单");
// 3. 通知商家
merchantService.notifyNewOrder(order.getMerchantId(), order);
}
}
库存扣减消息:
@Component
public class StockReduceProducer {
@Autowired
private RabbitTemplate rabbitTemplate;
public void sendStockReduceMessage(List<OrderItemDTO> items) {
rabbitTemplate.convertAndSend(
"stock.exchange",
"stock.reduce",
items
);
}
}
@Component
public class StockReduceConsumer {
@RabbitListener(queues = "stock.reduce.queue")
public void handleStockReduce(List<OrderItemDTO> items) {
for (OrderItemDTO item : items) {
dishService.reduceStock(item.getDishId(), item.getQuantity());
}
}
}
八、分布式事务处理
8.1 事务场景
下单事务:
- 创建订单(订单服务)
- 扣减库存(菜品服务)
- 生成支付订单(支付服务)
支付回调事务:
- 更新支付状态(支付服务)
- 更新订单状态(订单服务)
- 发送通知(消息服务)
8.2 解决方案
本地消息表:
@Service
public class OrderServiceImpl implements OrderService {
@Transactional
public void createOrder(CreateOrderRequest request) {
// 1. 创建订单
Order order = buildOrder(request);
orderMapper.insert(order);
// 2. 保存本地消息
LocalMessage message = new LocalMessage();
message.setBizId(order.getId());
message.setTopic("order.created");
message.setContent(JSON.toJSONString(order));
message.setStatus(0);
localMessageMapper.insert(message);
// 3. 发送消息(定时任务扫描发送)
}
}
Seata AT模式:
@GlobalTransactional
public void createOrder(CreateOrderRequest request) {
// 1. 创建订单
orderService.createOrder(request);
// 2. 扣减库存
dishService.reduceStock(request.getItems());
// 3. 生成支付订单
paymentService.createPaymentOrder(request.getOrderNo());
}
九、高可用设计
9.1 服务高可用
多节点部署:每个服务至少部署2个节点
负载均衡:使用Nginx或Spring Cloud Gateway实现负载均衡
服务熔断:使用Hystrix或Sentinel实现熔断降级
服务限流:使用Sentinel实现接口限流
9.2 数据库高可用
主从复制:MySQL主从复制,读写分离
分库分表:使用ShardingSphere实现分库分表
数据库监控:监控慢查询、连接数、锁等待
9.3 缓存高可用
Redis集群:Redis Cluster或Sentinel模式
缓存预热:定时任务预热热点数据
缓存降级:缓存不可用时降级到数据库
十、监控与告警
10.1 监控体系
应用监控:
- JVM监控:堆内存、GC、线程数
- 接口监控:响应时间、QPS、错误率
- 业务监控:订单量、支付成功率
系统监控:
- CPU、内存、磁盘、网络
- 数据库监控:连接数、慢查询
- 缓存监控:命中率、内存使用率
日志监控:
- 错误日志监控
- 业务日志采集
- 链路追踪
10.2 告警配置
应用告警:
- 接口错误率 > 1%
- 响应时间 > 1秒
- JVM内存使用率 > 80%
系统告警:
- CPU使用率 > 80%
- 磁盘使用率 > 85%
- 数据库连接数 > 80%
业务告警:
- 订单创建失败率 > 5%
- 支付失败率 > 3%
- 库存不足告警
十一、安全设计
11.1 数据安全
数据加密:
- 敏感数据加密存储(密码、手机号)
- 传输数据使用HTTPS
- 数据库字段加密
SQL注入防护:
- 使用预编译语句
- 使用MyBatis等ORM框架
- 输入参数校验
11.2 接口安全
认证授权:
- JWT Token认证
- OAuth 2.0授权
- 接口权限控制
防重放攻击:
- 时间戳校验
- 随机数校验
- 签名校验
限流防刷:
- 接口限流
- 验证码校验
- IP黑名单
十二、性能优化
12.1 数据库优化
索引优化:
- 为查询条件字段添加索引
- 避免全表扫描
- 使用覆盖索引
SQL优化:
- 避免SELECT *
- 避免大表JOIN
- 使用分页查询
连接池优化:
- 合理配置连接池参数
- 监控连接泄漏
12.2 缓存优化
热点数据缓存:
- 用户信息、菜品信息缓存
- 订单状态缓存
- 配置信息缓存
缓存预热:
- 定时任务预热热点数据
- 启动时加载配置数据
缓存更新策略:
- 写时更新缓存
- 缓存失效策略
12.3 代码优化
异步处理:
- 非核心业务异步处理
- 使用线程池或消息队列
批量操作:
- 数据库批量插入、更新
- Redis批量操作
对象复用:
- 使用对象池
- 避免频繁创建对象
十三、总结
外卖系统是一个复杂的分布式系统,涉及用户、商家、骑手三方角色,需要处理高并发、实时性、数据一致性等挑战。通过合理的架构设计、技术选型和性能优化,可以构建一个稳定、高效、可扩展的外卖平台。
核心要点:
- 微服务化架构,服务拆分合理
- 数据库分库分表,支持水平扩展
- 多级缓存体系,提升性能
- 消息队列解耦,异步处理
- 分布式事务,保证数据一致性
- 监控告警,保障系统稳定
- 安全防护,保护用户数据
未来演进方向:
- 智能化推荐:基于用户行为推荐菜品
- 动态定价:根据供需关系动态调整价格
- 无人配送:接入无人配送系统
- 大数据分析:用户行为分析、经营分析
通过不断的技术演进和业务创新,外卖系统可以持续为用户提供更好的服务体验。
若内容若侵犯到您的权益,请发送邮件至:platform_service@jienda.com我们将第一时间处理!
所有资源仅限于参考和学习,版权归JienDa作者所有,更多请访问JienDa首页。





