玩转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为单进程单线程模式,采用队列模式将并发访问变成串行访问,且多客户端 ...
随机推荐
- 配置asgi来达到能处理websocket
在项目中使用了webscoket进行实时通讯,但是生产环境又使用了django+nginx+uwsgi的部署方式,我们都知道uwsgi并不能处理websocket请求,所以需要asgi服务器来处理we ...
- 洛谷 P1950 长方形_NOI导刊2009提高(2) 题解
P1950 长方形_NOI导刊2009提高(2) 题目描述 小明今天突发奇想,想从一张用过的纸中剪出一个长方形. 为了简化问题,小明做出如下规定: (1)这张纸的长宽分别为n,m.小明讲这张纸看成是由 ...
- 【概率论】6-2:大数定理(The Law of Large Numbers)
title: [概率论]6-2:大数定理(The Law of Large Numbers) categories: - Mathematic - Probability keywords: - Ma ...
- 11、spark内核架构剖析与宽窄依赖
一.内核剖析 1.内核模块 1.Application 2.spark-submit 3.Driver 4.SparkContext 5.Master 6.Worker 7.Executor 8.Jo ...
- Code Chef JUNE Challenge 2019题解
题面 \(SUMAGCD\) 先去重,易知答案一定是一个数单独一组剩下的一组,前缀后缀\(gcd\)一下就行了 //quming #include<bits/stdc++.h> #defi ...
- (18)打鸡儿教你Vue.js
介绍一下怎么安装Vue.js vue.js Vue 不支持 IE8 及以下版本,因为 Vue 使用了 IE8 无法模拟的 ECMAScript 5 特性. Vue.js是一个渐进的,可逐步采用的Jav ...
- mac php 安装php多版本
之前的开发,PHP的版本都是基于php7.3 .but!!! 接到一个老项目 tp3.1的.没法用php7.3 只能在装一个php5.6了.真坑爹.为啥还要TP3.1的项目.并且是刚开发的新项目. 真 ...
- 【MySQL 读书笔记】“order by”是怎么工作的?
针对排序来说,order by 是我们使用非常频繁的关键字.结合之前我们对索引的了解再来看这篇文章会让我们深刻理解在排序的时候,是如何利用索引来达到少扫描表或者使用外部排序的. 先定义一个表辅助我们后 ...
- npm start的时候改变端口及组合脚本
windows npm修改端口启动 set PORT=3000&&roadhog server npm start Linux npm 修改端口启动 set PORT=3000 roa ...
- 在Android Studio中找不到AppCompatActivity解决方案
在创建新的.java文件时,要导入父类中的 AppCompatActivity,报错,无法找到这个父类. 解决方案: 1.先找到“project structure”,然后app--Depende ...