去年帮母校计算机系重构跑腿系统时,我发现市面上现有解决方案存在三个致命伤:订单匹配效率低下导致学生等待超时、支付流程繁琐引发纠纷、跑腿员接单体验堪比抢春运火车票。这促使我设计了一套基于Flask+UniApp的全新架构,在三个校区实测中,将平均订单完成时间从47分钟压缩到19分钟。
校园场景的特殊性决定了技术选型必须考虑:
在对比了Django和FastAPI后,最终选择Flask的核心考量:
实测数据:在4核8G服务器上,Flask处理简单订单API的QPS达到387,而Django仅为214。
UniApp的跨平台特性解决了三大痛点:
采用分级缓存策略应对午间订单高峰:
python复制# 订单状态缓存设计示例
def get_order_status(order_id):
# 第一层:内存缓存(时效性要求高的数据)
status = redis.get(f"order:{order_id}:status")
if status:
return status
# 第二层:数据库查询
order = Order.query.get(order_id)
redis.setex(f"order:{order_id}:status", 300, order.status)
return order.status
重要经验:校内WiFi环境下,TCP连接复用比HTTP/2更有效,将keepalive_timeout设置为75秒后,API平均响应时间从210ms降至89ms
按月份分表+热点数据冗余的方案:
sql复制-- 每月创建订单分表
CREATE TABLE orders_202307 (
id BIGINT PRIMARY KEY,
user_id INT NOT NULL,
runner_id INT,
order_type ENUM('express','cafeteria','supermarket') NOT NULL,
status ENUM('pending','accepted','delivering','completed','canceled') NOT NULL,
-- 冗余存储常用查询字段
user_nickname VARCHAR(32),
runner_nickname VARCHAR(32),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB PARTITION BY RANGE (UNIX_TIMESTAMP(created_at)) (
PARTITION p0 VALUES LESS THAN (UNIX_TIMESTAMP('2023-07-16')),
PARTITION p1 VALUES LESS THAN (MAXVALUE)
);
为解决校内建筑遮挡导致的定位漂移,采用MySQL GIS扩展:
sql复制ALTER TABLE users ADD COLUMN location POINT SRID 4326;
CREATE SPATIAL INDEX idx_location ON users(location);
-- 查询500米范围内的跑腿员
SELECT id FROM users
WHERE ST_Distance_Sphere(location, POINT(116.404, 39.915)) <= 500
AND user_type = 'runner';
支付状态机必须包含超时回滚:
mermaid复制stateDiagram-v2
[*] --> UNPAID
UNPAID --> PAID: 支付成功
UNPAID --> CLOSED: 30分钟未支付
PAID --> REFUNDED: 用户申请退款
PAID --> COMPLETED: 跑腿员确认送达
python复制def verify_wechatpay_signature(headers, body):
signature = headers.get('Wechatpay-Signature')
timestamp = headers.get('Wechatpay-Timestamp')
nonce = headers.get('Wechatpay-Nonce')
cert = get_wechatpay_certificate()
message = f"{timestamp}\n{nonce}\n{body}\n"
return cert.verify(signature, message)
| 方案 | 延迟 | 开发成本 | 适用场景 |
|---|---|---|---|
| 轮询 | 高(5s) | 低 | 初期小流量 |
| WebSocket | 低(<100ms) | 中 | 稳定连接环境 |
| 微信订阅消息 | 中(1s) | 高 | 必须用户触达 |
最终采用混合模式:
javascript复制// uni-app端上传示例
uni.uploadFile({
url: 'https://api.example.com/upload',
filePath: tempFilePath,
name: 'file',
formData: {
'scene': 'order'
},
success: (res) => {
this.imageUrl = JSON.parse(res.data).url
}
});
初期方案:
docker-compose复制version: '3'
services:
web:
image: flask-app:v1.2
ports:
- "5000:5000"
depends_on:
- redis
- mysql
生产环境方案:
业务指标:
系统指标:
配置示例:
yaml复制# Prometheus告警规则
groups:
- name: order.alerts
rules:
- alert: HighCancelRate
expr: rate(orders_canceled_total[5m]) / rate(orders_created_total[5m]) > 0.15
for: 10m
微信登录的unionId陷阱:部分学生微信未绑定邮箱时无法获取unionId,必须改用openId+学号绑定方案
接单并发问题:两个跑腿员同时抢单导致状态冲突,最终采用乐观锁解决:
python复制def accept_order(order_id, runner_id):
order = Order.query.filter_by(
id=order_id,
status='pending'
).first()
if order and order.update_status('accepted'):
order.runner_id = runner_id
db.session.commit()
return True
return False
食堂高峰期定位漂移:在建筑密集区增加蓝牙信标辅助定位
支付金额精度问题:必须使用Decimal类型,float会导致分账误差
iOS端下拉刷新冲突:自定义scroll-view组件解决与微信原生冲突
当前正在实施的三个创新功能:
python复制# 简单的推荐算法示例
def recommend_runners(order):
# 基于历史接单记录的协同过滤
similar_orders = Order.query.filter_by(
order_type=order.order_type,
location=order.location
).limit(100).all()
runner_scores = defaultdict(float)
for o in similar_orders:
if o.runner_id and o.rating > 3:
runner_scores[o.runner_id] += o.rating
return sorted(runner_scores.items(), key=lambda x: -x[1])[:5]
这个项目给我的最大启示是:校园场景的技术方案必须平衡先进性和实用性。比如我们曾尝试用Rust重写高性能订单匹配服务,最终发现对团队来说维护成本远大于性能收益。现在我们的技术选型原则是:能用成熟方案解决的,绝不盲目追新。