etcd实现分布式锁

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

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

package main

import (
	"go.etcd.io/etcd/v3/clientv3"
	"context"
	"fmt"
	"time"
)

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.Errorf("抢锁失败")
	}
	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{"localhost:2379"},
		DialTimeout:time.Duration(5*time.Second),
	}

	eMutex1 := &EtcdMutex{Conf:conf,Ttl:10,Key:"Dlock"}
	eMutex2 := &EtcdMutex{Conf:conf,Ttl:10,Key:"Dlock"}
	go func() {
		AA:err := eMutex1.Lock()
		if err != nil{
			fmt.Println("eMutex1 catch lock failed")
			time.Sleep(time.Second)
			goto AA
		}else {
			fmt.Println("eMutex1 catch lock success")
			time.Sleep(time.Second * 10)
			fmt.Println("eMutex1 release")
			eMutex1.UnLock()
		}
	}()

	go func() {
	BB:err := eMutex2.Lock()
		if err != nil{
			fmt.Println("eMutex2 catch lock failed")
			time.Sleep(time.Second)
			goto BB
		}else {
			fmt.Println("eMutex2 catch lock success")
			time.Sleep(time.Second * 10)
			fmt.Println("eMutex2 release")
			eMutex2.UnLock()
		}
	}()

	time.Sleep(time.Second*30)
}

结果
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值