美文网首页Golang 开发者
golang基于etcd实现分布式锁

golang基于etcd实现分布式锁

作者: 我的饭卡呢 | 来源:发表于2018-11-17 20:11 被阅读415次

    我们希望同一时间只有一个线程能够访问到资源,但是分布式资源点之间的协调会非常麻烦,这个时候我们就需要一个分布式锁。

    etcd分布式锁实现原理:

    1.利用租约在etcd集群中创建一个key,这个key有两种形态,存在和不存在,而这两种形态就是互斥量。
    2.如果这个key不存在,那么线程创建key,成功则获取到锁,该key就为存在状态。
    3.如果该key已经存在,那么线程就不能创建key,则获取锁失败。

    锁结构体:

    在使用该锁时,需要传入Ttl,Conf,Key字段来初始化锁

    type EtcdMutex struct {
        Ttl int64  //租约时间
        Conf clientv3.Config  //etcd集群配置
        Key string   //etcd的key
        cancel context.CancelFunc  //关闭续租的func
        lease clientv3.Lease
        leaseID clientv3.LeaseID
        txn clientv3.Txn
    }
    

    初始化锁:

    func(em *EtcdMutex)init()error{
        var err error
        var ctx context.Context
        client,err := clientv3.New(em.Conf)
        if err != nil{
            return err
        }
        em.txn = clientv3.NewKV(client).Txn(context.TODO())
        em.lease = clientv3.NewLease(client)
        leaseResp,err := em.lease.Grant(context.TODO(),em.Ttl)
        if err != nil{
            return err
        }
        ctx,em.cancel = context.WithCancel(context.TODO())
        em.leaseID = leaseResp.ID
        _,err = em.lease.KeepAlive(ctx,em.leaseID)
        return err
    }
    

    获取锁:

    
    func(em *EtcdMutex)Lock()error{
        err := em.init()
        if err != nil{
            return err
        }
        //LOCK:
            em.txn.If(clientv3.Compare(clientv3.CreateRevision(em.Key),"=",0)).
                Then(clientv3.OpPut(em.Key,"",clientv3.WithLease(em.leaseID))).
                Else()
        txnResp,err := em.txn.Commit()
        if err != nil{
            return err
        }
        if !txnResp.Succeeded{   //判断txn.if条件是否成立
            return fmt.Errof("抢锁失败")        
        }
        return nil
    }
    

    释放锁:

    func(em *EtcdMutex)UnLock(){
        em.cancel()
        em.lease.Revoke(context.TODO(),em.leaseID)
        fmt.Println("释放了锁")
    }
    

    调用锁:

    func main(){
        var conf = clientv3.Config{
            Endpoints:   []string{"172.16.196.129:2380", "192.168.50.250:2380"},
            DialTimeout: 5 * time.Second,
        }
        eMutex1 := &EtcdMutex{
            Conf:conf,
            Ttl:10,
            Key:"lock",
        }
         eMutex2 := &EtcdMutex{
            Conf:conf,
            Ttl:10,
            Key:"lock",
        }
        //groutine1 
        go func() {
            err := eMutex1.Lock()
            if err != nil{
                fmt.Println("groutine1抢锁失败")
                fmt.Println(err)
                return
            }
            fmt.Println("groutine1抢锁成功")
            time.Sleep(10*time.Second)
            defer eMutex.UnLock()
        }()
    
        //groutine2
        go func() {
            err := eMutex2.Lock()
            if err != nil{
                fmt.Println("groutine2抢锁失败")
                fmt.Println(err)
                return
            }
            fmt.Println("groutine2抢锁成功")
            defer eMutex.UnLock()
        }()
        time.Sleep(30*time.Second)
    }
    
    

    相关文章

      网友评论

        本文标题:golang基于etcd实现分布式锁

        本文链接:https://www.haomeiwen.com/subject/dxrifqtx.html