玩转CONSUL(2)–分布式锁
1. 前言
分布式锁的场景,大家应该都有遇到过。比如对可靠性有较高要求的系统中,我们需要做主备切换。这时我们可以利用分布式锁,来做选主动作,抢到锁作为主,执行对应的任务,剩余的实例作为备份
redis和zookeeper都可以用来做分布式锁,典型的如redis,可以使用SETNX
命令来实现分布式锁。本文将介绍基于consul的分布式锁实现
2. 例子
测试例子test_lock.go
package main
import (
"github.com/hashicorp/consul/api"
"log"
"strconv"
"sync"
"time"
)
func main() {
wg := &sync.WaitGroup{}
for i := 0; i < 3; i++ {
wg.Add(1)
go tryLock("mylock", "session"+strconv.Itoa(i), wg)
}
wg.Wait()
}
func tryLock(key string, sessionName string, wg *sync.WaitGroup) {
defer wg.Done()
// Get a new client
config := &api.Config{
Address: "dev1:8500",
Scheme: "http",
}
client, err := api.NewClient(config)
if err != nil {
panic(err)
}
opts := &api.LockOptions{
Key: key,
SessionName: sessionName,
}
lock, err := client.LockOpts(opts)
log.Println(sessionName, "try to get lock obj")
for i := 0; i < 3; i++ {
leaderCh, err := lock.Lock(nil)
if err != nil {
log.Println("err", err, sessionName)
}
if leaderCh == nil{
log.Println("err", err, sessionName)
continue
}
log.Println(sessionName, "lock and sleep")
time.Sleep(5 * time.Second)
err = lock.Unlock()
if err != nil {
log.Fatal("err", err)
}
log.Println(sessionName, "unlock")
time.Sleep(5 * time.Second)
}
}
3. 原理
consul中锁的主要是依赖KV Store和Session相关API
3.1 创建session
PUT /v1/session/create 创建1个session
3.2 加锁
PUT /v1/kv/{key}?acquire={sessionId}
这里的key是锁的名称
如果成功加锁,则consul返回true, 否则返回false
注意:获取失败,接口并不阻塞,如果想要加锁,需要再次发起请求
可以使用 GET /v1/kv/{key} 获取锁信息
[
{
"LockIndex": 91,
// 锁的名称
"Key": "mylock",
"Flags": 3304740253564472344,
"Value": null,
// sessionId
// 从这里可以看出当前是那个session持有锁
"Session": "c090b464-23f3-bce1-d999-6163ba6eb91f",
"CreateIndex": 2588219,
"ModifyIndex": 2590269
}
]
3.3 保持会话
PUT /v1/session/renew/{sessionId}
锁是有生命周期,它的生命周期是与session的生命周期一致 因此对于锁的持有者,它需要周期性的执行renew session,以确保session关联的锁不被释放。hashicorp/consul/api
的实现是 每隔TTL/2 执行1次renew
3.4 释放锁
有2种方式可以释放锁
1) 主动释放
PUT /v1/kv/{key}?release={sessionId}
2)被动释放(session超时或者被check为invalidate
)
锁释放以后
[
{
"LockIndex": 109,
"Key": "mylock",
"Flags": 3304740253564472344,
"Value": null,
// 可以看到已经没有session信息里
"CreateIndex": 2588219,
"ModifyIndex": 2592871
}
]
4. 注意
1个client释放锁之后,其它client无法立刻获得锁,这可能是由于lock-delay设置引起的。
The final nuance is that sessions may provide a lock-delay. This is a time duration, between 0 and 60 seconds. When a session invalidation takes place, Consul prevents any of the previously held locks from being re-acquired for the lock-delay interval; this is a safeguard inspired by Google’s Chubby. The purpose of this delay is to allow the potentially still live leader to detect the invalidation and stop processing requests that may lead to inconsistent state. While not a bulletproof method, it does avoid the need to introduce sleep states into application logic and can help mitigate many issues. While the default is to use a 15 second delay, clients are able to disable this mechanism by providing a zero delay value.
为防止由于网络波动等原因,session的状态被错误的检查为invalidate
导致锁被释放。此时如果其它client需要加锁,则需要等待lock-delay
,才能再次加锁成功。(主动释放没有这个问题)
可以将lock-delay
设置成0,表示不启用lock-delay
机制
3. 参考资料
玩转CONSUL(2)–分布式锁的更多相关文章
- consul实现分布式锁
分布式一致性问题: 分布式的CAP理论告诉我们"任何一个分布式系统都无法同时满足一致性(Consistency).可用性(Availability)和分区容错性(Partition tole ...
- 服务注册发现consul之四: 分布式锁之四:基于Consul的KV存储和分布式信号量实现分布式锁
一.基于key/value实现 我们在构建分布式系统的时候,经常需要控制对共享资源的互斥访问.这个时候我们就涉及到分布式锁(也称为全局锁)的实现,基于目前的各种工具,我们已经有了大量的实现方式,比如: ...
- 基于Redis的分布式锁真的安全吗?
说明: 我前段时间写了一篇用consul实现分布式锁,感觉理解的也不是很好,直到我看到了这2篇写分布式锁的讨论,真的是很佩服作者严谨的态度, 把这种分布式锁研究的这么透彻,作者这种技术态度真的值得我好 ...
- Java分布式锁看这篇就够了
### 什么是锁? 在单进程的系统中,当存在多个线程可以同时改变某个变量(可变共享变量)时,就需要对变量或代码块做同步,使其在修改这种变量时能够线性执行消除并发修改变量. 而同步的本质是通过锁来实现的 ...
- 利用consul在spring boot中实现最简单的分布式锁
因为在项目实际过程中所采用的是微服务架构,考虑到承载量基本每个相同业务的服务都是多节点部署,所以针对某些资源的访问就不得不用到用到分布式锁了. 这里列举一个最简单的场景,假如有一个智能售货机,由于机器 ...
- 基于Redis实现分布式锁(1)
转自:http://blog.csdn.net/ugg/article/details/41894947 背景在很多互联网产品应用中,有些场景需要加锁处理,比如:秒杀,全局递增ID,楼层生成等等.大部 ...
- Java分布式锁,搞懂分布式锁实现看这篇文章就对了
随着微处理机技术的发展,人们只需花几百美元就能买到一个CPU芯片,这个芯片每秒钟执行的指令比80年代最大的大型机的处理机每秒钟所执行的指令还多.如果你愿意付出两倍的价钱,将得到同样的CPU,但它却以更 ...
- 【转】Redis学习笔记(四)如何用Redis实现分布式锁(1)—— 单机版
原文地址:http://bridgeforyou.cn/2018/09/01/Redis-Dsitributed-Lock-1/ 为什么要使用分布式锁 这个问题,可以分为两个问题来回答: 为什么要使用 ...
- 基于Redis实现分布式锁实战
背景在很多互联网产品应用中,有些场景需要加锁处理,比如:秒杀,全局递增ID,楼层生成等等.大部分的解决方案是基于DB实现的,Redis为单进程单线程模式,采用队列模式将并发访问变成串行访问,且多客户端 ...
随机推荐
- C利用time函数实现简单的定时器
//定时器 #include <stdio.h> #include <time.h> #include <stdlib.h> int main(int num, c ...
- 《挑战30天C++入门极限》c++中指针学习的两个绝好例子
c/c++中指针学习的两个绝好例子 对于众多人提出的c/c++中指针难学的问题做个总结: 指针学习不好关键是概念不清造成的,说的简单点就是书没有认真看,指针的学习犹如人在学习饶口令不多看多学多 ...
- SpringCloud:Ribbon负载均衡
1.概述 Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端 负载均衡的工具. 简单的说,Ribbon是Netflix发布的开源项目,主要功能是提供客 ...
- 线程池(6)-submit与execute区别
在线程池里提交任务经常见到submit与execute,如何选择,傻傻分不清楚.那么他们俩有什么区别,使用场景是什么?这篇博客将会介绍. 1.方法定义 void execute(Runnable co ...
- Docker镜像使用
当运行容器时,使用的镜像如果在本地中不存在,docker 就会自动从 docker 镜像仓库中下载,默认是从 Docker Hub 公共镜像源下载. 下面我们来学习: 1.管理和使用本地 Docker ...
- ubuntu之路——day11.2 快速搭建系统并进行迭代、在不同的划分上进行训练和测试
快速搭建系统并进行迭代 1.建立dev/test set,并确定你的目标 2.快速建立初始化的系统 3.使用前面提到的bias/variance分析和错误分析来进行模型优化和迭代 针对以上的过程,An ...
- 【转】JDK5.0中JVM堆模型、GC垃圾收集详细解析
基本概念 堆/Heap JVM管理的内存叫堆:在32Bit操作系统上有4G的限制,一般来说Windows下为2G,而Linux下为3G:64Bit的就没有这个限制.JVM初始分配的内存由-Xms指定, ...
- html5中的fieldset/legend元素和keygen元素
html5中的fieldset/legend元素和keygen元素 一.总结 一句话总结: fieldset/legend元素和figure和figcaption很像,只不过是作用于表单,前者表示内容 ...
- pt-table-checksum解读【转】
pt-table-checksum是目前可以说是最好的查看主从一致性的工具 先来个使用例子,有助快速上手使用 在主库执行: mysql>GRANT SELECT, PROCESS, SUPER, ...
- oracle tablespace pctfree pctused
二.oracle pctfree和pctused详解 一.建立表时候,注意PCTFREE参数的作用 PCTFREE:为一个块保留的空间百分比,表示数据块在什么情况下可以被insert,默认是10,表示 ...