springcloud实现秒杀系统详细教程

秒杀系统详细教程

1. 项目概述

下载代码 以网上开源仓库seckill_parent为例将项目下载到IDEA里面

1.1 项目简介

这是一个基于Spring Cloud微服务架构的秒杀系统,采用分布式设计,能够应对高并发场景下的商品抢购需求。

1.2 业务特点

  • 瞬时并发量大:大量用户在同一时间抢购,网站流量瞬间激增
  • 库存少:低价限量商品,访问数量远大于库存数量
  • 业务流程简单:流程短,立即购买、下订单、减库存
  • 前期预热:未开启活动时显示倒计时,只能访问不能下单

1.3 技术栈

技术版本说明
JDK1.8Java运行环境
Maven3.5.2项目构建工具
MySQL5.7数据库
Spring Boot2.0.4.RELEASE应用框架
Spring CloudFinchley.M9微服务框架
Redis3.2缓存数据库
RabbitMQ3.7.14消息队列

2. 系统架构设计

2.1 整体架构

┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│   前端页面      │    │   网关服务      │    │   注册中心      │
│   (Client)      │◄──►│   (Zuul)        │◄──►│   (Eureka)      │
└─────────────────┘    └─────────────────┘    └─────────────────┘
                                │
                ┌───────────────┼───────────────┐
                │               │               │
        ┌───────▼──────┐ ┌─────▼─────┐ ┌──────▼──────┐
        │  商品服务    │ │  订单服务  │ │  库存服务   │
        │  (Stock)     │ │  (Order)   │ │ (Storage)   │
        └──────────────┘ └───────────┘ └─────────────┘
                │               │               │
        ┌───────▼──────┐ ┌─────▼─────┐ ┌──────▼──────┐
        │  用户服务    │ │  时间服务  │ │  消息队列   │
        │  (User)      │ │  (Time)    │ │ (RabbitMQ)  │
        └──────────────┘ └───────────┘ └─────────────┘

2.2 微服务模块说明

服务名称端口功能描述
seckill_server9000Eureka注册中心
seckill_zuul8080网关服务,统一入口
seckill_client3000前端页面服务
seckill_stock7000商品服务,管理商品和秒杀政策
seckill_order4000订单服务,处理订单创建和支付
seckill_storage6001库存服务,管理库存扣减
seckill_user5000用户服务,用户管理
seckill_time8000时间服务,提供统一时间

3. 核心功能实现

3.1 秒杀政策管理

3.1.1 数据库设计
-- 秒杀政策表
CREATE TABLE `tb_limit_policy` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `sku_id` bigint(20) NOT NULL COMMENT 'skuid',
  `quanty` bigint(20) DEFAULT NULL COMMENT '数量',
  `price` bigint(20) DEFAULT NULL COMMENT '秒杀价格',
  `begin_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '开始时间',
  `end_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '结束时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
3.1.2 政策创建流程
@Transactional
public Map<String,Object> insertLimitPolicy(LimitPolicy limitPolicy){
    // 1. 参数验证
    if(limitPolicy == null){
        return errorResult("数据传入错误");
    }
    
    // 2. 写入数据库
    int flag = skuDao.insertLimitPolicy(limitPolicy);
    if(flag != 1){
        return errorResult("数据执行失败");
    }
    
    // 3. 计算有效期并写入Redis
    long diff = (end_time.getTime() - now_time.getTime())/1000;
    redisTemplate.opsForValue().set("LIMIT_POLICY_"+sku_id, limitPolicy, diff, TimeUnit.SECONDS);
    
    return successResult();
}

3.2 秒杀订单创建

3.2.1 核心逻辑
public Map<String, Object> createOrder(String sku_id, BigInteger user_id) {
    // 1. 参数验证
    if (sku_id == null || sku_id.equals("")){
        return errorResult("前端又传错了!");
    }
    
    // 2. 从Redis获取秒杀政策
    LimitPolicy limitPolicy = (LimitPolicy) redisTemplate.opsForValue().get("LIMIT_POLICY_"+sku_id);
    if(StringUtils.isEmpty(limitPolicy)){
        return errorResult("活动已经过期!");
    }
    
    // 3. 时间验证
    String now = restTemplate.getForObject("http://localhost:8000/getTime", String.class);
    Date now_time = simpleDateFormat.parse(now);
    if (begin_time.getTime() <= now_time.getTime() && now_time.getTime() <= end_time.getTime()){
        
        // 4. Redis计数器控制并发
        int quanty = limitPolicy.getQuanty().intValue();
        if(redisTemplate.opsForValue().increment("SKU_QUANTY_"+sku_id,1) <= quanty){
            
            // 5. 创建订单对象
            Order order = new Order();
            order.setOrder_id(order_id);
            order.setTotal_fee(skuVo.getPrice());
            order.setActual_fee(limitPolicy.getPrice());
            // ... 设置其他属性
            
            // 6. 写入消息队列
            Map<String,Object> map = new HashMap<>();
            map.put("order", order);
            map.put("orderDetail", orderDetail);
            rabbitTemplate.convertAndSend("order_queue", map);
            
            return successResult(order_id);
        } else {
            return errorResult("商品已经售完了!");
        }
    } else {
        return errorResult("活动已经过期!");
    }
}
3.2.2 关键设计点

1. Redis计数器控制并发

  • 使用redisTemplate.opsForValue().increment("SKU_QUANTY_"+sku_id,1)实现原子性计数
  • 确保只有指定数量的用户可以成功下单

2. 时间服务统一时间

  • 通过独立的时间服务提供统一时间,避免服务器时间不一致问题
  • 使用restTemplate.getForObject("http://localhost:8000/getTime", String.class)获取时间

3. 消息队列异步处理

  • 订单创建后立即返回成功,实际订单写入通过消息队列异步处理
  • 提升用户体验,避免长时间等待

3.3 库存管理

3.3.1 库存扣减流程
// 支付成功后触发库存扣减
public Map<String, Object> payOrder(String order_id, String sku_id){
    // 1. 更新订单状态
    int flag = orderDao.updateOrderStatus(order_id);
    if (flag != 1){
        return errorResult("订单状态更新失败!");
    }
    
    // 2. 发送库存扣减消息
    rabbitTemplate.convertAndSend("storage_queue", sku_id);
    
    return successResult();
}
3.3.2 库存服务监听
@Component
public class StorageListener {
    
    @RabbitListener(queues = "storage_queue")
    public void handleStorageMessage(String sku_id) {
        // 执行库存扣减逻辑
        storageService.decreaseStock(sku_id);
    }
}

4. 缓存策略

4.1 Redis缓存设计

缓存Key数据类型说明
LIMIT_POLICY_{sku_id}String秒杀政策信息
SKU_QUANTY_{sku_id}String商品已售数量计数器
SKU_{sku_id}String商品详细信息

4.2 缓存更新策略

// 政策创建时写入Redis
public void insertLimitPolicy(LimitPolicy limitPolicy) {
    // 计算有效期
    long diff = (end_time.getTime() - now_time.getTime())/1000;
    
    // 写入Redis并设置过期时间
    redisTemplate.opsForValue().set("LIMIT_POLICY_"+sku_id, limitPolicy, diff, TimeUnit.SECONDS);
}

// 政策到期自动删除
// Redis会自动删除过期的key

5. 消息队列应用

5.1 队列设计

队列名称生产者消费者消息内容
order_queue订单服务订单服务订单信息
storage_queue订单服务库存服务商品ID

5.2 消息处理流程

用户下单 → 订单服务 → order_queue → 订单服务监听 → 写入订单表
用户支付 → 订单服务 → storage_queue → 库存服务监听 → 扣减库存

6. 高并发优化策略

6.1 限流策略

  • Redis计数器:使用Redis的原子性操作控制并发数量
  • 时间窗口:通过秒杀政策的开始和结束时间控制访问窗口

6.2 缓存策略

  • 热点数据缓存:商品信息、秒杀政策等热点数据缓存到Redis
  • 计数器缓存:已售数量使用Redis计数器,避免数据库压力

6.3 异步处理

  • 订单异步写入:订单创建后立即返回,实际写入通过消息队列异步处理
  • 库存异步扣减:支付成功后通过消息队列异步扣减库存

6.4 数据库优化

  • 读写分离:查询操作使用缓存,写操作异步处理
  • 分库分表:订单表可以按时间或用户ID分表

7. 部署和启动

7.1 环境准备

  1. 安装JDK 1.8
  2. 安装Maven 3.5.2
  3. 安装MySQL 5.7
  4. 安装Redis 3.2
  5. 安装RabbitMQ 3.7.14

7.2 数据库初始化

# 执行SQL脚本
mysql -u root -p < seckill.sql

7.3 配置文件修改

修改各服务的application.yml文件中的数据库连接信息:

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/seckill?useUnicode=true&characterEncoding=utf8&useSSL=false
    username: your_username
    password: your_password

7.4 启动顺序

  1. 启动注册中心:seckill_server
  2. 启动网关服务:seckill_zuul
  3. 启动各业务服务:seckill_stockseckill_orderseckill_storage
  4. 启动前端服务:seckill_client

7.5 使用启动脚本

# Windows环境
start-all.bat

# 检查服务状态
check-status.bat

# 停止所有服务
stop-all.bat

8. 测试流程

8.1 创建秒杀政策

  1. 访问:http://localhost/seckillClient/page/limitPolicyPage.html
  2. 选择商品,设置秒杀价格、库存、开始时间、结束时间
  3. 点击保存

8.2 用户登录

  1. 访问:http://localhost/seckillClient/page/loginPage.html
  2. 输入用户名密码登录

8.3 商品浏览

  1. 商品列表:http://localhost/seckillClient/page/stockListPage.html
  2. 商品详情:http://localhost/seckillClient/page/stockDetailPage.html?sku_id=xxx

8.4 秒杀下单

  1. 在商品详情页点击"立即抢购"
  2. 确认订单信息
  3. 提交订单

8.5 支付流程

  1. 点击"微信支付"
  2. 系统提示"支付成功"
  3. 库存自动扣减

9. 性能监控

9.1 关键指标

  • QPS:每秒查询数
  • 响应时间:接口响应时间
  • 成功率:秒杀成功率
  • 库存消耗速度:库存扣减速度

9.2 监控点

  • Redis缓存命中率
  • 消息队列积压情况
  • 数据库连接池使用情况
  • 各服务响应时间

10. 扩展优化建议

10.1 技术优化

  • 引入分布式锁:使用Redisson实现分布式锁
  • 引入限流组件:使用Sentinel或Hystrix进行限流
  • 引入监控组件:使用Spring Boot Admin监控应用状态
  • 引入链路追踪:使用Sleuth+Zipkin追踪请求链路

10.2 业务优化

  • 引入防刷机制:限制同一用户重复下单
  • 引入黑名单机制:对恶意用户进行限制
  • 引入库存预热:提前将库存加载到缓存
  • 引入降级机制:系统压力大时进行服务降级

10.3 架构优化

  • 引入CDN:静态资源使用CDN加速
  • 引入负载均衡:使用Nginx进行负载均衡
  • 引入数据库集群:主从复制、读写分离
  • 引入缓存集群:Redis集群提高可用性

11. 常见问题解决

11.1 秒杀超卖问题

问题:库存为负数
解决:使用Redis原子性操作控制并发

11.2 重复下单问题

问题:同一用户重复下单
解决:使用Redis记录用户下单状态

11.3 系统崩溃问题

问题:高并发导致系统崩溃
解决:使用消息队列削峰填谷

11.4 数据一致性问题

问题:缓存与数据库数据不一致
解决:使用消息队列保证最终一致性

12. 总结

本秒杀系统通过以下技术手段实现了高并发场景下的商品抢购:

  1. 微服务架构:服务解耦,独立部署
  2. Redis缓存:热点数据缓存,提升访问速度
  3. 消息队列:异步处理,削峰填谷
  4. 计数器限流:控制并发数量,防止超卖
  5. 时间服务:统一时间,避免时间不一致问题

系统设计充分考虑了秒杀场景的特点,通过多种技术手段保证了系统的高可用性和数据一致性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值