Consul分布式锁原理详解及实例

Posted 魏小言

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Consul分布式锁原理详解及实例相关的知识,希望对你有一定的参考价值。

Consul分布式锁原理详解及实例

现在大型系统为了保证服务高可用,都采用分布式架构提供服务。Consul是一款较zookeepr、etcd等年轻的纯Goland分布式服务架构。其包含多个功能模块服务发现、检查健康、K/V存储、多数据中心等,这里就其分布式锁进行介绍。

Consul分布式锁实现和其K/V存储的特性密切相关。K/V存储在业务中最常见的之一是Redis「基于K/V设计的存储、中间件等等很多,相对Redis是业务开发中接触更普遍的其中一个」,其SetNx可以出色的完成分布式锁的功能。Consul与Redis机制不同,Consul依赖K/V与Session的绑定关系,进而完成互斥锁定。

Session是什么呢/?在Consul中,session的概念和浏览器的session类似,标识本次操作owner,类似句柄。与Node/K-V关联,上游是一Node,下游多个K-V,相关系列函数包含renew、acquire、destroy、create…。
「源码:github.com/hashicorp/consul/api@v1.4.0/session.go」

K-V就是常规键值对,在Consul中,通过Api进行Get-Set。
「源码:github.com/hashicorp/consul/api@v1.4.0/kv.go」

Consul实现分布式锁,准确来讲,和K/V、Session各自功能没什么关联,主要应用的是两者之间的关系。
简单来说,根据Key绑定的Session判断是否可抢占。流程见下图:
在这里插入图片描述

其详细源码见:github.com/hashicorp/consul/api@v1.4.0/lock.go

其中含大量参数细节,着重注意:

// Lock 分布式锁数据结构
type Lock struct {
    c    *Client   // 提供访问consul的API客户端
    opts *LockOptions // 分布式锁的可选项
    isHeld       bool          // 该锁当前是否已经被持有
    sessionRenew chan struct{} // 通知锁持有者需要更新session
    locksession  string        // 锁持有者的session
    l            sync.Mutex    // 锁变量的互斥锁
}
// LockOptions 提供分布式锁的可选项参数
type LockOptions struct {
    Key              string        // 锁的 Key,必填项,且必须有 KV 的写权限
    Value            []byte        // 锁的内容,以下皆为选填项
    Session          string        // 锁的session,用于判断锁是否被创建
    SessionOpt       *SessionEntry // 自定义创建session条目,用于创建session,避免惊群
    SessionName      string        // 自定义锁的session名称,默认为 "Consul API Lock"
    SessionTTL       string        // 自定义锁的TTL时间,默认为 "15s"
    MonitorRetries   int          // 自定义监控的重试次数,避免脑裂问题
    MonitorRetryTime time.Duration // 自定义监控的重试时长,避免脑裂问题
    LockWaitTime     time.Duration // 自定义锁的等待市场,避免死锁问题
    LockTryOnce      bool          // 是否只重试一次,默认为false,则为无限重试
}

注意:lock delay需要注意一下。 在使用etcd和redis
redlock实现分布式锁的时候,一个节点释放锁,另一个节点可以立马拿到锁, 就算有延迟也只是网络上的调用开销。但consul的lock
delay策略不是这样的,一个节点释放锁了,另一个节点不能立马拿到锁。需要等待lock delay时间后才可以拿到锁「脑裂现象」。

Q&A
1、Consul分布式锁最终会落地以Api形式到Consul,那么Consul如何保证两个Http请求的原子性/?
Consul分布式强一致性算法Raft,及满足CAP的弱一致性方案Gossip协议。


2、Consul分布式强一致性与Session提供的分布式锁关系/? Session分布式锁基于Consul强一致特性

「要正确得实现了Paxos和Raft算法都不是一件特别容易的事,尤其是Paxos,Raft还好些。但如果想每一个服务都嵌入一个Paxos或者Raft,这对于维护将是一场灾难。Google的做法是使用Chubby作为一致性的基础服务提供者,在这之上提供分布式锁和Leader选举的服务(是不是有点PaaS的味道)。」

下附:
1、文档:
https://learn.hashicorp.com/tutorials/consul/application-leader-elections#overview
https://learn.hashicorp.com/tutorials/consul/application-leader-elections
2、编码demo

func DynamicCollectLog(arguments docopt.Opts) {
    lockCollect, err := lock.ConsulLock()
    if err != nil {
        log.Infof("DynamicCollectLog ConsulLock Lock fail")
        return
    }
    defer lockCollect.Unlock()
    _ = CmdCollect(arguments)
    sigCh := make(chan os.Signal, 1)
    signal.Notify(sigCh, syscall.SIGTERM, syscall.SIGINT)
    for {
        select {
        case sig, _ := <-sigCh:
            fmt.Printf("DynamicCollectLog ConsulLock(%s),  Unlock...\\n", sig)
            log.Errorf("DynamicCollectLog ConsulLock(%s),  Unlock...", sig)
            err = lockCollect.Unlock()
            if err != nil {
                log.Infof("DynamicCollectLog ConsulUnlock fail")
            }else{
                log.Info("DynamicCollectLog ConsulLock Unlocked")
            }
        }
    }
}


func ConsulLock() (lock *api.Lock, err error) {
    client, err := api.NewClient(&api.Config{})
    if err != nil {
        log.Infof("ConsulLock failed to created client %v", err)
        return nil, err
    }
    lockKey := "FlowAnalysis_Collect_Consul_Lock_key"
    lock, err = client.LockOpts(&api.LockOptions{
        Key:        lockKey,
        Value:      []byte("sender 1"),
        SessionTTL: "10s",
    })
    if err != nil {
        log.Infof("ConsulLock failed to created lock %v", err)
        return nil, err
    }
    _, err = lock.Lock(nil)
    if err != nil {
        log.Infof("ConsulLock failed to accquired lock")
        return nil, err
    }
    return lock, nil
}

以上是关于Consul分布式锁原理详解及实例的主要内容,如果未能解决你的问题,请参考以下文章

分布式服务治理zookeeper原理及使用大全

你真正了解过Consul吗——掌握Consul分布式锁一篇就够了

Consul 核心原理解析之-Raft leader选举

ZooKeeper原理详解及常用操作

详解docker compose,consul!!

基于Consul的分布式锁实现