1. 项目背景与核心价值
同城甜品电商系统是近年来本地生活服务领域的一个热门方向。随着消费升级和懒人经济的兴起,越来越多用户希望通过手机就能订购周边优质甜品店的产品。这个Java开发的网上甜品系统正是瞄准了这一市场需求痛点。
我去年参与过一个类似项目的全流程开发,发现这类系统有几个关键特性:首先是配送时效性要求高,用户通常希望下单后1-2小时内能收到商品;其次是商品展示需要突出视觉吸引力,高质量的图片和视频展示尤为重要;最后是订单波峰特征明显,下午茶时段和周末的流量往往是平时的3-5倍。
2. 系统架构设计
2.1 技术栈选型
后端采用Spring Boot + MyBatis组合,这是经过多个项目验证的可靠方案。Spring Boot的自动配置特性让我们能快速搭建起项目骨架,而MyBatis在复杂SQL查询方面比JPA更灵活。数据库选用MySQL 8.0,利用其JSON字段类型存储甜品的个性化属性(如甜度、配料选择等)。
前端采用Vue.js + Element UI,这个组合在管理端开发中效率很高。为了提升移动端体验,我们额外引入了Vant组件库。特别要说明的是,图片存储没有用常规的OSS服务,而是自建了MinIO集群,这样在用户密集访问热门商品图片时能更好控制CDN成本。
2.2 微服务拆分策略
系统按功能划分为六个微服务:
- 用户服务:处理注册登录、地址管理等
- 商品服务:管理甜品分类、库存、评价等
- 订单服务:处理下单、支付状态跟踪
- 配送服务:对接骑手API和路径规划
- 促销服务:管理优惠券、满减活动
- 通知服务:处理短信、APP推送
这种拆分在初期看似有些过度设计,但在618活动期间,我们能够单独对订单服务和配送服务进行扩容,避免了资源浪费。服务间通信采用RocketMQ消息队列,重要业务操作都实现了本地消息表来保证最终一致性。
3. 核心功能实现细节
3.1 智能推荐模块
甜品推荐算法我们尝试了三种方案:
- 基于内容的推荐:根据用户历史订单中的甜品类别进行推荐
- 协同过滤:找到相似口味偏好的用户群体做推荐
- 实时热度榜:结合近期销量和评价数据
最终采用了一种混合策略 - 首屏展示实时热度榜(用Redis ZSET实现),第二屏展示个性化推荐。这里有个值得分享的细节:甜品推荐需要考虑时段因素,比如上午推荐咖啡搭配的甜点,下午茶时段推荐套餐组合。
3.2 订单超时处理
由于甜品对配送时效要求高,我们设计了严格的超时控制机制:
java复制// 订单状态检查任务
@Scheduled(cron = "0 */5 * * * ?")
public void checkOrderTimeout() {
List<Order> unpaidOrders = orderMapper.selectUnpaidOrders(30);
unpaidOrders.forEach(order -> {
order.setStatus(OrderStatus.CANCELLED);
orderMapper.update(order);
stockService.releaseStock(order.getItems()); // 释放库存
});
List<Order> undeliveredOrders = orderMapper.selectUndeliveredOrders(2);
undeliveredOrders.forEach(order -> {
compensationService.processDelay(order); // 触发延迟补偿
});
}
这里有两个关键参数需要根据业务调整:未支付订单的超时时间(30分钟)和配送超时阈值(2小时)。我们通过A/B测试发现,甜品类的订单支付转化率在20分钟时达到峰值,超过30分钟后几乎不会有支付行为。
4. 性能优化实践
4.1 缓存策略设计
商品详情页采用了多级缓存方案:
- 浏览器缓存静态资源(图片、CSS等)
- CDN缓存热门商品详情页
- Redis缓存商品基础信息(TTL 10分钟)
- 本地缓存(Caffeine)存储价格等敏感信息(TTL 1分钟)
特别注意缓存击穿问题,我们使用Redis的SETNX命令实现了简单的互斥锁:
java复制public ProductDetail getProductDetail(Long id) {
String cacheKey = "product:" + id;
ProductDetail detail = redisTemplate.opsForValue().get(cacheKey);
if (detail == null) {
String lockKey = "lock:" + cacheKey;
if (redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 30, TimeUnit.SECONDS)) {
try {
detail = productMapper.selectDetail(id);
redisTemplate.opsForValue().set(cacheKey, detail, 10, TimeUnit.MINUTES);
} finally {
redisTemplate.delete(lockKey);
}
} else {
// 等待重试或返回降级数据
return getProductDetailFromBackup(id);
}
}
return detail;
}
4.2 数据库优化
订单表做了按月分表处理,使用ShardingSphere实现透明访问。有个容易踩的坑是:甜品订单的查询往往需要关联用户表和商品表,而分片键是订单ID。我们的解决方案是在订单表中冗余了必要的用户和商品信息,虽然增加了存储空间,但使查询效率提升了5倍。
针对商品分类的树形结构查询,采用了闭包表设计模式。相比传统的邻接表,在查询某个分类的所有子分类时,性能从O(n)提升到了O(1):
sql复制CREATE TABLE category_closure (
ancestor BIGINT NOT NULL,
descendant BIGINT NOT NULL,
depth INT NOT NULL,
PRIMARY KEY (ancestor, descendant)
);
5. 运营数据分析
5.1 用户行为埋点
为了优化推荐效果,我们在关键位置添加了埋点:
- 商品曝光(记录展示位置和时段)
- 点击行为(记录从点击到下单的转化路径)
- 购物车操作(添加/删除/结算)
- 支付成功后的满意度评价
这些数据通过Kafka实时传输到Flink计算集群,生成用户画像标签。一个有趣的发现是:工作日下午3-5点的订单中,有62%会同时购买咖啡类饮品,这促使我们推出了"下午茶组合"套餐,使客单价提升了28%。
5.2 库存预测模型
甜品原料的保质期短,库存预测尤为关键。我们基于历史销售数据、天气数据(温度、降水)、节假日信息训练了LSTM预测模型。关键代码如下:
python复制def build_model(input_shape):
model = Sequential()
model.add(LSTM(64, return_sequences=True, input_shape=input_shape))
model.add(Dropout(0.2))
model.add(LSTM(32))
model.add(Dense(1))
model.compile(loss='mse', optimizer='adam')
return model
模型部署后,原料浪费率从15%降到了7%左右。特别要注意的是,甜品销售受天气影响很大,我们在特征工程中加入了未来三天的天气预报数据,这对预测准确率提升非常明显。
6. 安全与风控措施
6.1 防刷单机制
甜品促销活动经常遭遇刷单问题,我们实现了多维度风控规则:
- 设备指纹识别(通过UA、屏幕分辨率等生成)
- 行为模式分析(正常用户浏览路径与机器人的差异)
- 地理位置验证(下单IP与收货地址的距离检测)
- 支付频率限制(同一支付方式在时间窗口内的使用次数)
这些规则通过Drools规则引擎实现,可以在运营后台动态调整阈值。当检测到可疑订单时,系统不会直接拒绝,而是转入人工审核队列,避免误伤真实用户。
6.2 数据安全保护
用户敏感信息(手机号、地址等)采用AES加密存储,密钥由KMS管理。在开发环境,我们使用数据脱敏工具对所有敏感字段进行掩码处理。一个容易忽视的风险是:甜品评价中的图片可能包含地理位置等元信息,我们在图片上传时使用了Apache Commons Imaging库自动清除EXIF信息。
7. 部署与监控方案
7.1 容器化部署
使用Docker + Kubernetes部署微服务,每个Pod都包含主容器和Sidecar容器(用于日志收集和监控)。Jenkins流水线实现了从代码提交到生产环境的全自动部署,关键阶段包括:
- 单元测试(必须100%通过)
- SonarQube代码质量检查
- 构建Docker镜像并推送到Harbor
- 蓝绿部署到K8s集群
为了快速回滚,我们始终保留最近5个版本的镜像。甜品系统的特殊之处在于需要处理大量的图片上传,因此给Nginx Ingress Controller配置了单独的缓存策略。
7.2 监控告警体系
基于Prometheus + Grafana搭建监控系统,除了常规的CPU、内存监控外,我们还特别关注:
- 订单创建成功率(5分钟内的异常波动)
- 平均响应时间(按API端点细分)
- 支付回调超时率
- 库存变更异常(突发的库存减少)
告警通过分级策略发送到不同渠道:P0级问题(如支付系统不可用)直接电话通知负责人,P1级问题(如推荐服务响应变慢)发送企业微信告警,P2级问题(如图片上传失败)记录到值班日志中次日处理。