00:01
各位同学大家好,下面呢咱们继续来学习red中的分布式锁,刚才呢给大家讲到了在red操作中如何来设置锁,释放锁,包括设置过期时间,以及通过UID防止锁的误删,只能自己删自己,而不能删别人的锁。那咱们下面呢给各位继续来演示right中分布式锁的另外一个问题,给各位做个说明,那这个问题是什么呢?给大家来举一个场景,咱们来说明一下。就是我们在reddi进行上锁和解锁过程中,目前是缺乏一个原子性操作的,什么叫原子性的正常就是啊,我上锁之后再解锁,当我解锁之后别人是不能操作呀,但是目前它操作中并没有涉及到原子性操作,所以它会产生一些问题。那问题是什么呢?下面给大家我来说一下咱们描述这个问题,比如说我们现在啊,在里边啊,有这么两个操作啊,注意有两个操作,比如说左边是我们的A操作。
01:11
右边是我们的B操作,现在两操作,那比如现在呢,两个操作中,我在第一个A操作先进行了,各位肯定都知道它操作中的第一步是不是先上锁呀,就对我这个相关内容,先做一个上锁操作,然后上锁之后第二步进行我们的具体操作,比如说你是做添加修改还是等等操作,然后他在具体操作之后,第三步是不是要释放锁,要比如说我们做那个delete删除操作。但是现在啊,问题又出来了,比如说啊,这个A操作,它在释放锁的时候呢,就是它这里边释放锁,咱之前说到我们这里边的,首先第一个要通过这个UUID是不是进行比较,如果你UID一样,它是不是来释放啊,比如说现在啊,它释放左比较离外,发现U外地是一样的,或者说是相同的,那现在是不是要做这个删除操作呀,比如说它在删除的时候,正要删除,但是还没有删除啊,注意我的描述啊,它正要删除,但是还没有删除的时候,这个时候呢,碰巧我这个锁呢,已经到了这个过期时间了,它一到过期时间怎么样,是不是就会自动释放了。
02:32
各位注意我这个场景啊,给大家再说一遍。现在我们的A先进行操作,那它操作中呢,首先肯定是上锁操作,然后再释放,它在释放的时候先比较UYD是否是一样,比如它一比较发现UID它是相同的,如果相同的话,咱是不是叫释放所呀,或者说删除操作,但是这个时候有一个问题,它在删除的时候,正要删除,还没有删除就已经比较过了,可以删除,但是他正要删除还没有删的时候,我的锁或者我的K已经过期了,到了过期时间,这个时候是是会自动释放,但你注意啊,我这山还没有结束吧,是不是还要删呀,只是我所目前作释放了,而他一释放是问题,大家能想到我现在B是不是就获取到了我这个锁,就是因为你释放我B肯定能获取到这个锁,而B1获取之后,它会进行我们的具体操作,大家注意啊。
03:31
这里边问题就出来了,我B在操作的时候,因为我A还没有结束嘛,A是不还可以继续进行这个锁的一个删除,它继续删除这个操作,而你注意A要删除的话,它是不是会把这个B的这个锁给它删掉,就是把B的锁给它释放掉啊,就是A的这个操作会释放B的这个锁,所以这个问题就是缺乏原子性造成的,有同学可能会想啊,你这里边已经做了UID的处理,怎么A还能删成B的这锁呢?因为你看这过程啊,我A已经比较过了,UID是一样的,但是这个时候呢,碰巧了,我这个删的时候还没有删,锁就过期了,那它自动释放了,但是我A还要继续完成,它一完成那它删除锁删的就不是自己了,而是B的这个锁,因为它这个锁已经释放了,它就把B给它删掉,这过程就是因为什么造成的,因为我目前操作中没有原子性,它们互相会干扰。
04:31
所以造成了目前的问题,A操作正确,应该是上锁操作,解锁删除,然后在B,但是目前我这个A还没有删完,之后B就得到了,然后A1删把B就删掉了,这里边造成这个问题。它就是没有进行原子性操作而造成的这个问题,所以各位把这给他知道,这是咱们说明的第三问题,那这个问题怎么解决呢?大家想一下啊,咱之前讲过它的解决方案,不是各位是否记得啊,当时啊,咱们在讲那个就是我们做那个秒杀案例的时候,曾经说一个东西,这个东西。
05:14
叫做落脚本,这个位应该记得啊,落脚本什么意思呢?它是一种嵌入式的语言,它能支持我们的Java或者C加加等等操作,然后这个脚本一个最大特点是什么呢?支持原子操作,也就是说落脚本在执行的时候别人不能干预,只有等他执行完成之后,别人才能进入,好比说我现在说话,我说的时候别人不能打断,只有我说完之后别人才可以打断,这就是落脚本特点,咱之前在做那个秒杀案例中应该提到过这个东西,关于落脚本就是里边这个特点啊,它有一定原子性,然后不会被其他这个命令插队,可以完成ready中事务性的一些操作。这是我们提到的,所以咱们现在就能通过落脚本保证我们删除的原则性,就是我上锁删除,别仓操作,我们一删完之后别人不能操作,这是我们提到的,那怎么做,我这里边有段代码,我把代码给各位复制过来,咱们来看一下这个过程。
06:16
那在里边我来复制,然后咱们看下这个操作啊,首先这操作中的前面部分跟之前都一样,你看啊,我生成UID,然后里边设置我的K啊,只是K里边又加了一个,这个就是SKID啊,商品的ID,然后设置之后,首先我们设置锁,包括用UID这个值设置它的这个过期时间,然后设置之后判断,如果这个锁得到了,那我们就设置它这个值,把它的值给它加一,然后加一之后下面咱是不是要做一个锁的释放,但是释放的时候各位注意我这特点啊,里边我就写了一个落脚本,通过落脚本做到这是一个脚本,然后下面是执行,最终做这个操作,这是我们写的这么一段代码,就是在这个过程中通过落脚本实现,我这个就是操作的原则,行,当你删这个锁,或者说释放锁,只有在我这操作之后,别人才能进行,这是我们提到的。
07:17
那这落脚本我们可以看一下里面这过程啊,这脚本写应该很简单,首先第一个义务判断,判断我这个K跟我们那个就是UID值是否一样,也就是这里边传的K和UID啊,就咱取到里边这个值和我传的UID是否一样,如果一样的话,那我们调这个删除方法进行删除,如果不一样,RETURN0,咱们就不用删除,最终结束就是一段简单脚本,判断UID是否一样。一样的话调方法删除,不一样的话不删除,因为用的是落脚本特点,所以这个操作只有他执行完成之后,别的操作才能进入,他在执行过程中别的操作不能打断,这是我们提到的这么一个特点,那这个写完之后呢,咱们现在就通过落脚本来实现了我们删除的原子性操作,这个我们就说完了,所以大家把这个特点给大家记住,这个不要你能写出来,但是你通过代码能够改出你的效果,因为里边跟我们之前做那个秒杀过程基本上是类似的。
08:27
所以说咱们现在就把这个分布式锁的部分给各位,就最终说完了,然后最后我们来总结一下咱们操作啊,首先我这里写到第一个咱可以加锁,包括里边做这操作,在加锁中咱可以设置它的UID判断,我只能删我自己的这个锁,只能释放自己锁,别人的锁不能释放,用这个妥当,这是我们的第一步。然后第二个通过落脚本释放锁能保证操作的原子性,就是我上锁释放锁别人才能操作,我在没有删完之后,别人是不能进入操作的,通过录脚本的特点,保证删除锁或者释放锁的原则性,这是我们说的第二个,包括这个重试,比如你这里边没有得到锁,咱们等一会儿继续重试。
09:14
这是我们提到的分布式锁,然后分布式锁呢,我们为了确保所可用,至少要满足以下几个条件,就咱们刚才说到的啊,第一个条件,互斥性,在任何时候只有一个客户端能持有锁,比如我现在A和B,你只有A有锁或者B有锁,不能两个同时有锁,A有锁释放之后B才可以有,B有锁释放之后A才可以有,而不能同时持有,这是第一个特点,叫做互斥型。然后第二个不会发生死锁,什么叫死锁呢?比如现在我一个客户端在有锁的时候呢,他这过程中突然崩溃了,而他并没有主动释放,这个时候呢,咱可以设置它的过期时间,让它自动释放,如果你不自动释放,它是不是就一直等待呀,会发生思索,所以这个咱要保证,也就是代码中的里边的这个体现。
10:09
设置它的过期时间。这是里边的第二个特点,各位把它知道,然后里边还有第三个叫做解铃排,需记铃人什么意思呢?就是加锁和解锁必须是图形后端,比如说A加锁要A解锁,B加锁要B解锁,而A不能去释放B的锁,B也不能释放B的锁,这是第三点。然后还有最后一点,加锁和解锁必须具有圆则性,就是我加锁在解锁之后别人才能操作,而我加锁在没有解锁完成之前,别人是不能进入操作的,不能进行干扰这个过程,咱刚才用落脚本把这过程应该做到实现,所以这些呢,就是关于re中应用问题的说明,包括解决,给各位最终重复一遍啊,咱们说了四个问题。
11:02
第一个缓存穿透,第二个缓存击穿,第三个缓存雪崩,还有最后一个分布式锁,所以各位把这四个问题是什么,包括它有什么特点,以及他们的解决方案,各位都要给他特别熟悉,因为这些都是我们在使用中针对re使用过程中常见的这么几个问题,所以咱们现在这部分我们就讲完了。
我来说两句