登陆

程序员常识码头:为什么要运用分布式锁?

admin 2019-10-29 142人围观 ,发现0个评论

文章转载自微信大众号“程序员常识码头”,有爱好的能够重视一下。

想获程序员常识码头:为什么要运用分布式锁?取更多材料的能够私信小七“学习”

为什么要运用散布式锁?

为了保证一个办法在高并发情况下的同一时刻只能被同一个线程履行,在传统单体运用单机布置的情况下,能够运用Java并发处理相关的API(如ReentrantLcok或synchronized)进行互斥操控。可是,跟着事务开展的需求,原单体单机布置的体系被演化成散布式体系后,由于散布式体系多线程、多进程而且散布在不同机器上,这将使原单机布置情况下的并发操控锁战略失效,为了处理这个问题就需求一种跨JVM的互斥机制来操控共享资源的拜访,这便是散布式锁要处理的问题。

下面介绍JAVA散布式锁的三种常用完成办法:

1.依据数据库完成散布式锁

要完成散布式锁,最简略的办法或许便是直接创立一张锁表,然后经过操作该表中的数据来完成了。当咱们要锁住某个办法或资源时,咱们就在该表中添加一条记载,想要开释锁的时分就删去这条记载.

详细操作便是在数据库中创立一个表,表中包括办法名等字段,并在办法名字段上创立仅有索引,想要履行某个办法,就运用这个办法名向表中刺进数据,成功刺进则获取锁,履行完成后删去对应的行数据开释锁。

上面官鼎笔趣阁这种简略的完成有以下几个问题:

  1. 这把锁强依靠数据库的可用性,数据库是一个单点,一旦数据库挂掉,会导致事务体系不行用。
  2. 这把锁没有失效时刻,一旦解锁操作失利,就会导致锁记载一向在数据库中,其他线程无法再取得到锁。
  3. 这把锁只能对错堵塞的,由于数据的insert操作,一旦刺进失利就会直接报错。没有取得锁的线程并不会进入排队行列,要想再次取得锁就要再次触发程序员常识码头:为什么要运用分布式锁?取得锁操作。
  4. 这把锁对错重入的,同一个线程在没有开释锁之前无法再次取得该锁。由于数据中数据现已存在了。

当然,咱们也能够有其他办法处理上面的问题。

数据库是单点?

搞两个数据库,数据之前双向同步。一旦挂掉快速切换到备库上。

没有失效时刻?

只需做一个守时使命,每隔一守时刻把数据库中的超时数据整理一遍。

非堵塞的?

搞一个while循环,直到insert成功再回来成功。

非重入的?

在数据库表中加个字段,记载当时取得锁的机器的主机信息和线程信息,那么下次再获取锁的时分先查询数据库,假如当时机器的主机信息和线程信息在数据库能够查到的话,直接把锁分配给他就能够了。

长处:凭借数据库,计划程序员常识码头:为什么要运用分布式锁?简略。

缺陷:在实践施行的进程中会遇到各种不同的问题,为了处理这些问题,完成办法将会越来越杂乱;依靠数据库需求必定的资源开支,功用问题需求考虑


2.依据Redis完成散布式锁

在Redis2.6.12版别之前,运用setnx指令设置key-value、运用ex程序员常识码头:为什么要运用分布式锁?pire指令设置key的过期时刻获取散布式锁,运用del指令开释散布式锁,可是这种完成有如下一些问题:

setnx指令设置完key-value后,还没来得及运用expire指令设置过期时刻,当时线程挂掉了,会导致当时线程设置的key一向有用,后续线程无法正常经过setnx获取锁,形成死锁。

呈现这个问题是由于两个指令是分隔履行而且不具有原子特性,假如能将这两个指令合二为一就能够处理问题了。在Redis2.6.12版别中完成了这个功用,Redis为set指令添加了一系列选项。也便是说现在set指令就能够完成散布式锁,下面咱们来了解一下set指令(set(keyName, lockValue, "NX", "EX", expireSeconds)):

  1. SET指令是原子程序员常识码头:为什么要运用分布式锁?性操作,NX指令保证只需当key不存在时才会设置value
  2. 设置的value要有仅有性,来保证锁不会被误删(value=体系时刻戳+UUID)
  3. 当上述指令履行回来OK时,客户端获取锁成功,不然失利
  4. 客户端能够经过redis开释脚原本开释锁(del 指令)
  5. 假如锁抵达了最大生计时刻将会主动开释

只需当时key的value和传入的value相同才会履行DEL指令。

长处:高功用,凭借Redis完成比较便利。

缺陷:线程获取锁后,假如处理时刻过长会导致锁超时失效(失效时刻我设置多长时刻为好?怎么设置的失效时刻太短,办法没等履行完,锁就主动开释了,那么就会发生并发问题。假如设置的时刻太长,其他获取锁的线程就或许要平白的多等一段时刻。这个问题运用数据库完成散布式锁相同存在),所以,经过超时时刻来操控锁的失效时刻并不是非常的靠谱。


3.依据Zookeeper完成散布式锁

ZooKeeper是一个为散布式运用供给一致性服务的开源组件,它内部是一个分层的文件体系目录树结构,规则同一个目录下只能有一个仅有文件名。大致思维即为:每个客户端对某个办法加锁时,在zookeeper上的与该办法对应的指定节点的目录下,生成一个仅有的瞬时有序节点。判别是否获取锁的办法很简略,只需求判别有序节点中序号最小的一个。当开释锁的时分,只需将这个瞬时节点删去即可。一起,其能够防止服务宕机导致的锁无法开释,而发生的死锁问题。

依据ZooKeeper完成散布式锁的过程如下:

  • 创立一个目录mylock;
  • 线程A想获取锁就在mylock目录下创立暂时次序节点;
  • 获取mylock目录下一切的子节点,然后获取比自己小的兄弟节点,假如不存在,则阐明当时线程次序号最小,取得锁;
  • 线程B获取一切节点,判别自己不是最小节点,设置监听比自己次小的节点;
  • 线程A处理完,删去自己的节点,线程B监听到改动事情,判别自己是不是最小的节点,假如是则取得锁。

单点问题?

运用Zookeeper能够有用的处理单点问题,ZK是集群布置的,只需集群中有半数以上的机器存活,就能够对外供给服务。

长处:具有高可用、可重入、堵塞锁特性,可处理失效死锁问题。详细阐明如下:

  1. 锁无法开释,形成死锁!运用Zookeeper能够有用的处理锁无法开释的问题,由于在创立锁的时分,客户端会在ZK中创立一个暂时节点,一旦客户端获取到锁之后忽然挂掉(Session衔接断开),那么这个暂时节点就会主动删去掉。其他客户端就能够再次取得锁。
  2. 堵塞锁特性!运用Zookeeper能够完成堵塞的锁,客户端能够经过在ZK中创立次序节点,而且在节点上绑定监听器,一旦节点有改动,Zookeeper会通知客户端,客户端能够查看自己创立的节点是不是当时一切节点中序号最小的,假如是,那么自己就获取到锁,便能够履行事务逻辑了。
  3. 可重入!运用Zooke程序员常识码头:为什么要运用分布式锁?eper也能够有用的处理不行重入的问题,客户端在创立节点的时分,把当时客户端的主机信息和线程信息直接写入到节点中,下次想要获取锁的时分和当时最小的节点中的数据比对一下就能够了。假如和自己的信息相同,那么自己直接获取到锁,假如不相同就再创立一个暂时的次序节点,参加排队。

缺陷:由于需求频频的创立和删去节点,功用上不如Redis办法。


总结

上面几种办法,哪种办法都无法做到完美。就像CAP相同,在杂乱性、可靠性、功用等方面无法一起满意,所以,依据不同的运用场景挑选最适合自己的才是王道。

结语

就以这段话自勉、共勉吧。越尽力、越走运,假如你不是官二代、富二代、红二代,那么请记住:勤勉才是改动你命运的仅有捷径。

想要更多材料的能够点击下方“了解概况”

  • 首长世界(00697)与首钢基金缔结新基金办理服务协议
  • 请关注微信公众号
    微信二维码
    不容错过
    Powered By Z-BlogPHP