SpringCloud实战:redisson 分布式锁案例

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhuyu19911016520/article/details/84947566

对前面讲解 redisson 实现分布式锁的文章做个补充(上篇文章地址),上篇文章测试的不太准确,本篇将使用jmeter专业测试工具,模拟并发请求
背景:启动 redis,6379端口,SpringCloud微服务,模拟秒杀抢购场景,100库存,用jmeter测试,起300个线程并发请求2次,总计600个请求数,最后查看库存是否为负数,证明分布式锁是否锁住了库存。

  • 注册中心 10025端口
  • 消费者服务 9700端口
  • 秒杀服务 8083、8084,启动2个服务

测试流程如下:

  • 1.启动注册中心,消费者服务与秒杀服务都注册到注册中心
  • 2.启动消费者服务,通过feign 以负载均衡方式调用秒杀服务
  • 3.启动秒杀服务,请求秒杀服务时,修改商品库存,商品库存存储在redis中,默认100
  • 4下面是整体架构图
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    库存设置为100
    在这里插入图片描述

通过jmeter执行http请求,模拟用户抢购
在这里插入图片描述
查看结果,从jmeter上可以看到有600个请求,有13个失败了
在这里插入图片描述
再看redis中的库存,为0,说明锁住了,没有发生超卖现象
在这里插入图片描述

总共测试了多次,贴出有代表性的:

  • 1秒内启动 200线程,循环请求2次,总计400请求,成功了几十个请求,其余请求被hystrix降级返回了
  • 2秒内启动 300线程,循环请求2次,总计600请求,请求全部成功,库存为0
  • 3秒内启动 500线程,循环请求2次,总计1000请求,请求全部成功,库存为0
  • 5秒内启动 1000线程,循环请求2次,总计2000请求,请求全部成功,库存为0
    说明在1秒内启动200个线程并发请求,程序无法处理过来

再贴出秒杀服务的主要代码,注册中心与消费者服务的代码请查看 SpringCloud 实战系列
秒杀服务主要依赖了 redisson 与 netty , 其他都是微服务开发需引入的

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--web 模块-->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
	<groupId>org.redisson</groupId>
	<artifactId>redisson</artifactId>
	<version>3.6.5</version>
</dependency>
<dependency>
	<groupId>io.netty</groupId>
	<artifactId>netty-all</artifactId>
	<version>4.1.25.Final</version>
</dependency>

启动主类的代码如下:

@EnableDiscoveryClient
@SpringBootApplication
public class DistributedLockApplication {
	public static void main(String[] args) {
		SpringApplication.run(DistributedLockApplication.class, args);
	}
	//添加redisson的bean
	@Bean
	public Redisson redisson(){
		Config config = new Config();
		//此示例是单库的,可以是主从、sentinel、集群等模式
		config.useSingleServer().setAddress("redis://localhost:6379");
		return (Redisson)Redisson.create(config);
	}
}

然后是提供秒杀功能的控制器

@RestController
public class IndexController {
    private static String commodityCount = "commodityCount";//商品key
    private static String lockKey = "testRedisson";//分布式锁的key
    @Autowired private StringRedisTemplate redisTemplate;
    @Autowired private Redisson redisson;

    /**
     * 查询是否健康
     * @return
     */
    @RequestMapping(value = "/health" , method = RequestMethod.GET)
    public String health(){
        return "health";
    }

    /**
     * 设置商品数量为100个
     * @param value
     * @return
     */
    @RequestMapping("/setValue")
    public String setValue(int value){
        redisTemplate.opsForValue().set(commodityCount , value + "");
        return "success";
    }

    /**
     * 模拟秒杀抢购,并发200个请求过来,查看是否出现超卖
     * @return
     */
    @RequestMapping("/spike")
    public String spike(){
        String flag = "success";
        RLock lock = redisson.getLock(lockKey);
        try{
            //lock.lockAsync(5 , TimeUnit.SECONDS);
            //lock.lock(5, TimeUnit.SECONDS); //设置60秒自动释放锁  (默认是30秒自动过期)
            Future<Boolean> res = lock.tryLockAsync(100, 5, TimeUnit.SECONDS);
            boolean result = res.get();
            System.out.println("result:" + result);
            if(result){
                int stock = Integer.parseInt(redisTemplate.opsForValue().get(commodityCount).toString());
                if(stock > 0){
                    redisTemplate.opsForValue().set(commodityCount,(stock-1)+"");
                }else{
                    flag = "fail";
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        finally{
            lock.unlock(); //释放锁
        }
        return flag;
    }
}

源码已上传至码云,获取源码

redisson config配置参考:https://github.com/redisson/redisson/wiki/2.-Configuration#261-single-instance-settings

猜你喜欢

转载自blog.csdn.net/zhuyu19911016520/article/details/84947566