1. 项目概述:SSM+SpringBoot宠物商城全栈实践
去年带队完成了一个日均PV超10万的宠物用品电商平台,核心采用SpringBoot+Vue技术栈。这个项目让我深刻体会到,现代电商系统开发早已不是简单的CRUD,而是需要在高并发、个性化推荐、支付安全等维度做深度设计。本文将分享从架构设计到性能优化的全链路实战经验,重点解析三个核心问题:如何构建高可用的分布式架构?如何实现毫秒级响应的商品推荐系统?以及如何设计兼顾安全与体验的支付流程?
2. 技术架构设计与选型
2.1 分层架构设计
系统采用经典的三层架构,但在具体实现上做了针对性优化:
- 表现层:Vue 3 + TypeScript实现组件化开发,通过Axios拦截器统一处理JWT令牌刷新
- 业务层:SpringBoot 2.7 + MyBatis-Plus,采用DDD领域驱动设计划分商品、订单等限界上下文
- 数据层:MySQL 8.0分库分表(商品库/订单库分离),Redis 6.2缓存热点数据
特别注意:MySQL连接池推荐使用HikariCP而非Druid,实测在1000并发下HikariCP的TPS高出23%
2.2 关键技术选型对比
| 技术点 | 候选方案 | 最终选择 | 选择理由 |
|---|---|---|---|
| ORM框架 | JPA vs MyBatis | MyBatis-Plus | 需要复杂SQL优化且团队熟悉XML配置 |
| 缓存方案 | Redis vs Memcached | Redis哨兵模式 | 支持更丰富的数据结构且社区活跃度高 |
| 消息队列 | RabbitMQ vs Kafka | RabbitMQ | 订单量级在百万级,RabbitMQ的轻量特性更合适 |
| 前端UI库 | Element vs AntD | Element Plus | 对Vue 3支持更完善,组件API设计更符合国人习惯 |
3. 核心模块实现细节
3.1 商品推荐系统实现
3.1.1 混合推荐算法设计
采用协同过滤(CF)与内容推荐(CB)的混合策略:
java复制// 协同过滤核心代码优化版
public List<Product> hybridRecommend(Long userId) {
// 阶段一:基于用户行为的协同过滤
List<Product> cfItems = userBasedCF.recommend(userId, 50);
// 阶段二:基于商品特征的内容过滤
List<Product> cbItems = contentBasedFiltering.recommend(
userRecentBrowsing.get(userId), 30);
// 阶段三:加权融合与去重
return blendStrategy.blend(cfItems, cbItems)
.stream()
.distinct()
.limit(20)
.collect(Collectors.toList());
}
3.1.2 性能优化方案
- 离线计算:使用Spark MLlib每晚全量更新用户相似度矩阵
- 实时更新:用户行为数据通过RabbitMQ触发增量计算
- 缓存策略:推荐结果按用户ID分片存储Redis,TTL设置2小时
3.2 高并发订单处理
3.2.1 下单流程设计
mermaid复制graph TD
A[库存预占] --> B[风控校验]
B --> C[订单创建]
C --> D[支付通知]
D --> E[库存扣减]
3.2.2 关键技术实现
- 分布式锁:采用Redisson的RLock实现库存操作互斥
java复制RLock lock = redissonClient.getLock("stock_" + skuId);
try {
lock.lock(5, TimeUnit.SECONDS);
// 执行库存操作
} finally {
lock.unlock();
}
- 事务补偿:通过定时任务扫描中间状态订单
- 限流措施:Sentinel配置QPS阈值和熔断降级规则
4. 性能优化实战记录
4.1 数据库优化
4.1.1 索引优化案例
商品表新增联合索引后,搜索性能提升8倍:
sql复制-- 优化前:无索引,执行时间320ms
SELECT * FROM products
WHERE category_id = 5 AND price BETWEEN 100 AND 500;
-- 优化后:添加复合索引(category_id,price)
ALTER TABLE products ADD INDEX idx_cat_price(category_id, price);
-- 执行时间降至40ms
4.1.2 分库分表策略
订单表按用户ID哈希分片:
yaml复制# ShardingSphere配置示例
spring:
shardingsphere:
datasource:
names: ds0,ds1
sharding:
tables:
t_order:
actual-data-nodes: ds$->{0..1}.t_order_$->{0..15}
table-strategy:
inline:
sharding-column: user_id
algorithm-expression: t_order_$->{user_id % 16}
4.2 前端性能提升
- 组件懒加载:路由级代码分割
javascript复制const ProductDetail = () => import('@/views/ProductDetail.vue');
- 图片优化:WebP格式+CDN加速
- 请求合并:GraphQL替代部分REST API
5. 典型问题排查实录
5.1 内存泄漏排查案例
现象:促销期间服务器频繁Full GC
排查过程:
- 使用Arthas的
memory命令观察堆内存 - 发现
ConcurrentHashMap$Node对象异常增长 - 最终定位到本地缓存未设置TTL
解决方案:
java复制// 错误写法
private static Map<Long, Product> cache = new ConcurrentHashMap<>();
// 正确写法
private static Cache<Long, Product> cache = Caffeine.newBuilder()
.maximumSize(10_000)
.expireAfterWrite(5, TimeUnit.MINUTES)
.build();
5.2 分布式事务问题
场景:支付成功但库存未扣减
解决方案:采用RocketMQ事务消息
java复制// 发送半消息
TransactionSendResult sendResult = producer.sendMessageInTransaction(
new Message("order_topic", JSON.toJSONBytes(order)),
null);
// 本地事务执行器
@Override
public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
try {
orderService.processPayment(msg.getBody());
return LocalTransactionState.COMMIT_MESSAGE;
} catch (Exception e) {
return LocalTransactionState.ROLLBACK_MESSAGE;
}
}
6. 安全防护体系
6.1 多层次安全措施
- 传输层:全站HTTPS + HSTS头
- 认证层:JWT签名+短期有效期(30分钟)
- 数据层:敏感字段AES加密存储
- 风控层:基于用户行为的异常检测
6.2 典型防御代码示例
java复制// SQL注入防护
@SqlInjectionSafe
public List<Product> search(String keyword) {
return productMapper.selectList(
new QueryWrapper<Product>()
.like("name", keyword.replace("%", "\\%"))
);
}
// XSS防护
public String sanitize(String input) {
return HtmlUtils.htmlEscape(input);
}
7. 部署与监控方案
7.1 Docker Compose部署
yaml复制version: '3'
services:
redis:
image: redis:6.2-alpine
ports:
- "6379:6379"
volumes:
- redis_data:/data
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: pet@1234
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
volumes:
redis_data:
mysql_data:
7.2 监控体系搭建
- 指标收集:Prometheus + Grafana
- 日志分析:ELK栈(Filebeat收集日志)
- APM工具:SkyWalking追踪调用链
8. 项目演进思考
这个项目从最初单体架构演进到现在的微服务架构,有几个关键决策点值得分享:
- 服务拆分时机:当商品搜索QPS超过2000时才考虑独立搜索服务
- 技术债务管理:建立SonarQube每日扫描机制
- 渐进式演进:先用SpringCloud Alibaba Nacos替代Eureka,再逐步引入Sentinel
在移动端适配过程中,发现Vant UI的瀑布流组件在iOS上有渲染性能问题,最终通过以下方案解决:
javascript复制// 优化图片加载策略
<van-image
lazy-load
:src="item.image"
:options="{ loadingHeight: '200px' }"
/>
宠物电商这类垂直领域项目,最大的挑战其实不在于技术实现,而在于如何平衡用户体验与运营需求。比如在商品详情页,我们经过三次AB测试才确定最优的SKU选择器交互设计。技术人需要时刻记住:任何架构设计和代码优化,最终都要服务于业务价值