栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 前沿技术 > 大数据 > 大数据系统

基于Zookeeper实现的分布式锁

基于Zookeeper实现的分布式锁

zookeeper由于其node path的唯一性,也具备实现分布式锁的天然条件。同时得益于其watch机制在实现起来更方便。

本文基于golang实现的zookeeper分布式锁,仅供参考。使用的第三方library是github.com/samuel/go-zookeeper/zk .

GetLock:

GetLock相对来说比较复杂。

Zookeeper在create key的时候可以选择不同模式:

currPath, err := conn.Create(zkKey, nil, 3, zk.WorldACL(zk.PermAll))

第三个参数3表示flag, 有4中取值:

  • 0:永久,除非手动删除
  • 1:短暂,session断开则该节点也被删除
  • 2:会自动在节点后面添加序号
  • 3:Ephemeral和Sequential,即,短暂且自动添加序号

这里我们选择EPHEMERAL_SEQUENTIAL,EPHEMERAL的好处是说如果当前session断连了,那么过段时间他锁创建的key就会自动删除,就避免了死锁的问题。

SEQUENTIAL的好处是说此时zookeeper创建的节点是默认自增的,可以很方便的找到prev node path。

由于zookeeper节点的唯一性,创建节点有两种结果:

  • success:创建自增节点成功
  • err: 创建失败

创建自增节点成功后,我们会拿到创建的节点path,类似 /lock/lock-000001 这种格式,然后我们通过判断当前创建的节点是否为/lock 父节点的第一个子节点,如果是,则说明当前client获得了锁。

children, _, err := conn.Children("/lock")
    if err != nil {
        fmt.Printf("err: %v", err)
    }
    if "/lock/"+children[len(children)-1] == currPath {
        fmt.Println("lock got success.")
        return true
    }

如果不是,那么需要等待其他client释放锁。

为了避免节点删除时造成的大量网络请求,俗称羊群效应(可以参考公众号的另一篇文章),我们不会去watch /lock 这个节点,而是watch currPath-1 的节点:

这里还有一个tricky的地方,就是因为watch是两个原子操作,分别是先获取children,如果非首子节点,那么就进行watch操作,如果在watch的时候他的前一个兄弟节点已经delete了,怎么办?

exists, _, eventC, err := conn.ExistsW(prevPath) 可以看出在注册watch事件的时候,会返回一个exists的字段,如果exists是false,则说明要watch的节点已经被delete了,我们直接获得锁。

prevPath := getPrevPath(children, currPath)
    exists, _, eventC, err := conn.ExistsW(prevPath)
    if err != nil {
        fmt.Printf("err: %v", err)
    }
    if !exists {
        return true
    }
    gottenC := make(chan int)
    go func() {
    FOR:
        for {
            select {
            case e := <-eventC:
                fmt.Println("event type: " + e.Type.String())
                if e.Type == zk.EventNodeDeleted {
                    gottenC <- 1
                    break FOR
                }
            }
        }
    }()
    <-gottenC
    return true

ReleaseLock

相对于GetLock,ReleaseLock就相对简单很多,

func ReleaseLock(lockId string) {
    conn := GetConn()
    conn.Delete(lockId, 0)
}

以上,就是我们基于Zookeeper实现的一个分布式锁。

欢迎关注公众号二蛋实验室,每天一篇技术分享,分享前端后端,架构,股票心得等。

本文由博客一文多发平台 OpenWrite 发布!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/329690.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号