#### redis高并发秒杀测试
> 测试项目: https://github.com/14251104246/redis-demo.git
#### 准备
- 使用`docker-compose`命令启动redis服务器(可以用其他方式启动)
- idea启动测试项目
- jmeter测试脚本
- [高并发秒杀-重现超卖问题.jmx](https://github.com/14251104246/redis-demo/blob/master/src/test/jmeter/%E9%AB%98%E5%B9%B6%E5%8F%91%E7%A7%92%E6%9D%80-%E9%87%8D%E7%8E%B0%E8%B6%85%E5%8D%96%E9%97%AE%E9%A2%98.jmx)
- [高并发秒杀-有事务方式减少库存.jmx](https://github.com/14251104246/redis-demo/blob/master/src/test/jmeter/%E9%AB%98%E5%B9%B6%E5%8F%91%E7%A7%92%E6%9D%80-%E6%9C%89%E4%BA%8B%E5%8A%A1%E6%96%B9%E5%BC%8F%E5%87%8F%E5%B0%91%E5%BA%93%E5%AD%98.jmx)
#### 重现秒杀时出现的超卖问题
- 核心测试代码如下:
```java
/**
* 用于测试redis秒杀
*/
@RestController
@RequestMapping("/api/spike")
@Slf4j
public class SpikeController {
@Resource(name = "stringRedisTemplate")
private StringRedisTemplate stringRedisTemplate;
@Autowired
private RedissonClient redissonClient;
//记录实际卖出的商品数量
private AtomicInteger successNum = new AtomicInteger(0);
@RequestMapping(value = "/initSku", method = RequestMethod.GET)
public String initSku() {
//初始化库存数量
stringRedisTemplate.opsForValue().set("product_sku", "5");
//初始化实际卖出的商品数量0
successNum.set(0);
return "初始化库存成功";
}
/**
* 会出现超卖情况的减少库存方式
* @return
*/
@RequestMapping(value = "/reduceSku", method = RequestMethod.GET)
public String reduceSku() {
Integer sku = Integer.parseInt(stringRedisTemplate.opsForValue().get("product_sku"));
sku = sku - 1;
if (sku < 0) {
return "库存不足";
}
stringRedisTemplate.opsForValue().set("product_sku", sku.toString());
//记录实际卖出的商品数量
return "减少库存成功,共减少" + successNum.incrementAndGet();
}
@RequestMapping(value = "/successNum", method = RequestMethod.GET)
public String successNum() {
return "顾客成功抢到的商品数量:" + successNum.get();
}
}
```
- 测试api:
```
API{初始化库存数量} >> http://127.0.0.1:8090/api/spike/initSku
API{减少库存数量} >> http://127.0.0.1:8090/api/spike/reduceSku
API{查看共减少库存数量} >> http://127.0.0.1:8090/api/spike/successNum
```
- 第一个api用于:初始化库存中的商品数量为5
- 第二个api用于:减少库存1个商品(即客户购买一个商品)
- 第三个api用于:查看用户实际购买的商品
- 少量用户请求的情况展示:
- 首先初始商品库存:http://127.0.0.1:8090/api/spike/initSku
>![image.png](https://upload-images.jianshu.io/upload_images/7176877-569fb412ed3204c6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
- redis数据库中商品库存记录,结果为5
>![image.png](https://upload-images.jianshu.io/upload_images/7176877-3c373cf1058a0da6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
- 查看用户实际购买的商品,结果为0
>![image.png](https://upload-images.jianshu.io/upload_images/7176877-a2019253556b9b5f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
- 客户购买5次商品(调用5次`减少库存数量`api),下面只列出3个图
>![image.png](https://upload-images.jianshu.io/upload_images/7176877-5e210855a352cdb8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
>![image.png](https://upload-images.jianshu.io/upload_images/7176877-3c27d4abc48392c4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
>![image.png](https://upload-images.jianshu.io/upload_images/7176877-cce7dad4d0f446f8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
- 客户继续购买(继续调用`减少库存数量`api)时,会提示库存不足
- 再次查看redis数据库中商品库存记录,结果为0
> ![image.png](https://upload-images.jianshu.io/upload_images/7176877-c2c4f000761a989e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
- 再次查看用户实际购买的商品,结果为5
> ![image.png](https://upload-images.jianshu.io/upload_images/7176877-6afe5f8e1efeef59.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
- 大量用户请求的情况(高并发秒杀)展示
- 首先初始商品库存:http://127.0.0.1:8090/api/spike/initSku
>![image.png](https://upload-images.jianshu.io/upload_images/7176877-569fb412ed3204c6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
- redis数据库中商品库存记录,结果为5
>![image.png](https://upload-images.jianshu.io/upload_images/7176877-3c373cf1058a0da6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
- 查看用户实际购买的商品,结果为0
>![image.png](https://upload-images.jianshu.io/upload_images/7176877-a2019253556b9b5f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
- 使用jmeter打开测试脚本,可以看到基本配置如下
> ![image.png](https://upload-images.jianshu.io/upload_images/7176877-6e396d593cf087c1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
- jmeter并发配置如下(当用户数达到 1000 的时候才开始测试)
> ![image.png](https://upload-images.jianshu.io/upload_images/7176877-f986edb5bb69f971.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
- 点击jmeter的`start`按钮,开始1000个并发请求
- 再次查看redis数据库中商品库存记录,结果为0
> ![image.png](https://upload-images.jianshu.io/upload_images/7176877-c2c4f000761a989e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
- **注意:再次查看用户实际购买的商品,结果超过5,出现超卖情况!!!**
> ![image.png](https://upload-images.jianshu.io/upload_images/7176877-912903c714c61d78.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
#### 超卖问题原因分析
- 从上面测试结果,我们知道,高并发请求`http://127.0.0.1:8090/api/spike/reduceSku`,会出现超卖的情况
- 下面我们看下超卖问题的原因
```
/**
* 会出现超卖情况的减少库存方式
* @return
*/
@RequestMapping(value = "/reduceSku", method = RequestMethod.GET)
public String reduceSku() {
Integer sku = Integer.parseInt(stringRedisTemplate.opsForValue().get("product_sku"));
sku = sku - 1;
if (sku < 0) {
return "库存不足";
}
stringRedisTemplate.opsForValue().set("product_sku", sku.toString());
//记录实际卖出的商品数量
return "减少库存成功,共减少" + successNum.incrementAndGet();
}
```
- 从代码片可以看出,问题原因是库存数量`sku`的读和写操作不在同一个原子操作上,导致类似`不可重复读`的现象。可以类比多线程的问题。
#### 通过redis事务解决超卖问题
##### 使用redis原生的sdk
- 如下改造`reduceSku()`方法,作为一个新接口`http://127.0.0.1:8090/api/spike/reduceSku3`
```
/**
* 加入事务的减少库存方式
* @return
*/
@RequestMapping(value = "/reduceSku3", method = RequestMethod.GET)
public String reduceSku3() {
Jedis jedis = new Jedis("127.0.0.1", 6379);
List<Object> result ;
Transaction transaction = null;
try {
jedis.watch("product_sku");
int sku = Integer.parseInt(jedis.get("product_sku"));
if (sku > 0) {
transaction = jedis.multi();
transaction.set("product_sku", String.valueOf(sku - 1));
// int exp = 1/0;
result = transaction.exec();
if (result == null || result.isEmpty()) {
没有合适的资源?快使用搜索试试~ 我知道了~
spring boot高并发秒杀测试.zip
共33个文件
java:13个
yml:4个
jmx:3个
1.该资源内容由用户上传,如若侵权请联系客服进行举报
2.虚拟产品一经售出概不退款(资源遇到问题,请及时私信上传者)
2.虚拟产品一经售出概不退款(资源遇到问题,请及时私信上传者)
版权申诉
0 下载量 194 浏览量
2024-12-04
14:42:53
上传
评论
收藏 35KB ZIP 举报
温馨提示
redis高并发秒杀测试测试项目https://github.com/14251104246/redis-demo.git准备使用docker-compose启动redis服务器(可以用其他方式命令启动)理念启动测试项目jmeter测试高并发杀-重新超卖问题.jmx高并发秒杀-有事务方式减少库存.jmx删除秒时出现的超卖问题核心测试代码如下/** * 用于测试redis秒杀 */@RestController@RequestMapping("/api/spike")@Slf4jpublic class SpikeController { @Resource(name = "stringRedisTemplate") private StringRedisTemplate stringRedisTemplate; @Autowired private RedissonClient redissonClient; //记录实际卖出的商品数量 private AtomicInteger succ
资源推荐
资源详情
资源评论
收起资源包目录
spring boot高并发秒杀测试.zip (33个子文件)
pom.xml 4KB
标签.txt 29B
doc
表结构和数据.sql 1000B
Jenkinsfile 5KB
src
test
java
com
example
demo
DemoApplicationTests.java 331B
controller
SetControllerTest.java 540B
RedisTest.java 3KB
gatling
user-files
simulations
DemoSimulation.scala 857B
conf
logback.xml 835B
gatling.conf 9KB
jmeter
高并发秒杀-重现超卖问题.jmx 21KB
高并发秒杀-有事务方式减少库存(zSet).jmx 21KB
高并发秒杀-有事务方式减少库存.jmx 21KB
main
resources
application-test.yml 874B
schema.sql 540B
application-dev.yml 2KB
application.yml 661B
data.sql 361B
java
com
example
demo
DemoApplication.java 1KB
controller
SpikeController.java 5KB
SysUserController.java 1KB
SetController.java 2KB
dao
SysUserDao.java 272B
pojo
entity
SysUser.java 815B
service
impl
SysUserServiceImpl.java 884B
SysUserService.java 242B
conf
RedissonConfig.java 3KB
RedisConfig.java 3KB
.idea
.name 4B
redis.yml 132B
Dockerfile 285B
资源内容.txt 733B
README.md 14KB
共 33 条
- 1
资源评论
徐浪老师
- 粉丝: 8317
- 资源: 1万+
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功