分布式锁总结

Posted Java编程指南

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了分布式锁总结相关的知识,希望对你有一定的参考价值。

作者:乒乓狂魔

链接:https://my.oschina.net/pingpangkuangmo/blog/784879

1 设置锁超时时间

redis、数据库等实现的分布式锁,需要设置锁超时时间的原因在于:其他客户端无法得知已经获取锁的客户端的状态 是挂了呢,还是正在执行。所以只能傻傻的设置一个超时,认为超时之后就简单的判定获取锁的客户端挂了。

一旦锁设定了超时时间,可能获取锁的客户端因各种原因执行业务操作的时候耗时较长,超出了锁的超时时间,这时其他客户端就可以再次获取锁了,所以就会带来并发问题。

2 消除锁超时时间

为了消除这个锁超时,就需要由服务器来作为代理来通知,

如ZooKeeper,一旦客户端挂了,就会删除对应的临时节点,然后通知watch该节点的其他客户端。所以客户端不需要设置锁超时,就等待通知即可。

从这点来说ZooKeeper是更可靠的,降低了因锁超时带来的并发问题。

3 方案的高可用问题

redis、数据库等方案要想实现高可用,则必须有对应的高可用方案。如最简单的主从架构,又引入了一致性的问题,又会有很多的坑。

ZooKeeper方案本身可以做到高可用、一致性,所以ZooKeeper方案也更简单一些。

4 连接的单点问题

这个单点不是说redis或zookeeper的单点问题,而是客户端和服务器端的这个连接的单点问题。先来举个例子:

如ZooKeeper还是会出现并发问题的,如客户端获取到锁了之后,和ZooKeeper连接出现了session超时, 就会导致ZooKeeper集群删除对应的临时节点,其他客户端也就能获取到锁了,此时就存在并发问题。

这种问题的根由就是:客户端和ZooKeeper集群之间的连接是单连接,即只连接其中的一台机器。一旦该连接出现网络抖动, 这种分布式锁方案也会出现并发问题。

减少并发的措施:增大session的超时时间,尽量减少网络抖动,但是这也会降低服务器端对客户端的状态检测的灵敏度,这个灵敏度在分布式锁的场景下也不是特别重要,所以无所谓了。

5 消除连接的单点问题

要消除单点,必然是建立多连接来防止网络的抖动,即客户端连接多个服务器端,向每个服务器都执行获取锁的操作。

如redis的Redlock实现的分布式锁。

有N个独立的master服务器,客户端会向所有的服务器发送获取锁的操作。过半的服务器都获取到锁了则认为获取到锁了,这种也有很多细节。这种方式就解决了上述所说的ZooKeeper单连接可能造成的并发问题。

然而redis由于上述1所说的redis自身设计的问题,Redlock实现的分布式锁也会有锁超时问题,即也会存在并发。

所以理想中更好的方案就是:解决了上述2个问题,从而来进一步减少并发的可能性

redis如果能像ZooKeeper一样,实现了和客户端绑定的临时key,一旦redis客户端挂了,临时key删除,通知watch该key的其他客户端(感觉这个是一个不错的需求,不知redis未来是否要实现),就可以消除锁超时,再使用Redlock实现的分布式锁,这时候可靠性就更高了。

本文侧重总结在可靠性方面的问题,性能嘛,单机的redis当然是最快的了,其次zookeeper,最后数据库。而上述第五点,Redlock方案牺牲了一些性能来换取了可靠性。

6 概览分布式锁

其实要解决2个高可用的问题:

  • 数据存储的高可用(解决基本使用)

    如使用redis、数据库、ZooKeeper,他们承载着分布式锁需要的数据,不能是单点的,要集群高可用

  • 连接的高可用(降低并发的概率)

    那就需要建立多连接,如向N个redis master建立连接,向每一个都获取锁。

所以应该理想的布局是:

和N个独立的服务器(如ZooKeeper)都建立连接,向每台服务器都请求获取锁的操作,过半成功才表示获取到锁

这N个独立的服务器既有数据的保障,又有多连接的保障。所以简单来说,应该和3个独立的ZooKeeper机器都建立连接,而不是这3台构成一个ZooKeeper集群。


以上是关于分布式锁总结的主要内容,如果未能解决你的问题,请参考以下文章

分布式锁总结

JAVA总结--分布式锁

Redis 分布式锁的正确实现原理演化历程与 Redisson 实战总结

Redis 分布式锁的正确实现原理演化历程与 Redisson 实战总结

分布式锁总结

分布式锁总结