Consul 是一个支持多数据中心分布式高可用的服务发现和配置共享的服务软件,由 HashiCorp 公司用 Go 语言开发, 基于 Mozilla Public License 2.0 的协议进行开源. Consul 支持健康检查,并允许 HTTP 和 DNS 协议调用 API 存储键值对.
命令行超级好用的虚拟机管理软件 vgrant 也是 HashiCorp 公司开发的产品.
一致性协议采用 Raft 算法,用来保证服务的高可用. 使用 GOSSIP 协议管理成员和广播消息, 并且支持 ACL 访问控制.
综合比较, Consul 作为服务注册和配置管理的新星, 比较值得关注和研究.
client: 客户端, 无状态, 将 HTTP 和 DNS 接口请求转发给局域网内的服务端集群.
server: 服务端, 保存配置信息, 高可用集群, 在局域网内与本地客户端通讯, 通过广域网与其他数据中心通讯. 每个数据中心的 server 数量推荐为 3 个或是 5 个.
分布式锁 ,是控制 分布式系统 之间同步访问共享 资源 的一种方式。在分布式系统中,常常需要协调他们的动作。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要 互斥 来防止彼此干扰来保证一致性,在这种情况下,便需要使用到分布式锁。
目前几乎很多大型网站及应用都是分布式部署的,分布式场景中的数据一致性问题一直是一个比较重要的话题。分布式的CAP理论告诉我们“任何一个分布式系统都无法同时满足一致性(Consistency)、可用性(Availability)和分区容错性(Partition tolerance),最多只能同时满足两项。”所以,很多系统在设计之初就要对这三者做出取舍。在互联网领域的绝大多数的场景中,都需要牺牲强一致性来换取系统的高可用性,系统往往只需要保证“最终一致性”,只要这个最终时间是在用户可以接受的范围内即可。
在很多场景中,我们为了保证数据的最终一致性,需要很多的技术方案来支持,比如分布式事务、分布式锁等。有的时候,我们需要保证一个方法在同一时间内只能被同一个线程执行。
在这里我们使用Consul来管理分布式锁。Consul内置了服务注册与发现框 架、分布一致性协议实现、健康检查、Key/Value存储、多数据中心方案,不再需要依赖其他工具(比如 ZooKeeper 等)。
session是 一个 远程 进程 和consul 节点 之间 的 链接, 它 由 一个 远程 进程 和 可以 显式 无效 或 由于 健康 检查 机制 。 根据 会话 配置 , 创建 与 已 失效 会话 锁 摧毁 或 释放 。
Consul支持多种 检查 (如 HTTP 、 TCP 等)。 在session 创建 过程中 可以 定义 的 健康 检查 列表。 这些 检查 将 用于 确定 是否sessio 需要 使 之 失效 。
除了 健康 检查 , 会话 也 具有 内置 支持 的 TTL 。 当 TTL 过期session 被视为 无效 。 远程 进程 负责 更新session 之前 TTL 过期 。
Consul API client 提供 一个 方便 的 抽象 ,session 和 K/V 存储 。 有 是 一个 锁 结构 与 锁定 、 解锁 和 破坏 的 方法 。 也 有 用于帮助 创建 锁 实例 方法 。 API 客户端 还 负责 更新 会话 。
client, err := api.NewClient(&api.Config{Address: "127.0.0.1:8500"})
type LockOptions struct { Key string // Must be set and have write permissions Value []byte // Optional, value to associate with the lock Session string // Optional, created if not specified SessionOpts *SessionEntry // Optional, options to use when creating a session SessionName string // Optional, defaults to DefaultLockSessionName (ignored if SessionOpts is given) SessionTTL string // Optional, defaults to DefaultLockSessionTTL (ignored if SessionOpts is given) MonitorRetries int // Optional, defaults to 0 which means no retries MonitorRetryTimetime.Duration // Optional, defaults to DefaultMonitorRetryTime LockWaitTime time.Duration // Optional, defaults to DefaultLockWaitTime LockTryOnce bool // Optional, defaults to false which means try forever }
LockOptions 是 所有 可能 的 选项 的 容器 , 可以 用于 设置 键 和 值 、 定制 会话 或 设置 TTL 。
opts := &api.LockOptions{ Key: "webhook_receiver/1", Value: []byte("set by sender 1"), SessionTTL: "10s", SessionOpts: &api.SessionEntry{ Checks: []string{"check1", "check2"}, Behavior: "release", }, } lock, err := client.LockOpts(opts)
另一种常用的 方法 是 LockKey, 它 创建 一个 锁 与 所有 选项 设置 为 默认 条目 名称 除外 。
lock, err := client.LockKey("webhook_receiver/1")
stopCh := make(chan struct{}) lockCh, err := lock.Lock(stopCh) if err != nil { panic(err) } cancelCtx, cancelRequest := context.WithCancel(context.Background()) req, _ := http.NewRequest("GET", "https://example.com/webhook", nil) req = req.WithContext(cancelCtx) gofunc() { http.DefaultClient.Do(req) select { case <-cancelCtx.Done(): log.Println("request cancelled") default: log.Println("request done") err = lock.Unlock() if err != nil { log.Println("lock already unlocked") } } }() gofunc() { <-lockCh cancelRequest() }()
Golang 通过 Consul 实现分布式锁