分布式锁场景
在分布式环境下多个操作需要以原子的方式执行
首先启一个springboot项目,再引入复述,依赖包:
org.springframework。启动
spring-boot-starter-data-redis 2.2.2
。发布
以下是一个扣减库存的接口作为例子:
@RestController
公共类IndexController {
@ autowired
私人StringRedisTemplate StringRedisTemplate;
@RequestMapping (“/deduct_stock”)
公共Stirng deductStock () {
int股票=Integer.parseInt (stringRedisTemplate.opsForValue () . get(“股票”));//jedis.get(关键)
如果股票比;0){
int realStock=股票- 1;
stringRedisTemplate.opsForValue.set(“股票”,realStock + ");//jedis.set(键值)
system . out。println(扣减成功,剩余库存:" + realStock + ");其他
} {
System.out.println(扣减失败,库存不足!”);
}
返回“结束”;
}
}
1。单实例应用场景
以上代码使用JMeter压测工具进行调用,设置参数为:
[用户]的线程数量:100
增加周期(秒):0
循环数:2
用单个web调用,结果出现并发问题:
<中心> 中心>
解决方案:加入同步锁(同步)
@RestController
公共类IndexController {
@ autowired
私人StringRedisTemplate StringRedisTemplate;
@RequestMapping (“/deduct_stock”)
公共Stirng deductStock () {
同步(){
int股票=Integer.parseInt (stringRedisTemplate.opsForValue () . get(“股票”));//jedis.get(关键)
如果股票比;0){
int realStock=股票- 1;
stringRedisTemplate.opsForValue.set(“股票”,realStock + ");//jedis.set(键值)
system . out。println(扣减成功,剩余库存:" + realStock + ");其他
} {
System.out.println(扣减失败,库存不足!”);
}
返回“结束”;
}
}
}
2。多实例分布式场景
以上代码,比如有多个应用程序,用nginx做负载均衡,进行同时调用压测
两个程序存在同样的扣减,出现并发现象。
第一个应用扣减结果显示:
<中心> 中心>
第二个应用扣减结果显示:
<中心> 中心>
解决方案:复述的setnx方法(可参考setnx的api)
多个线程setnx调用时,有且仅有一个线程会拿到这把锁,所以拿到锁的执行业务代码,最后释放掉锁,代码如下:
@RestController
公共类IndexController {
@ autowired
私人StringRedisTemplate StringRedisTemplate;
@RequestMapping (“/deduct_stock”)
公共Stirng deductStock () {
字符串lockkey=發ockkey”;
布尔结果=stringRedisTemplate.opsForValue.setIfAbsent (lockkey lockvalue ");//能。setnx
如果(!结果){
返回";
}
int股票=Integer.parseInt (stringRedisTemplate.opsForValue () . get(“股票”));//jedis.get(关键)
如果股票比;0){
int realStock=股票- 1;
stringRedisTemplate.opsForValue.set(“股票”,realStock + ");//jedis.set(键值)
system . out。println(扣减成功,剩余库存:" + realStock + ");其他
} {
System.out.println(扣减失败,库存不足!”);
}
springRedisTemplate.delete (lockkey);
返回“结束”;
}
}
调用200次,压测结果显示还是有问题,只减掉了一部分:
<中心> 中心>
这时,加大压测次数,结果正常了:
第一个应用扣减结果显示:
<中心> 中心>
第二个应用扣减结果显示:
<中心> 中心>
这个只是因为加大了调用次数,执行业务代码需要一点时间,这段时间拒绝了很多等待获取锁的请求。但是,还是有问题,假如复述,服务挂掉了,抛出异常了,这时锁不会被释放掉,出现死锁问题,可以添加试试 抓处理,代码如下:
@RestController