consul分布式锁使用纪要

使用consul的http api所提供的四个方法实现分布式锁:

lock delay的概念

lock delay是指在lock释放后,对其再lock需要等待的时间,其文档中说是收到了 http://research.google.com/archive/chubby.html 的启发,目的是尽可能防止 仍旧存活的节点获取锁之后 做出一些可能导致不一致场景出现 的操作

实现

consul的go client提供了lock方法,里面基本上就是对上述方法的封装。而因业务需求,我选择在server端增加lock方法,方便不同的client统一使用
这里用伪代码实现一个server端的lock接口,只体现主流程。写成一个blocking的操作,尝试在一段时间内不断的acquire直到成功或超时
方法返回给client sessionId,之后client可以通过这个sessionId请求renew和unlock等操作来完成整个流程

//LockOnSession basically using the same logic as the "Lock" function in github.com/hashicorp/consul/api/lock.go
func LockOnSession(key, sessionTTL) (*iface.LockOnSessionOutput, error) {

	// verify input
	{
		if _, err := time.ParseDuration(SessionTTL); err != nil {
			return &iface.LockOnSessionOutput{}, grpc.Errorf(codes.InvalidArgument, "invalid SessionTTL: %v", err)
		}
	}

	var sessionId string
	s := consulClient.Session()
	// create session
	{
		se := consulApi.SessionEntry{
			TTL:      SessionTTL,
			Behavior: consulApi.SessionBehaviorDelete, // Delete或release,按需要选择  

		}
		sessionId, _, err = s.CreateNoChecks(&se, nil)
		if nil != err {
			return &iface.LockOnSessionOutput{}, grpc.Errorf(codes.Internal, "create session error: %v", err)
		}
	}

	qOpts := &consulApi.QueryOptions{
		WaitTime: consulApi.DefaultLockWaitTime,
	}
	kv := consulClient.KV()

	start := time.Now()
	attempts := 0
WAIT:
	if attempts > 0 {
		elapsed := time.Now().Sub(start)
		start = time.Now()
		if elapsed > qOpts.WaitTime {
			s.Destroy(sessionId, nil)
			return &iface.LockOnSessionOutput{Locked: false, SessionId: ""}, nil
		}
		qOpts.WaitTime -= elapsed

	}
	attempts ++


	// Look for an existing lock, blocking until not taken
	pair, meta, err := kv.Get(Key, qOpts)
	if nil != err {
		s.Destroy(sessionId, nil)
		return &iface.LockOnSessionOutput{}, grpc.Errorf(codes.Internal, "read lock error: %v", err)
	}
	if nil != pair && consulApi.LockFlagValue != pair.Flags {
		s.Destroy(sessionId, nil)
		return &iface.LockOnSessionOutput{}, grpc.Errorf(codes.FailedPrecondition, "%v", consulApi.ErrLockConflict)
	}
	if nil != pair && "" != pair.Session {
		qOpts.WaitIndex = meta.LastIndex
		goto WAIT
	}

	// Try to acquire the lock
	lockEntry := &consulApi.KVPair{
		Key:     Key,
		Session: sessionId,
		Flags:   consulApi.LockFlagValue,
	}
	if locked, _, err := kv.Acquire(lockEntry, nil); nil != err {
		s.Destroy(sessionId, nil)
		return &iface.LockOnSessionOutput{}, grpc.Errorf(codes.Internal, "acquire lock error: %v", err)
	} else if !locked {
		// Determine why the lock failed
		if nil != pair && "" != pair.Session {
			//If the session is not null, this means that a wait can safely happen
			//using a long poll
			qOpts.WaitIndex = meta.LastIndex
			goto WAIT
		} else {
			// If the session is empty and the lock failed to acquire, then it means
			// a lock-delay is in effect and a timed wait must be used
			<-time.After(time.Second)
			goto WAIT
		}
	}
	return &iface.LockOnSessionOutput{Locked: true, SessionId: sessionId}, nil
}

转载于:https://my.oschina.net/u/3211934/blog/1619506

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值