00:00
大家可能会发现啊,我现在呢,确确实实已经重新进一步完善了我的程序,加锁的同时,并且给他加了过期时间啊,当然啊。我们这儿呢,要强调目前是不是已经修改到5.0版了,当前大家所看到的程序是5.0版,那么请挑出来5.0版的bug。那么有没有发现一个问题?所有高频发的程序一定要考虑一个东西,叫原子性。我们现在枷锁和给这把锁要设置的时间并不在同一行,也即加锁和设置过期时间这两行并不是原子的,那就算你写成啊,如果说if。Flag是true的话。那么。我们再加过期时间,否则的话是把你这样都没有必要这么写,为什么?因为刚才只要是把设置和加过期时间分开的,非原子操作。
01:04
根本就没有任何意义,所以说现在呢,杨哥当时的时候为什么要写这个命令,没有给大家直接一口气。添加上过期时间,就是这样一步步的推导出来,告诉你我们这个是怎么怎么完善的,你把这个故事啊,这个流程,这些过程都整清楚了,你去面试啊。应付项目经理的考核,你才有谈资,所以说我们这儿出现的问题是设置这个所,这个key和过期时间分开了,必须要合并成一行,并且具备什么原子性,那么还好我们RA给我们提供了一些命令,它也在不停的慢慢的进化,那么在这块呢,同学们,我们呢,就不能够写成这样,甭管你加不加判断,加这个加不加if不是问题的关键。那么同学们走起,我们这儿只能是set if。Absent,刚才我们是不是用这个,现在我们必须要用这个,那么我们的K还是上面这个。
02:06
OK value,还是原来那么十秒钟,Time unit OK,只有这样才能保证它的原子操作,这个命令自身已经具备了原子性,听懂了吧?那么所以说我们这儿就需要把我们的程序从5.0版改为6.0版,让它完成我们的。加锁并携带的过期时间,彻彻底底让它成为原子性操作加锁且带有锁的过期时间完成修改为我们的6.0版,那同学们继续。继续找,你认为6.0版这些还有存在着哪些bug和隐患,我先暂停,请思考好,同学们,我们继续那么在代码层面啊。解到这儿几乎是具备了一个分布式的原子锁的一个雏形,但是从代码层面差不多了,那么接下来我们就要考虑一下我们的业务层面。
03:08
会,这儿会存在着一个在运行过程中的一个潜在的隐患,同学们请看啊,那么在这儿的话呢,我们给这把锁,现在用这个命令保证加锁成功,且自带着过期时间多少十秒钟好的,那么这呢会出现一种问题。第一个假设第一个线程搁到这儿开跑了。那么现在正常情况下,假设这个线程五秒钟就完成,第一个线程进来加了把锁,谁用谁加锁自带过去时间,自动把red给你记住时,20秒钟完成,巴拉巴拉巴拉你进去干你的业务逻辑大概五秒钟以后完成,把自己家的这把锁删掉,好比去一个卫生间。进去你加锁,释放完内存以后,你自己解锁,OK,根本都用不到十秒钟,十秒钟是一个第二层保险是个垫底的,好说,这是一切顺利的前提下,那么接下来我们看一下不顺利前提下的业务会变成什么样呢?
04:07
如果这个A进来了,搁到这儿,突然发现去调另外一个业务,那个业务它宕机了。平时呢,五秒钟就能完成的工作,他这儿可能须要干12秒钟,听懂了吧,我们刚才已经说过了,我们必须要给我们建的所自带一个过期时间,否则程序不严谨,会有隐患,但是我们解决了一个问题,又会带来另外一个问题,就是如果A线程进到这啊,第60行,它这卡着了。平时需要五秒钟就能做完的程序,他现在呢,已经超过了十秒钟,超过了十秒钟会出现什么情况啊,是不是red自己会把这个锁给删掉啊,那么就会变成A线程在这儿。我要完成这个业务啊,需要12秒钟,但是十秒钟以后自己把这个锁给干掉了,那么现在A线程还在这干着呢啊。
05:08
不好意思啊,只要这儿被删掉了,外面可是等着一大堆BCDEF线程呢,他们马上就挤进来,一判断发现,哎哟,好事,Red,这没有线程。OK,没有这把red的线程锁欧了,其他的线程就爽死了。那么现在假设第二个线程B线程过来了,由于我认为上面没有这把锁,我自己也就加锁那么好,一加B线程也就开始来进行工作。那么这个时候B线程的这把锁的过去时间也是十秒钟,可你可别忘了,现在A线程在这儿啊,他还没结束,假设两秒钟以后。总共耗时12秒钟以后,A线程结束了,噼里啪啦的往下走。隔到这儿一删,那么将会出现一种可怕的情况,A线程之前自己加的锁十秒钟,由于A线程第一个线程他本次处理这个业务需要12秒钟,他自己的那把锁已经过期了,然后他一删,他把第二个线程B线程加的这把锁给删掉了,那么这样是不是就误删了其他线程的锁呀?
06:24
这是一个很可怕很严重的问题,所以说我们在5.0版的基础上,虽然说修改为了6.0版,那么在6.0版的基础上,我们有出现了一个严重的问题,怎么着张冠李戴删除了别人的锁,这个是很可怕,那么再来看一下,我给大家总结了一张图。上面是T1到T9时间点,Radius服务器线程A和线程B一开始线程A进来。TX这把锁。我们呢,不存在,在设置底是第一个线程肯定不存在可以加锁成功,我们现在30秒钟test不存在获取锁成功,A就在red服务器上面加锁成功了,然后加锁成功以后,A是不是一顿操作咣咣咣咣咣的往前走,那么好,假设现在B线程绿色这个也想去加锁,它去服务器上去看哟,T这把锁存在获取锁失败,那么B线程是不是只能等着好,我们这儿多少秒,30秒钟,但是A这波操作可能超过了30秒钟,听懂了吧,那么现在你自己设置的过期时间,A自己设置的,我们默认30秒钟搁到这儿,T5这个时间段的时候,到达30秒锁被red服务器自动示范,换句话说,A线程在red上面加的锁被red服务器自动释放掉了,现在red。
07:50
服务器上面在T5这个时间段没有锁了,但是非常抱歉,A的工作还没做完呢,A继续咣咣咣咣的往前走,那么现在又到了一定时间段,B同事啊,突然发现,哎。
08:04
现在red服务器上面T6这个时间段test这把锁不存在,获取锁成功注线。T5自己到达30秒钟以后,把A线程加的锁自动释放掉了,因为你到了过去时间自己删。然后到T6这个时间段加了这把锁,有没有加锁成功,加锁了这个test,这把锁不是A的,是谁的,是B的明白,那么这个时候B也就开始咣咣咣咣一顿操作,去忙他的工作,然后完了以后,假设超过了38秒钟以后,A做完了,我上test这把锁反正名字都叫test,被线程A给删掉了,线程A很happy,觉得呢,反正自己做了一件很爽的事,加锁成功,业务逻辑成功,删除所成功,玩火,过了一会儿回来以后,B。发现,哎,那我的锁呢。不好意思啊,这个时候B是不是就尴尬了?所以说整个过程我们要非常严谨的注意一个问题,防止张冠李戴。
09:07
不能伤了别人的锁,听懂了吧,这个是非常严重的隐患,在工作当中,你基本上那如果出这种故障,全场嗨翻,保证今天P0的事故,你绝绝对摊上事儿了,你一定会成为你们想项目组当中的什么。VIP bug VIP版的bug专属会员,明白了吧,不能放这样的bug,所以说我们怎么办?只能删除自己的锁,不许动别人的,自己的牙刷自己用,自己的毛巾自己用,你不可能跟别人共用一把牙刷吧?OK,所以说要修改为7.0版加一层判断只能删除自己的锁,那么同学们思考一下,你这个判断应该怎么加?同学们,所以说呢,通过前面的思考我们就明白了,必须在程序里面不能直不楞登的这么直接delete,要判断自己的锁才能删,别人的锁不能删,那么怎么判断是不是我们的if一样string。
10:04
点OPS for value就是对吧,Get谁我们这个T这个T谁呀,我们现在屯的这个T是不是就叫at硅谷at洛,但是注意它的每一个value是不一样的,你的锁。名字是一个,但是Y是每一个线程加个流水号,那么所以说我们这儿。搁到这儿得到的一克如果等于我们的value,这样才能保证并表示这是我们自己的所假设A线程进来得到这儿我A线程存的名字啊,叫这个我存的value是不是自己的流水号加A线程自己的名字啊,然后完了以后如果通过这一行代码得到的。这个K的值刚好就是A存进去的这个值是不是它表明这是属于自己的锁,你才可以去动delete这个命令,这样的话才能保证自己删除自己的,不许动别人的,再次强调不允许发生张冠李戴乱删除这种错误,这是非常严重的bug OK,那么所以说到第七步,我们加一个判断,完成我们的delete操作,这个就是我们目前7.0版的程序。
我来说两句