# mall **Repository Path**: zhang-yanning/mall ## Basic Information - **Project Name**: mall - **Description**: 简单的商城功能 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-10-06 - **Last Updated**: 2026-10-06 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 高并发秒杀商城(微服务版) 基于 **SpringBoot 2.7 + Spring Cloud Alibaba + MySQL + Redis + RocketMQ** 的前后端分离秒杀系统,重点实现高并发场景下的秒杀功能。 ## 一、项目结构 ``` e:\mall ├── mall-cloud/ # 后端(Maven 多模块) │ ├── mall-common/ # 公共模块:统一返回/异常/JWT/常量 │ ├── mall-api/ # Feign 接口 + DTO(服务间调用) │ ├── mall-gateway/ # API 网关 :8080(JWT 鉴权 + Redis 限流) │ ├── mall-user/ # 用户服务 :8101(注册/登录/JWT 签发) │ ├── mall-product/ # 商品服务 :8201(缓存防穿透/击穿/雪崩) │ ├── mall-seckill/ # 秒杀服务 :8301(核心:Lua 预扣 + Sentinel + MQ) │ └── mall-order/ # 订单服务 :8401(MQ 消费建单/支付/超时取消) ├── mall-web/ # 前端(Vue3 + Vite + Element Plus) └── sql/mall_init.sql # 数据库初始化脚本(4 个库 + 演示数据) ``` ## 二、环境要求 | 组件 | 版本 | 说明 | |------|------|------| | JDK | 8 / 11 | 后端编译运行 | | Maven | 3.6+ | 后端构建 | | Node.js | 18+ | 前端构建(Vite 5) | | MySQL | 8.x | 4 个业务库 | | Redis | 6.x | 库存预扣 / 缓存 / 限流 / 分布式锁 | | Nacos | 2.x | 注册中心(standalone 模式即可) | | RocketMQ | 4.9+ | 异步下单削峰 | ## 三、启动步骤 ### 1. 初始化数据库 ```bash mysql -uroot -proot < sql/mall_init.sql ``` ### 2. 启动中间件 ```bash # Redis(Windows 可用 Memurai 或 WSL/宝塔) redis-server # Nacos 单机模式 startup.cmd -m standalone # RocketMQ(先启动 NameServer,再启动 Broker) mqnamesrv mqbroker -n 127.0.0.1:9876 ``` ### 3. 启动后端(按需顺序,无强依赖) ```bash cd mall-cloud mvn clean install -DskipTests # 分别启动(或在 IDE 中运行各启动类) cd mall-gateway && mvn spring-boot:run cd mall-user && mvn spring-boot:run cd mall-product && mvn spring-boot:run cd mall-seckill && mvn spring-boot:run cd mall-order && mvn spring-boot:run ``` > 数据库账号密码默认 root/root,在各个服务的 `application.yml` 中修改。 ### 4. 启动前端 ```bash cd mall-web npm install npm run dev # 访问 http://localhost:5173 ``` ## 四、秒杀核心设计 ### 请求链路(层层过滤,DB 只接收真实成交量) ``` 用户请求 │ ▼ Gateway 网关 :8080 ├─ Redis+Lua 固定窗口限流(单 IP 120次/10s,429 快速失败) └─ JWT 鉴权(白名单放行登录/商品/活动浏览) │ ▼ Seckill 秒杀服务 :8301 ├─ ① 秒杀地址加密校验(MD5 动态路径,5 分钟有效,防脚本直刷) ├─ ② 活动时间校验 ├─ ③ Sentinel 限流(seckillExecute QPS=200,超限快速失败) ├─ ④ Redisson 分布式锁库存预热(首次懒加载到 Redis) ├─ ⑤ Redis + Lua 原子脚本:【一人一单 SISMEMBER + 库存 DECR】单线程原子执行 │ └─ 判断 + 扣减一步完成,天然防超卖、防重复购买 └─ ⑥ RocketMQ 异步下单(削峰填谷)——发送失败立即回补 Redis 库存 │ ▼ 两个独立消费组消费同一 Topic ├─ Order 订单服务 :8401 → 建单落库(uk_user_activity 唯一索引兜底一人一单,幂等) └─ Seckill 消费组 → 异步扣减 DB 库存(WHERE available_stock > 0 防超卖 + orderNo 幂等键) │ ▼ 前端轮询 /order/status/{orderNo} 感知下单结果 ``` ### 高并发要点清单 | 问题 | 方案 | 代码位置 | |------|------|----------| | 超卖 | Redis Lua 原子预扣 + DB `available_stock > 0` 条件更新 | `SeckillService` / `SeckillActivityMapper` | | 重复购买 | Lua 内 SISMEMBER 一人一单 + 订单表唯一索引兜底 | `SeckillService` / `OrderCreateConsumer` | | 恶意刷接口 | 秒杀地址加密(每次动态生成,5 分钟有效) | `SeckillService.generatePath` | | 流量洪峰 | 网关 Redis 限流 + Sentinel QPS 限流 + MQ 异步削峰 | `AuthGlobalFilter` / `SentinelConfig` | | 缓存穿透 | 空值缓存(60s) | `ProductService.getById` | | 缓存击穿 | Redisson 分布式锁 + 双重检查 | `ProductService.getById` | | 缓存雪崩 | TTL 加随机值 | `ProductService.getById` | | MQ 重复消费 | 订单唯一键幂等 + orderNo 幂等键 | 两个 Consumer | | MQ 发送失败 | 立即回补 Redis 库存(补偿) | `SeckillService.execute` | | 超时未支付 | 定时任务 15 分钟取消 + Feign 回补库存 | `OrderTimeoutTask` | | 倒计时不同步 | 服务器时间接口校准偏移量 | `/seckill/time` + 前端 time store | ## 五、功能演示 1. 注册并登录账号 2. 首页查看秒杀活动(进行中/未开始倒计时/已结束三种状态) 3. 进入商品详情 → 点击「立即抢购」 - 前端先请求加密地址 → 再发起秒杀 → 轮询订单状态 → 跳转订单页 4. 订单页 15 分钟内点击「支付」完成模拟支付 5. 超时未支付:定时任务自动取消并回补库存 ### curl 压测示例 ```bash # 1. 登录拿 token TOKEN=$(curl -s -X POST http://localhost:8080/api/user/login \ -H 'Content-Type: application/json' \ -d '{"username":"test","password":"123456"}' | sed 's/.*"token":"\([^"]*\)".*/\1/') # 2. 获取秒杀地址 PATH=$(curl -s http://localhost:8080/api/seckill/path/1 -H "Authorization: Bearer $TOKEN" | sed 's/.*"data":"\([^"]*\)".*/\1/') # 3. 执行秒杀 curl -s -X POST "http://localhost:8080/api/seckill/execute?activityId=1&path=$PATH" \ -H "Authorization: Bearer $TOKEN" ``` > 压测建议:JMeter / wrk 模拟多用户并发秒杀。注意网关限流为单 IP 120 次/10s,压测时可在 `mall-gateway` 的 `application.yml` 中调大 `mall.rate-limit.max-count`。 ### 管理端创建活动(演示接口) ```bash curl -X POST http://localhost:8080/api/seckill/activity \ -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \ -d '{"productId":4,"seckillPrice":999.00,"totalStock":100,"startTime":"2026-10-10T10:00:00","endTime":"2026-10-11T10:00:00"}' ``` ## 六、演示数据说明 `sql/mall_init.sql` 预置: - 6 个商品(含图片) - 活动 1、2:进行中(2026-01-01 ~ 2026-12-31 窗口) - 活动 3:未开始(2027 窗口,用于倒计时演示) Redis 库存懒加载:首次秒杀请求会通过分布式锁从 DB 预热库存到 Redis,无需手动预热。