基于zookeeper实现分布式锁

基于zookeeper实现分布式锁

.NET 分布式计算

详细介绍

ZookeeperLocker

背景

随着互联网的迅速发展,单点服务器已经逐渐被抛弃了。集群、分布式、微服务这些专业名词,也走进了开发者人群中。也正因为技术在不断更新以及我们不断学习,才使IT这行朝气蓬勃。但是这些知识虽然可以解决并发,增加稳定性,但是对同一资源竞争冲突还是无法避免,所以分布式锁也就进入了我们的视线。

分布式锁的几种典型解决方案

  • 基于数据库分布式锁

    数据库存在一种悲观锁(排他锁)。相当于只有提交完更新操作才能进行读取,隔离级别最高。可以通过这一特性去完成分布式锁,我们可以先去读取数据如果读取不到,则表示已经被其他线程或主机所占用该条记录,只有等待正在占用的主机或线程去提交到数据库相当于一个释放锁的操作,这条数据就能供其他连接来读取并锁住。这些是没有监听回调的,只能手动去重试连接来获取锁。

  • 基于Redis分布式锁

    redis通过SETNX来实现锁,相当于判断key是否存在来确定的,如果存在redis会返回1则表示不存在key并且插入key值成功,返回-1表示已存在key值则插入失败并且该条key-value没有设置超时时间。通过这一特性也能轻松的达到多系统同步功能,当然也是需要手动去重试来检测锁状态。会造成死锁的情况,如果一直没有删除该键则锁一直占用着(解决方案是加超时时间来避免释放不掉的情况)

  • 基于zookeeper分布式锁

    zookeeper有一套比较完整的文件系统,可以创建持久文件和临时文件等,他也提供文件操作的监听,比如删除或增加文件都会有通知。通过这一特性就可以实现锁。可以创建一个锁的序列,让所有对该资源进行插入到zookeeper文件中,zk会自动分配一个已经排好的序列节点的文件名,并且节点的删除都是存在监听的。我们可以节点从小到大的顺序去依次删除节点,只有当前节点为最小节点时才获取了锁并执行操作,当删除节点就相当于释放锁。

分布式锁对比

首先为了我写的zookeeperlocker有意义,我会主要分析redis和数据库的不足。
1. 因为前两个采用的时重试机制,对于获取锁都是不断的碰撞,并不是一个顺序的去加锁释放锁,很容易造成前面的请求迟迟碰撞不到的情况,随机性太大。
2. 重试的时间的选取也是比较麻烦的,太小容易对数据库和redis造成较大压力,太大容易给用户造成体验方面的问题,不能合理的去分配。
3. redis可以做集群忽略宕机的可能,如果数据库服务器宕机就会影响到我们写的各种服务,稳定性差。redis的通过超时时间来避免死锁这个稳定性也是不可取的比如一个占用资源出现状况占用资源的时间比超时时间要长这样就会导致锁并没有完全锁住的可能。
再讲讲zk的不足吧,性能上确实还时很差劲的和redis还是有很大距离。

使用

简单加锁操作

var zkLocker = new ZkLocker(new ZkOption()  {ConnectionsString = "192.168.1.246:2181", SessionTimeout = 30000});
zkLocker.Lock();
dosomething();
zkLocker.UnLock();

设置超时时间

var zkLocker = new ZkLocker(new ZkOption()  {ConnectionsString = "192.168.1.246:2181", SessionTimeout = 30000});
//单位毫秒
zkLocker.Lock(5000);
dosomething();
zkLocker.UnLock();
推荐源码