六 Redis分布式锁实战

一 redis设置值存在的问题

在这里插入图片描述
上边代码在单机部署时是没问题的,但是如果是下边这种分布式(集群)架构的话,就会产生问题了
在这里插入图片描述
本地启动两个同样的应用,分别是8080和8090端口,通过Nginx配置访问这两个应用
在这里插入图片描述

使用Jmeter模拟多个请求去请求nginx
在这里插入图片描述
如果两个控制台有相同的数据出现,那就是说明在分布式环境下出现问题了(下边这俩数是一样的):
在这里插入图片描述

结果:synchronized等各种锁,只在JVM级别生效,在分布式集群架构下会失效;解决这个问题需要使用分布式锁,实现简单Redis的分布式锁代码如下
在这里插入图片描述

jedis有一条命令setnx(key,value),这条命令会向Redis服务端存一个key/value,返回的结果指的是是否存成功(如果服务端已经存在这个key了,那么就会返回false);由于Redis是单线程,所以只会有一个线程来执行这行setnx(key,value)代码;

上边的代码存在的问题:如果删除key之前代码出现异常,那么这个key就不会被正常删除了,所以应该加try/finally代码块,让删除key的代码一定执行
在这里插入图片描述
继续优化,如果执行finally前宕机了,这个key就不会被删除了,还是存在问题。这时可以加一个超时时间,超过这个超时时间后,redis会自动把这个key清除掉,此时即使程序中间出异常了,过了这个时间后,那个key也会被删除,其他线程还是可以在redis里设置key的(没有超时时间的话,这个key一直存在,其他线程一直就没法进来执行代码)
在这里插入图片描述

在高并发场景下,上边的代码还是有问题,线程1加的锁可能被线程2释放掉了(超时时间设置10秒,结果线程1执行需要15秒,这就存在问题了);解决:给每一个线程生成一个唯一的UUID,把这个UUID放在redis的value里
在这里插入图片描述
删除锁之前判断当前这个锁是不是自己加的,是的话再删除;

上边的代码其实还有问题,如果最下边的finally里边,删除key之前报错了就又出问题了;
上边的超时时间的设置也是个问题,设置多长都可能会出现问题,比如设置30秒,还是会有的代码逻辑执行超过30秒的;

可以采用定时任务来解决这个问题——锁续命:
主线程1进来把key锁上,假设锁了30秒,此时在后台同时开启一个子线程2做定时任务timer,每隔10秒执行定时器,去检查主线程1设置的这个锁是否还存在,如果存在意味着释放锁的代码还没执行(主线程业务代码还没执行完),此时把这个锁的超时时间重新置为30秒,如果不存在则结束这个子线程2;

二 分布式下redis解决方案redisson

基于以上问题,有一个开源框架已经解决了上边的定时器——redisson
redisson官网
redisson在封装redis命令上没有Jedis强,但是在分布式环境下要比Jedis优秀很多

使用redisson
引入依赖
在这里插入图片描述
springBoot启动类配置redisson
在springBoot启动类上加入redisson配置,将redisson对象注入到Bean容器里:
在这里插入图片描述

不同的redis环境使用的api不一样:
redisson

扫描二维码关注公众号,回复: 13448308 查看本文章

使用redisson实现之前的锁逻辑

注入redisson
在这里插入图片描述
实现业务逻辑:

在这里插入图片描述
redisson实现原理
在这里插入图片描述

redisson底层调用的大量lua脚本语言,调用了很多redis的原子操作功能(setnx);

高并发分布式锁如何实现——分段锁
假如编号是001的商品有1000个,则可以分为10个段

001-1=100个
001-2=100个
001-3=100个
-------------
001-10=100个

把001-1、001-2.。。。。。。。。。。001-10这10个段作为key分别放在redis集群里的不同机器里,然后针对不同的段进行加锁;

猜你喜欢

转载自blog.csdn.net/qq_33417321/article/details/119546353