手把手搭建秒杀系统

目标:

1,实现系统的搭建

2,实现商品页的展示

3,实现防止库存超卖方案一,悲观锁方案

 

  1. 秒杀系统的特点分析

瞬间超高的访问量,QPS达到10万+ 商品数量有限,先到先得 10 100000 有明确的开始和结束时间 8:00 8:30 不能出现超卖 10 100

  1. 方案实现的关键点

1,独立部署,不能影响正常的业务运营(最关键) 2,尽快将请求控制在上游 3,秒杀系统确权,MQ(削峰),订单系统 4,防刷反爬虫 抢购成功,正在生成订单,请稍后.... 10 10000 10 99990 查数据库磁盘 redis内存 JMeter 吞吐量

  1. 创建秒杀系统,项目的结构

 

  1. 引入依赖

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.0.0</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency>

  1. 数据库表新增一个库存字段

ALTER TABLE `t_product` ADD COLUMN `store` bigint NULL AFTER `update_user`;

  1. 配置MySQL数据库及Redis连接信息

server: port: 8080 spring: datasource: url: jdbc:mysql://192.168.77.128:3306/qf-v7 username: java password: java driver-class-name: com.mysql.jdbc.Driver redis: host: 192.168.77.128 password: java1807 mybatis: mapper-locations: classpath:/mapper/*.xml

  1. 实现商品详情页的开发
    1. 引入静态资源
    2. 引入商品详情页模板页面
    3. 开发后台Controller接口,跳转到商品详情页
    4. 创建mapper层及entity层,实现持久化层的开发,商品详情页的数据真实展示
    5. 访问接口:http://localhost:8888/product/getById?id=3
  2. 通过JMeter做压力测试,检测当前系统能扛住的并发量,创建CSV文件

 

 

 

  1. 关键参数说明

Average: 平均响应时间, 单位ms Min: 最小响应时间, 单位ms Max: 最大响应时间, 单位ms Error%: 事务错误率, 一般不高于1% Throughput: 吞吐量, 每秒完成的事务数, 也叫TPS, 也是性能测试很重要的指标, 越大越好, 越大说明系统的处理能力越强 Received KB/sec: 每秒从服务器端接收到的数据量 Sent KB/sec: 每秒向服务器发送的数据量 Avg. Bytes: 平均数据流量,单位是Byte

 

  1. 增加缓存,优化商品详情页的效率

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>

 

在启动类,添加注解

@EnableCaching//开启声明式缓存,利用注解来控制缓存 public class MiaoshaApplication {

 

@Override //value和key构成最终的key //value作为前缀 //key product::1 @Cacheable(value = "product",key = "#id") public TProduct getById(Long id) { return productMapper.selectByPrimaryKey(id); }

清空缓存:FLUSHALL ,重新做压力测试,查看效果,

 

  1. 静态化
  2. 批量生成静态页面,然后将其部署到Nginx上面,观察结果
  3. 静态页面需要的动态数据
    1. 比如评论信息,这个需要通过Ajax发起请求获取到数据
    2. 不过对于秒杀页面,这块数据,我们不需要去获取,此块我们采用降级处理的
    3. 降级处理:保护核心业务(展示商品的基本信息),关掉非核心业务(评论)
    4. 带宽是一个要考虑的现实问题,压缩文件

 

解决超卖问题!!!

版本一:悲观锁解决秒杀库存超卖问题

 

  1. 演示数据库版的超卖问题

service @Override public boolean sale(Long id) { int store = productMapper.getStoreById(id); if(store > 0){ productMapper.updateStoreById(id); return true; } return false; } <select id="getStoreById" parameterType="java.lang.Long" resultType="java.lang.Integer"> select store from t_product where id=#{id,jdbcType=BIGINT} </select> <update id="updateStoreById" parameterType="java.lang.Long"> update t_product set store=store-1 where id=#{id,jdbcType=BIGINT} </update>

  1. 采用悲观锁解决超卖的问题

<select id="getStoreById" parameterType="java.lang.Long" resultType="java.lang.Integer"> select store from t_product where id=#{id,jdbcType=BIGINT} for UPDATE </select> @Override @Transactional public boolean sale(Long id) { int store = productMapper.getStoreById(id); if(store > 0){ productMapper.updateStoreById(id); return true; } return false; }

 

 

 

16,乐观锁

version,高并发的情况下会出现频繁冲突

重试机制

1,基于固定次数,3次

2,基于时间的方式,在一个固定时间段内,100ms


版权声明:本文为qq_44728024原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。