从零开始java多线程到分布式锁(十四):分布式锁的讨论

一:分布式锁

  首先,我们在前面讨论了锁存在的意义:是为了解决数据共享性和互斥性冲突的一种解决方案,就是实现数据“最终一致性”。现在我们讨论一下为什么要用分布式锁的原因:

1.项目架构的演变(这里我们主要讨论服务应用层)

(1)常见小型企业---垂直单体应用

            其实主要还是应用的复杂度设计问题。这种设计应用从上而下,开发、部署以及维护都很方便,但是无法应对日益增加的访问。

(2)中小型企业--应用、数据层的集群(包括但不限于单体机器)

  这种做了应用(数据库)的集群(这里就群不限于集群还可能涉及到一些数据拆分的问题)。

3.中大型气---服务与Rpc架构

其中每一个服务的架构都同上一份图的架构一致。

2.常见锁的缺陷

  在之前我们有讨论过java中的Synchronized,Volatitle以及Lock等java实现锁的方案,实际上这些所都是依赖于Jvm中对象的一个Monitor的标识位。也就是说一个方法的同步依赖于一个对象,对象呗初始化到Jvm中,一旦应用做到集群或者以上(即部署在多个Jvm虚拟机上)就会导致获取锁不一致。这时候需要依赖一个中央资源管理的方式做分布锁。

 

二:分布式锁的实现

  目前比较常见的通用式锁设计有三种:基于数据库,基于缓存(Redis等)以及基于Zookeeper。

1.基于数据库

 (1)简单实现数据库分布式锁的原理以及缺点

              这种方法完全是可以实现分布式锁(注意这里表只能有一张)但是缺点也是很明显的:

              缺点一:单张表实现锁管理,流量增加时会导致数据库压力倍增。

              缺点二:无失效时间,一旦拿到锁的方法导致锁表,不仅会导致任意的锁方法获取不到锁,方法无法将进行。

             缺点三:无阻赛,很明显没有获取到锁的线程直接被抛弃。

(2)简单锁去缺点的优化

   针对上面的缺点做一些优化,首先锁表完全可以做一个独立的库甚至独立服务(但是说实话这样就有点得不偿失了)。其次可以用定时任务定时清理锁表。最后一点,可以在程序中用循环来解决获取不到锁继续获取锁的。

(3)使用场景

  数据库锁适用于项目中小,但是部署到多个虚拟机上上。但是无论上面的是否优化,个人不建议使用这种分布式锁。 

2.基于缓存锁(Redis)

(1)Redis实现分布式锁的方式

  实则上,分布式锁核心就是用一个中央管理器来管理锁标识,这里使用Redis来实现。其实Redis实现分布式锁还是比较简单的Redis基于命令SETNX

SETNX是将 key 的值设为 value,当且仅当 key 不存在。若给定的 key 已经存在,则 SETNX 不做任何动作。

  • 返回1,说明该进程获得锁,SETNX将键 lock.id 的值设置为锁的超时时间,当前时间 +加上锁的有效时间。
  • 返回0,说明其他进程已经获得了锁,进程不能进入临界区。进程可以在一个循环中不断地尝试 SETNX 操作,以获得锁

(2)SETNX的原理

               第一步:设置A线程对应的Key(Lock.id)与对应的超时时间(即锁的释放时间)

              第二步:A线程获取到锁(返回1)到key(Lock.id),进行执行A线程中的方法.

              第三步:其他线程试图获取到锁(返回0),没有获取到进入Redis的单线程等待直到获取到

              第四步:A线程释放锁

              第五步:其他线程竞争获取删除A线程的(Lock.id),设置自身线程的Key(Lock.id)然后执行第一步

(3)Redis分布式锁的缺点

      其实从上面的过程可以看到Redis锁是足够简单(基本上Redis完全作为通用的分布式锁),但是Redis分布式锁也是有缺点(当初本人就被面试官这个问题问蒙了)下面谈谈Redis分布式锁的缺点:

  缺点一:自动释放锁(即有超时时间释放),这会导致线程可能没有执行完毕就被释放了锁。

  缺点二:自动释放锁导致多线程同时得到锁 ,即锁线程被自动释放了,导致等待线程同时得到Lock.id,同时获取到锁了(实际                   上就是其他线程获取到所线程的Lock.id,然后都认为自身获取到上一个锁了)

  缺点三:集群环境下,导致获取到锁时间可能大于超时时间

(4)Redis优化以及使用场景

    实则上Redis锁缺点就是由于他的锁是自动释放,而不是有代码方法执行完毕然后释放锁。针对这种问题就是设置合适的超时时间。Redis锁毋庸置疑基本上适用于大多数的分布式锁结构。

 

3.基于Zookeeper的分布式锁

Zookeeper实现分布式锁的思路基于Zk的临时有序节点,判断是否加锁只要看该节点是否存在?释放锁只要删除该节点。但是方法缺点应该也很明显依赖于Zk。

 

三:多个锁的比较

上面我们谈到了几种方式,现在我们来比较一下他们:

从理解的难易程度角度(从低到高):数据库 > 缓存 > Zookeeper

从实现的复杂性角度(从低到高):Zookeeper >= 缓存 > 数据库

从性能角度(从高到低):缓存 > Zookeeper >= 数据库

从可靠性角度(从高到低):Zookeeper > 缓存 > 数据库

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值