一、系统架构设计
1. 整体架构
- 前端层:用户APP/小程序、骑手APP、商家管理端
- 服务层:订单服务、追踪服务、通知服务、地图服务
- 数据层:MySQL(订单主数据)、Redis(实时状态缓存)、MongoDB(轨迹数据)
- 第三方服务:地图API(高德/百度)、短信/推送网关
2. 核心组件
- 订单状态机:定义订单从创建到完成的完整生命周期
- 实时位置服务:骑手位置实时上报与处理
- WebSocket/长连接服务:实现实时推送
- 轨迹存储系统:高效存储和查询骑手移动轨迹
二、订单状态机设计
```mermaid
stateDiagram-v2
[*] --> 待支付
待支付 --> 已取消: 用户取消
待支付 --> 待接单: 支付成功
待接单 --> 配送中: 骑手接单
配送中 --> 已完成: 用户确认收货
配送中 --> 异常处理: 配送问题
异常处理 --> 待接单: 重新分配骑手
异常处理 --> 已完成: 问题解决
```
三、实时追踪实现方案
1. 骑手位置上报
```java
// 骑手APP端定时上报位置示例
public class RiderLocationReporter {
public void reportLocation(String orderId, double latitude, double longitude) {
// 1. 验证骑手与订单关联
// 2. 存储到Redis缓存
redisTemplate.opsForZSet().add("order:" + orderId + ":track",
new GeoLocation(String.valueOf(System.currentTimeMillis()),
new Point(longitude, latitude)), System.currentTimeMillis());
// 3. 存储到MongoDB用于历史轨迹查询
TrackPoint point = new TrackPoint(orderId, riderId, latitude, longitude, new Date());
mongoTemplate.save(point, "order_tracks");
// 4. 通知关联用户
webSocketService.sendOrderUpdate(orderId, "RIDER_LOCATION_UPDATE",
new LocationUpdate(latitude, longitude));
}
}
```
2. 用户端实时获取位置
```javascript
// 前端WebSocket实现示例
const socket = new WebSocket(wss://your-api-domain/order-tracking);
socket.onopen = () => {
socket.send(JSON.stringify({
type: subscribe,
orderId: 123456
}));
};
socket.onmessage = (event) => {
const data = JSON.parse(event.data);
if(data.type === location_update) {
updateMapMarker(data.latitude, data.longitude);
updateEstimatedTime(data.estimatedArrival);
}
};
```
3. 服务器端推送逻辑
```java
// 使用Spring WebSocket实现推送
@ServerEndpoint("/order-tracking")
public class OrderTrackingEndpoint {
private static final Map> orderSubscribers = new ConcurrentHashMap<>();
@OnMessage
public void onMessage(String message, Session session) {
OrderMessage msg = JSON.parseObject(message, OrderMessage.class);
if("subscribe".equals(msg.getType())) {
orderSubscribers.computeIfAbsent(msg.getOrderId(), k -> ConcurrentHashMap.newKeySet()).add(session);
}
}
public static void notifySubscribers(String orderId, Object data) {
Set sessions = orderSubscribers.get(orderId);
if(sessions != null) {
sessions.forEach(session -> {
try {
session.getBasicRemote().sendText(JSON.toJSONString(data));
} catch (IOException e) {
// 处理异常
}
});
}
}
}
```
四、关键技术实现
1. 实时位置处理
- GeoHash编码:将经纬度编码为字符串,便于范围查询
- Redis Geo:使用Redis的GEO类型存储骑手实时位置
- 轨迹压缩:采用Douglas-Peucker算法减少轨迹点存储量
2. 预计到达时间(ETA)计算
```python
简化的ETA计算示例
def calculate_eta(current_location, destination, avg_speed=15):
distance = haversine(current_location, destination) 计算两点距离(km)
time_minutes = (distance / avg_speed) * 60
return max(2, round(time_minutes)) 至少2分钟
```
3. 异常处理机制
- 超时检测:订单在某个状态停留超时自动触发异常处理
- 人工干预:客服可手动修改订单状态
- 自动重试:配送失败后自动重新分配骑手
五、数据存储设计
1. MySQL订单表
```sql
CREATE TABLE orders (
id VARCHAR(32) PRIMARY KEY,
user_id VARCHAR(32) NOT NULL,
rider_id VARCHAR(32),
status ENUM(PENDING, ACCEPTED, PICKED, DELIVERING, COMPLETED, CANCELLED) NOT NULL,
total_amount DECIMAL(10,2) NOT NULL,
create_time DATETIME NOT NULL,
update_time DATETIME NOT NULL,
estimated_arrival DATETIME,
actual_arrival DATETIME,
INDEX idx_status (status),
INDEX idx_user (user_id),
INDEX idx_rider (rider_id)
);
```
2. MongoDB轨迹集合
```javascript
// 轨迹点文档结构
{
"_id": ObjectId("..."),
"orderId": "123456",
"riderId": "rider001",
"location": {
"type": "Point",
"coordinates": [116.404, 39.915] // 经度,纬度
},
"timestamp": ISODate("2023-05-20T10:30:00Z"),
"speed": 12.5, // km/h
"direction": 45 // 方向角度
}
```
六、性能优化措施
1. 位置数据分片:按订单ID或骑手ID分片存储轨迹数据
2. 缓存策略:
- 热门订单状态缓存到Redis
- 骑手当前位置缓存有效期设为15秒
3. 推送限流:同一订单每秒最多推送1次位置更新
4. 异步处理:轨迹存储、通知发送等非实时操作异步化
七、测试方案
1. 单元测试:测试订单状态转换逻辑
2. 集成测试:测试位置上报到用户接收的全链路
3. 压力测试:模拟10万+订单同时追踪的性能
4. 异常测试:测试网络中断、服务宕机等场景下的恢复能力
八、部署方案
1. 容器化部署:使用Docker+Kubernetes实现弹性伸缩
2. 多区域部署:按用户地理位置分区部署追踪服务
3. 监控告警:设置位置更新延迟、推送失败率等关键指标告警
通过以上方案,小象买菜系统可以实现订单全流程的实时追踪,提升用户体验和配送效率。