【Redis】分布式锁-redission

我们一路走来,利用添加过期时间,防止死锁问题的发生,但是有了过期时间之后,可能出现误删别人锁的问题,这个问题我们开始是利用删之前 通过拿锁,比锁,删锁这个逻辑来解决的,也就是删之前判断一下当前这把锁是否是属于自己的,但是现在还有原子性问题,也就是我们没法保证拿锁比锁删锁是一个原子性的动作,最后通过lua表达式来解决这个问题

但是目前还剩下一个问题锁不住,什么是锁不住呢,你想一想,如果当过期时间到了之后,我们可以给他续期一下,比如续个30s,就好像是网吧上网, 网费到了之后,然后说,来,网管,再给我来10块的,是不是后边的问题都不会发生了,那么续期问题怎么解决呢,可以依赖于我们接下来要学习redission啦

一、基于setnx实现的分布式锁存在的问题

基于setnx实现的分布式锁存在下面的问题:

重入问题:在JDK中就有一个可重入锁的说法 ReentrantLock,重入问题是指 获得锁的线程可以再次进入到相同的锁的代码块中,例如有一个方法A去调用方法B,在方法A中要先去获取锁,然后执行业务去调用方法B,而B又要去获取同一把锁,在这种情况下,如果你的锁是不可重入的,那我在方法A中获取了锁,等我去调方法B的时候,它又想获取这把锁显然是无法获取的。那么此时它就回去等待我们锁的释放,而锁又无法释放,因为方法A还没有执行完,它在调B,于是就会出现死锁的情况了,因此在这种场景下我们其实是要求锁是可重入的。

可重入锁的意义在于防止死锁,比如HashTable这样的代码中,他的方法都是使用synchronized修饰的,假如他在一个方法内,调用另一个方法,那么此时如果是不可重入的,不就死锁了吗?所以可重入锁他的主要意义是防止死锁,我们的synchronized和Lock锁都是可重入的。


不可重试:我们之前实现的锁是一种非阻塞式,我们尝试去获取锁,如果失败会立即返回false,没有重试机制。但是在很多业务下不能立即失败,我们希望的是获取锁的时候如果被别人占用了,我等一等再试,如果最后成功了,那我再去执行业务。

因此在有些业务下我们希望这个锁是阻塞的,或者是可重试的。


**超时释放:**虽然我们之前利用判断锁标识、Lua脚本来去解决了因为超时释放导致的误删问题,但是这种超时的情况还是有可能发生的,虽然不会导致误删,但是也有可能会导致一些其他的隐患发生,所以这个超时问题我们还是要想办法去解决。

如果这个时间你设置的太短,我的业务还没有执行完呢,锁就释放了,这样一来等于我的业务执行过程中其他人也有可能来执行业务,这是一个风险。

但如果你设置的太长,将来我出现故障后,很长一段时间大家都在等待锁自动释放,这样锁的阻塞周期就过长了。

所以这是一个矛盾,我们也要去解决。

我们在加锁时增加了过期时间,这样的我们可以防止死锁,但是如果卡顿的时间超长,虽然我们采用了lua表达式防止删锁的时候,误删别人的锁,但是毕竟没有锁住,有安全隐患


主从一致性: 主从模式你也可以理解成读写分离模式,也就是说redis会有一个主节点和多个从节点,但我们去执行写操作的时候,我们去访问主节点,当我们执行的是读操作的时候,我们去访问从节点。当然主节点需要把自己的数据同步给所有从节点,保证主和从的数据是一致的,这样我们就可以在多个节点上去完成读的操作,提高整个服务的并发能力和高可用性。

而且主机宕机了,我们还可以从从节点中选出一个新的主,这样整个集群的可用性就更强了。

但是主从之间的数据同步是有延迟的,因此在极端情况下可能发生这样一种情况:现在我们有一个线程在主节点获取了锁,因为获取锁是set操作,它是一个写操作,那么这个写操作在主节点完成了,因为存在延迟,假如尚未同步给从节点的时候,突然间主节点就宕机了,此时我们会选一个新的从作为主,而这个从节点上因为没有完成同步,因此它是没有锁标识的,也就是说此时其他线程可以乘虚而入拿到锁,这个时候其实就等于有多个线程拿到锁了,因此可能会在这种极端的情况下出现安全问题,当然它出现的概率比较低,因为主从同步的延迟往往是极低的,它往往可以在毫秒级别甚至更低。

1653546070602

所以我们以上说的四个问题要么发生的概率极低,要么我们不一定有这样的需求,在有些业务下需要,有些业务下不需要。

所以这些点都是功能上的扩展点,不是必须得实现,不实现我们也能用,在大多数情况下我们之前实现的那个锁就已经够用了。

但如果说你对锁的要求很高,你有这样的需求,你就必须想办法去解决它们了,而要解决这几个问题可就麻烦了,所以这里不推荐大家亲自去实现,而是去找一找有没有成熟的框架来帮助我们,事实上就有这个东西,因此这节就是要去给大家介绍一个组件:Redission。


二、Redission

那么什么是Redission呢

Redisson是一个在Redis的基础上实现的Java驻内存数据网格(In-Memory Data Grid)。

人话:它是一个在redis基础上实现的一个分布式工具的集合,也就是在分布式系统下用到的各种各样的工具它都有,包括分布式锁,因此分布式锁只是它的一个子级。

它不仅提供了一系列的分布式的Java常用对象,还提供了许多分布式服务,其中就包含了各种分布式锁的实现。

官网地址: https://redisson.org

GitHub地址: https://github.com/redisson/redisson

1653546736063

进入官方GitHub网址后,首先点开Wiki,即它的官方文档。它里面包含的东西非常非常多

image-20240529073502327

其中在分布式锁里面又包含了各种各样不同的锁

image-20240529073728289

因此在企业环境下其实没有必要自己去实现锁,我们之前的讲解只是为了让大家明白分布式锁的原理,因为有的时候面试还是会问到的。因此如果你懂了原理,不管是面试还是以后工作中出现问题,都有利于你去实现和调试。

因此以后推荐大家使用分布式锁的时候直接使用这个开源的框架即可。

回答: Redis分布式锁Redission都是解决高并发中分布式锁的问题的方法。Redis分布式锁是通过使用K-V存储来判断是否拥有锁,避免了释放他人的锁的问题。当业务没有执行完毕但是锁已经过期时,可以采用守护线程的方式来定期检查锁是否过期,并延长锁的过期时间,也就是锁的续期机制。而Redission是一种实现分布式锁的解决方案,它首先获取锁,然后尝试加锁,加锁成功后执行业务逻辑,最后释放锁。Redission解决了Redis实现分布式锁中的锁过期和释放他人锁的问题,通过内部机制和看门狗机制来保证锁的有效性。然而,RedissionRedis主从架构下存在高一致性问题,解决高一致性问题可以使用红锁或者zk锁,但这可能会牺牲高可用性。总的来说,Redis分布式锁Redission都是解决高并发中分布式锁的方法,但需要根据具体情况选择合适的方案。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [RedisRedission两种方式实现分布锁](https://blog.csdn.net/weixin_45150104/article/details/125131846)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值