玩转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为单进程单线程模式,采用队列模式将并发访问变成串行访问,且多客户端 ...
随机推荐
- 【CSS3】 新增属性
一. box-shadow(阴影效果) 使用: box-shadow: 20px 10px 0 #000; -moz-box-shadow: 20px 10px 0 #000; -webkit-box ...
- c函数指针和指针函数如何使用何定义;如何调用使用
#include <stdio.h> int * sum(int x); //声明一个 指针函数 返回类型位一个指针变量 可以通过*p来获取值 int (*pfun)(int,int);/ ...
- 如何选择梯度下降法中的学习速率α(Gradient Descent Learning Rate Alpha)
梯度下降算法的任务是寻找参数θ,使之能够最小化损失函数. 那么梯度下降法中的学习速率α应该如何选择呢?通常我们画出损失函数随迭代次数增加而变化的曲线. 可能会得到如下的一条曲线,x轴表示迭代次数,y轴 ...
- Docker 常用命令,自用,持续更
1.进入容器 docker exec -it 容器id /bin/bash docker exec -it db30f533ee1b /bin/bash 2.复制文件到容器 docker cp 文件路 ...
- phpMyadmin各个版本漏洞【转载】
原作者:热爱网络安全的小菜狗 原文链接:phpMyadmin各版本漏洞 0x01 PREGREPLACEEVAL漏洞 影响版本:3.5.x < 3.5.8.1 and 4.0.0 < 4. ...
- Zk单机多实例部署
一.环境准备 当前环境:centos7.3一台软件版本:zookeeper-3.5.2部署目录:/usr/local/zookeeper启动端口:2181,2182,2183配置文件:/usr/loc ...
- Android根据内网外网连接情况配置服务器访问IP
新项目的app,可通过内网和外网的服务器ip进行请求访问,但是客户提供了专业终端,终端在wifi情况下走外网内网都可以,但关闭wifi则只能走4G专网,也就是只能走内网. 可前往我的小站查看:Andr ...
- centos下php扩展安装imagemagick
centos下php扩展安装imagemagick 2015-10-23TONY7PHP 对于php的imagick主要是两部分的安装 ImageMagick主程序地址http://www.image ...
- win10创建Ubuntu16.04子系统,安装常用软件以及图形界面(包括win10远程桌面连接Ubuntu)
一.开启win10子系统 [ Windows Subsystem for Linux(WSL)] 二.基本配置 三.安装常用的软件 安装配置zsh 使用 bash 客户端软件 cmder(其实是win ...
- C# WinForm MessageBox弹窗倒计时的自动关闭
[DllImport("user32.dll", EntryPoint = "FindWindow")] private static exter ...