欧宝品牌

浅谈分布式锁与笑不益看锁

点击量:57   时间:2021-06-15 15:56

技术学习视频教程网盘资源清理 https://pan.baidu.com/s/13dbR69NLIEyP1tQyRTl4xw

分布式相反性题目

  随着互联网技术的一连发展,数据量的一连增补,营业逻辑日趋复杂,在这栽背景下,传统的荟萃式体系已经无法已足吾们的营业需求,分布式体系被行使在更众的场景,而在分布式体系中访问共享资源就必要一栽互斥机制,来防止彼此之间的互有关扰,以保证相反性,在这栽情况下,吾们就必要用到分布式锁。

  最先吾们先来望一个幼例子:

  倘若某商城有一个商品库存剩10个,用户A想要买6个,用户B想要买5个,在理想状态下,用户A先买走了6了,库存削减6个还剩4个,此时用户B答该无法购买5个,给出数目不及的挑示;而在实在情况下,用户A和B同时获取到商品剩10个,A买走6个,在A更新库存之前,B又买走了5个,此时B更新库存,商品还剩5个,这就是典型的电商“秒杀”运动。

  从上述例子不寝陋出,在高并发情况下,倘若不做处理将会展现各栽不走预知的后果。那么在这栽高并发众线程的情况下,解决题目最有效很远大的手段就是给共享资源或对共享资源的操作添一把锁,来保证对资源的访问互斥。在Java JDK已经为吾们挑供了云云的锁,行使ReentrantLcok或者synchronized,即可达到资源互斥访问的主意。但是在分布式体系中,由于分布式体系的分布性,即众线程和众进程并且分布在分歧机器中,这两栽锁将失踪原有锁的奏效,必要吾们本身实现分布式锁——分布式锁。

  分布式锁必要具备哪些条件

  1. 获取锁和开释锁的性能要益

  2. 判定是否获得锁必须是原子性的,否则能够导致众个乞求都获取到锁

  3. 网络休止或宕机无法开释锁时,锁必须被明了,不然会发生物化锁

  4. 可重入一个线程中能够众次获取联相符把锁,比如一个线程在实走一个带锁的手段,该手段中又调用了另一个必要相通锁的手段,则该线程能够直接实走调用的手段,而无需重新获得锁;

  5.壅塞锁和非壅塞锁,壅塞锁即异国获取到锁,则不息期待获取锁;非壅塞锁即异国获取到锁后,不不息期待,直接返回锁战败。

  分布式锁实现手段

  一、数据库锁

  1. 基于MySQL锁外

  该实现手段十足凭借数据库唯一索引来实现,当想要获得锁时,即向数据库中插入一条记录,开释锁时就删除这条记录。这栽手段存在以下几个题目:

  (1) 锁异国失效时间,解锁战败会导致物化锁,其他线程无法再获取到锁,由于唯一索引insert都会返回战败。

  (2) 只能是非壅塞锁,insert战败直接就报错了,无法进入队列进走重试

  (3) 不走重入,联相符线程在异国开释锁之前无法再获取到锁

  2. 采用笑不益看锁增补版本号

  按照版本号来判定更新之前有异国其他线程更新过,倘若被更新过,则获取锁战败。

  二、缓存锁

  这边吾们主要介绍几栽基于redis实现的分布式锁:

  1. 基于setnx、expire两个命令来实现

  基于setnx(set if not exist)的特点,当缓存里key不存在时,才会往set,否则直接返回false。倘若返回true则获取到锁,否则获取锁战败,为了防止物化锁,吾们再用expire命令对这个key竖立一个超往往间来避免。但是这边望似完善,实则有弱点,当吾们setnx成功后,线程发生变态休止,expire还没来的及竖立,那么就会产生物化锁。

  解决上述题目有两栽方案

  第一栽是采用redis2.6.12版本以后的set,它挑供了一系列选项

EX seconds – 竖立键key的过期时间,单位时秒

PX milliseconds – 竖立键key的过期时间,单位时毫秒

NX – 只有键key不存在的时候才会竖立key的值

XX – 只有键key存在的时候才会竖立key的值

  第二栽采用setnx(),get(),getset()实现,大体的实现过程如下:

  (1) 线程Asetnx,值为超时的时间戳(t1),倘若返回true,获得锁。

  (2) 线程B用get 命令获取t1,与现在时间戳比较,判定是否超时,没超时false,倘若已超时实走步骤3

  (3) 计算新的超往往间t2,行使getset命令返回t3(这个值能够其他线程已经修改过),倘若t1==t3,欧宝品牌获得锁,倘若t1!=t3表明锁被其他线程获取了

  (4) 获取锁后,处理完营业逻辑,再往判定锁是否超时,倘若没超时删除锁,倘若已超时,不必处理(防止删除其他线程的锁)

  2. RedLock算法

  redlock算法是redis作者保举的一栽分布式锁实现手段,算法的内容如下:

  (1) 获取现在时间;

  (2) 尝试从5个相互自力redis客户端获取锁;

  (3) 计算获取一切锁消耗的时间,当且仅当客户端从无数节点获取锁,并且获取锁的时间幼于锁的有效时间,认为获得锁;

  (4) 重新计算有效期时间,原有效时间减往获取锁消耗的时间;

  (5) 删除一切实例的锁

  redlock算法相对于单节点redis锁郑重性要更高,但是实现首来条件也较为庄严。

  (1) 必须安放5个节点才能让Redlock的郑重性更强。

  (2) 必要乞求5个节点才能获取到锁,议定Future的手段,先并发向5个节点乞求,再一首获得反答终局,能萎缩反答时间,不过照样比单节点redis锁要消耗更众时间。

  然后由于必须获取到5个节点中的3个以上,以是能够展现获取锁冲突,即行家都获得了1-2把锁,终局谁也不及获取到锁,这个题目,redis作者借鉴了raft算法的精髓,议定冲突后在随机时间最先,能够大大降矮冲突时间,但是这题目并不及很益的避免,稀奇是在第一次获取锁的时候,以是获取锁的时间成本增补了。

  倘若5个节点有2个宕机,此时锁的可用性会极大降矮,最先必须期待这两个宕机节点的终局超时才能返回,另外只有3个节点,客户端必须获取到这通盘3个节点的锁才能拥有锁,难度也添大了。

  倘若展现网络分区,那么能够展现客户端永世也无法获取锁的情况,介于这栽情况,下面吾们来望一栽更郑重的分布式锁zookeeper锁。

  zookeeper分布式锁

  最先吾们来晓畅一下zookeeper的特性,望望它为什么正当做分布式锁,

  zookeeper是一个为分布式行使挑供相反性服务的柔件,它内部是一个分层的文件体系现在录树组织,规定联相符个现在录下只能有一个唯一文件名。

  数据模型:

悠久节点:节点创建后,不会由于会话失效而消逝

一时节点:与悠久节点相逆,倘若客户端连接失效,则立即删除节点

挨次节点:与上述两个节点特性相通,倘若指定创建这类节点时,zk会自动在节点名后添一个数字后缀,并且是有序的。

  监视器(watcher):

当创建一个节点时,能够注册一个该节点的监视器,当节点状态发生转折时,watch被触发时,ZooKeeper将会向客户端发送且仅发送一条关照,由于watch只能被触发一次。

  按照zookeeper的这些特性,吾们来望望如何行使这些特性来实现分布式锁:

  1. 创建一个锁现在录lock

  2. 期待获得锁的线程A就在lock现在录下,创建一时挨次节点

  3. 获取锁现在录下一切的子节点,然后获取比本身幼的兄弟节点,倘若不存在,则表明现在线程挨次号最幼,获得锁

  4. 线程B获取一切节点,判定本身不是最末节点,竖立监听(watcher)比本身次幼的节点(只关注比本身次幼的节点是为了防止发生“羊群效答”)

  5. 线程A处理完,删除本身的节点,线程B监听到变更事件,判定本身是最幼的节点,获得锁。

  幼结

  在分布式体系中,共享资源互斥访问题目专门远大,而针对访问共享资源的互斥题目,常用的解决方案就是行使分布式锁,这边只介绍了几栽常用的分布式锁,分布式锁的实现手段还有有许众栽,按照营业选择正当的分布式锁,下面对上述几栽锁进走一下比较:

  数据库锁:

益处:直接行使数据库,行使浅易。

弱点:分布式体系大无数瓶颈都在数据库,行使数据库锁会增补数据库义务。

  缓存锁:

益处:性能高,实现首来较为方便,在批准偶发的锁失效情况,不影响体系平常行使,提出采用缓存锁。

弱点:议定锁超时机制不是相等郑重,当线程获得锁后,处理时间过长导致锁超时,就失踪了锁的作用。

  zookeeper锁:

益处:不凭借超往往间开释锁;郑重性高;体系请求高郑重性时,提出采用zookeeper锁。

弱点:性能比不上缓存锁,由于要屡次的创建节点删除节点。


欧宝体育最新版本