redis分布式锁原理以及方案

Redis分布式锁

关于分布式锁

关于分布式锁,一般有三种选择,

1、redis

2、zk

3、DB锁(悲观锁、乐观锁)

​ 乐观锁加版本号,悲观锁加for update

超卖问题演变

1.使用同步代码块,使用多个服务器集群,就不行了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cTbcdidC-1619683478653)(img/image-20210409163749531.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uXzhgmV6-1619683478659)(img/image-20210409163825303.png)]

使用nginx做负载均衡

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GanR0Qpc-1619683478664)(img/image-20210409163838081.png)]

2.使用redis的setnx

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DvHp4Z4o-1619683478666)(img/image-20210409163926114.png
)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Voc5kfVq-1619683478667)(img/image-20210409163936309.png)]

问题:

进行执行代码块的时候,会导致出现异常,然后无法删除key,导致之后的线程一致无法进行抢购

解决办法;

使用finally,防止死锁

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KgmBsolq-1619683478668)(img/image-20210409163959187.png)]

出现宕机

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3zuWQb8q-1619683478669)(img/image-20210409164016244.png)]

解决办法:给key设置过期时间

​ 但是设置key,设置过期时间不是原子操作,所以也不行,就使用一条命令同时设置就可

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6fKn4uSv-1619683478669)(img/image-20210409164029831.png)]

在高并发的场景下,失效时间好,线程1执行时间刚刚好到一半业务就过期了

其他线程2进来执行,然后线程1删除锁,线程3进入,没法控制线程的进入顺序,导致线程混乱---------线程2的锁被线程1删除掉

解决办法给每个线程加一个线程id的标识,这样根据id匹配进行删除

这样就可以自己删掉自己的锁,不会导致自己删掉别人的锁问题存在

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jdaz9Wx0-1619683478670)(img/image-20210409164057433.png)]

存在问题:还是时间问题,导致多个线程同时执行一段并发代码,导致资源数据更改错误问题

我们可以弄一个分线程,然后执行定时任务(每隔10s),判断主线程是否还存在执行

,就给它“续命”延长30s时间,防止主线程因为操作过长导致失效key

当发现主线程不存在,则分线程结束 ----实现非常麻烦

进入redisson分布式锁主题

引入依赖

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CE92CZx1-1619683478672)(img/image-20210409164133080.png)]

初始化客户端

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0oAjfsSC-1619683478673)(img/image-20210409164145013.png)

多种模式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vhrAOvRI-1619683478674)(img/image-20210409164156398.png)]

修改原代码

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p9KlHA3j-1619683478676)(img/image-20210409164220877.png)]在这里插入图片描述

分布式实现原理

线程1进行加锁操作,使用setnx进行设置

线程2进行加锁,发现已经有人加锁了,加锁失败,然后进行尝试自旋

开启一个分线程也就是后台线程,如果设置key的过期时候为30s,分线程执行每隔10s执行一个定时任务,判断线程是否还持有锁,有则进行延长,没有持有锁,则分线程结束

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-awgKiMLo-1619683478677)(img/image-20210409164257665.png)]

lua脚本执行命令的时候,会把这些代码当成一条命令去执行,所以不存在原子性问题

底层实现了lua执行脚本的原子性,要么同时成功,要么同时失败

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VDMVLQsq-1619683478678)(img/image-20210409164315369.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hBDXxqip-1619683478679)(img/image-20210409164322928.png)]

点击进入任务看看

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sQIc6cFW-1619683478680)(img/image-20210409164338055.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cwnN4UpG-1619683478681)(img/image-20210409164352440.png)]

问题:

在高并发的场景下,使用redis主从节点,主节点进行接收数据,然后异步到从节点

在主节点接收线程1数据的时候,还没有异步到从节点时,主节点挂掉了,那么从节点作为下一次访问的主节点,线程3也要对线程1操作的某个商品id进行加锁操作,这时原来的从节点没有对应的数据信息进行操作

分布式锁解决

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VLRJcdjA-1619683478682)(img/image-20210409164445372.png)]

解决办法使用zookeeper集群

CAP原则又称CAP定理,指的是在一个分布式系统中,

一致性(Consistency)、

可用性(Availability)、

分区容错性(Partition tolerance)。

CAP 原则指的是,这三个要素最多只能同时实现两点,不可能三者兼顾。

对于redis分布式锁满足ap,redis主节点加锁成功后立马返回给客户端,可用性高

对于zookeeper满足cp,

zookeeper的话有leader主节点,多个从节点,当加锁成功后,会先将主节点的数据同步到从节点,当有半数的key同步成功后,才会返回给从节点(从节点同步成功后告诉主节点,主节点会根据从节点数量进行判断是否满足一半数量同步成功),牺牲一点可用性来进行数据同步一致性

当主节点挂掉了,底层有个zab原子网络协议,会选取一个节点作为新的leader节点

关于redis分布式锁和zookeeper的选择?

高并发的话选择redis,主从架构出现的问题概率小,出错了的话,写一个脚本进行判断人工补偿

如果要避免这些问题,就要使用zookeeper,但是并发没有redis的高

RedLock原理

底层类似zookeeper,加锁发送setnx会向所有从节点发送,当其中一个失败全部回滚

性能问题,本身也不能保证失效问题,不推荐使用

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lLkgNhyE-1619683478684)(img/image-20210409164509975.png)]

补偿

如果要避免这些问题,就要使用zookeeper,但是并发没有redis的高

加锁是串行执行的,超级高并发的情况速度比较慢,还可以进行优化

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值