当前位置: 首页 > news >正文

etcd之etcd分布式锁及事务(四)

1、etcd分布式锁及事务

1.1 前言

分布式锁是控制分布式系统之间同步访问共享资源的一种方式。在分布式系统中,常常需要协调他们的动作。如

果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥

来防止彼此干扰来保证一致性,在这种情况下,便需要使用到分布式锁。

1.2 etcd分布式锁设计

1、排他性:任意时刻,只能有一个机器的一个线程能获取到锁。

通过在etcd中存入key值来实现上锁,删除key实现解锁,参考下面伪代码:

func Lock(key string, cli *clientv3.Client) error {//获取key,判断是否存在锁resp, err := cli.Get(context.Background(), key)if err != nil {return err}//锁存在,返回上锁失败if len(resp.Kvs) > 0 {return errors.New("lock fail")}_, err = cli.Put(context.Background(), key, "lock")if err != nil {return err}return nil
}
//删除key,解锁
func UnLock(key string, cli *clientv3.Client) error {_, err := cli.Delete(context.Background(), key)return err
}

当发现已上锁时,直接返回lock fail。也可以处理成等待解锁,解锁后竞争锁。

//等待key删除后再竞争锁
func waitDelete(key string, cli *clientv3.Client) {rch := cli.Watch(context.Background(), key)for wresp := range rch {for _, ev := range wresp.Events {switch ev.Type {case mvccpb.DELETE: //删除return}}}
}

2、容错性:只要分布式锁服务集群节点大部分存活,client就可以进行加锁解锁操作。

etcd基于Raft算法,确保集群中数据一致性。

3、避免死锁:分布式锁一定能得到释放,即使client在释放之前崩溃。

上面分布式锁设计有缺陷,假如client获取到锁后程序直接崩了,没有解锁,那其他线程也无法拿到锁,导致死锁

出现。

通过给key设定leases来避免死锁,但是leases过期时间设多长呢?假如设了30秒,而上锁后的操作比30秒

大,会导致以下问题:

  • 操作没完成,锁被别人占用了,不安全

  • 操作完成后,进行解锁,这时候把别人占用的锁解开了

解决方案:给key添加过期时间后,以Keep leases alive方式延续leases,当client正常持有锁时,锁不会过

期;当client程序崩掉后,程序不能执行Keep leases alive,从而让锁过期,避免死锁。看以下伪代码:

//上锁
func Lock(key string, cli *clientv3.Client) error {//获取key,判断是否存在锁resp, err := cli.Get(context.Background(), key)if err != nil {return err}//锁存在,等待解锁后再竞争锁if len(resp.Kvs) > 0 {waitDelete(key, cli)return Lock(key)}//设置key过期时间resp, err := cli.Grant(context.TODO(), 30)if err != nil {return err}//设置key并绑定过期时间_, err = cli.Put(context.Background(), key, "lock", clientv3.WithLease(resp.ID))if err != nil {return err}//延续key的过期时间_, err = cli.KeepAlive(context.TODO(), resp.ID)if err != nil {return err}return nil
}
//通过让key值过期来解锁
func UnLock(resp *clientv3.LeaseGrantResponse, cli *clientv3.Client) error {_, err := cli.Revoke(context.TODO(), resp.ID)return err
}

经过以上步骤,我们初步完成了分布式锁设计。其实官方已经实现了分布式锁,它大致原理和上述有出入,接下来

我们看下如何使用官方的分布式锁。

1.3 etcd分布式锁使用

package mainimport ("context""fmt""github.com/coreos/etcd/clientv3""github.com/coreos/etcd/clientv3/concurrency""log"
)var endpoints = []string{"localhost:2379"}func ExampleMutex_Lock() {cli, err := clientv3.New(clientv3.Config{Endpoints: endpoints})if err != nil {log.Fatal(err)}defer cli.Close()// create two separate sessions for lock competitions1, err := concurrency.NewSession(cli)if err != nil {log.Fatal(err)}defer s1.Close()m1 := concurrency.NewMutex(s1, "/my-lock/")s2, err := concurrency.NewSession(cli)if err != nil {log.Fatal(err)}defer s2.Close()m2 := concurrency.NewMutex(s2, "/my-lock/")// acquire lock for s1if err := m1.Lock(context.TODO()); err != nil {log.Fatal(err)}fmt.Println("acquired lock for s1")m2Locked := make(chan struct{})go func() {defer close(m2Locked)// wait until s1 is locks /my-lock/if err := m2.Lock(context.TODO()); err != nil {log.Fatal(err)}}()if err := m1.Unlock(context.TODO()); err != nil {log.Fatal(err)}fmt.Println("released lock for s1")<-m2Lockedfmt.Println("acquired lock for s2")
}func main() {ExampleMutex_Lock()
}
# 输出
acquired lock for s1
released lock for s1
acquired lock for s2

此代码来源于官方文档,etcd分布式锁使用起来很方便。

1.4 etcd事务

顺便介绍一下etcd事务,先看这段伪代码:

Txn(context.TODO()).If(//如果以下判断条件成立Compare(Value(k1), "<", v1),Compare(Version(k1), "=", 2)
).Then(//则执行Then代码段OpPut(k2,v2), OpPut(k3,v3)
).Else(//否则执行Else代码段OpPut(k4,v4), OpPut(k5,v5)
).Commit()//最后提交事务
package mainimport ("context""fmt""github.com/coreos/etcd/clientv3""log""time"
)var endpoints = []string{"localhost:2379"}func ExampleKV_txn() {cli, err := clientv3.New(clientv3.Config{Endpoints:   endpoints,DialTimeout: 5 * time.Second,})if err != nil {log.Fatal(err)}defer cli.Close()kvc := clientv3.NewKV(cli)_, err = kvc.Put(context.TODO(), "key", "xyz")if err != nil {log.Fatal(err)}ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)_, err = kvc.Txn(ctx).// txn value comparisons are lexicalIf(clientv3.Compare(clientv3.Value("key"), ">", "abc")).// the "Then" runs, since "xyz" > "abc"Then(clientv3.OpPut("key", "XYZ")).// the "Else" does not runElse(clientv3.OpPut("key", "ABC")).Commit()cancel()if err != nil {log.Fatal(err)}gresp, err := kvc.Get(context.TODO(), "key")cancel()if err != nil {log.Fatal(err)}for _, ev := range gresp.Kvs {fmt.Printf("%s : %s\n", ev.Key, ev.Value)}
}func main() {ExampleKV_txn()
}
# 输出
key : XYZ

上面的使用例子,代码来自官方文档。

1.5 总结

如果发展到分布式服务阶段,且对数据的可靠性要求很高,选etcd实现分布式锁不会错。一般的Redis分布式

锁,可能出现锁丢失的情况(如果你是Java开发者,可以使用Redisson客户端实现分布式锁,据说不会出现锁丢

失的情况)。

相关文章:

etcd之etcd分布式锁及事务(四)

1、etcd分布式锁及事务 1.1 前言 分布式锁是控制分布式系统之间同步访问共享资源的一种方式。在分布式系统中&#xff0c;常常需要协调他们的动作。如 果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源&#xff0c;那么访问这些资源的时候&#xff0c;往往需要…...

智慧旅游微信小程序平台

作者介绍&#xff1a;✌️大厂全栈码农|毕设实战开发&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。 &#x1f345;获取源码联系方式请查看文末&#x1f345; 推荐订阅精彩专栏 &#x1f447;&#x1f3fb; 避免错过下次更新 Springboot项目精选实战案例 更多项目…...

C++设计模式创建型模式———简单工厂模式、工厂方法模式、抽象工厂模式

文章目录 一、引言二、简单工厂模式三、工厂方法模式三、抽象工厂模式四、总结 一、引言 创建一个类对象的传统方式是使用关键字new &#xff0c; 因为用 new 创建的类对象是一个堆对象&#xff0c;可以实现多态。工厂模式通过把创建对象的代码包装起来&#xff0c;实现创建对…...

C++ 类与对象(中) 默认成员函数

我们知道在类中&#xff0c;有成员变量和成员函数&#xff0c;我们可以通过创造不同的成员函数来实现这个类不同的功能&#xff0c;如果我们创造一个类&#xff0c;却不实现它的成员函数会如何呢&#xff1f;这个就涉及到类中的默认成员函数的概念了。但在本文我们主要介绍以下…...

中间人攻击(https降级攻击)和iptables命令分析

中间人攻击 以下是一个简单的中间人攻击示例&#xff0c;结合 ARP 欺骗和流量修改&#xff1a; 1. 进行 ARP 欺骗 首先&#xff0c;使用 arpspoof 进行 ARP 欺骗&#xff0c;将受害者的流量重定向到攻击者的机器上&#xff1a; sudo arpspoof -i eth0 -t 172.29.144.50 172…...

开源生活-分布式管理

开源竞争&#xff08;当自己没有办法彻底掌握一门技术的时候就彻底开源掉&#xff1b;培养出更多的依赖&#xff0c;让更多人帮助你完善你的技术&#xff0c;那么这不就是在砸罐子吗&#xff1f;一个行业里面总会有人先砸罐子的&#xff0c;你不如先砸罐子&#xff0c;还能听个…...

华为OD机试真题- 关联子串

该专栏题目包含两部分&#xff1a; 100 分值部分题目 200 分值部分题目 所有题目都会陆续更新&#xff0c;订阅防丢失 题目描述&#xff1a; 给定两个字符串str1和str2&#xff0c;如果字符串str1中的字符&#xff0c;经过排列组合后的字符串中&#xff0c;只要有一个字符串是…...

云智慧完成华为原生鸿蒙系统的适配, 透视宝 APM 为用户体验保驾护航

2024 年 10 月 22 日&#xff0c;首个国产移动操作系统 —— 华为原生鸿蒙操作系统 HarmonyOS NEXT 正式面世&#xff0c;成为继 iOS 和 Android 后的全球第三大移动操作系统。HarmonyOS NEXT&#xff0c;从系统内核、数据库根基&#xff0c;到编程语言创新、AI&#xff08;人工…...

QT 多语言转换 ts、qm

QT开发之路 企业级开发系列文章&#xff0c;主要目标快速学习、完善、提升 相关技能 高效完成企业级项目开发 分享在企业中积累的实用技能和经验。 通过具体的编码过程、代码示例、步骤详解、核心内容和展示的方法解决遇到的实际问题。 阅读前声明 本系列文章属于付费内容 禁止…...

C++学习:类和对象(二)

一、默认成员函数 1. 什么是默认成员函数&#xff1f; 在C中&#xff0c;每个类都有一些特殊的成员函数&#xff0c;如果程序员没有显式地声明&#xff0c;编译器会自动为类生成这些函数&#xff0c;这些函数称为默认成员函数 2. 默认成员函数列表 默认构造函数&#xff08…...

深度学习(五):语音处理领域的创新引擎(5/10)

一、深度学习在语音处理中的崛起 在语音处理领域&#xff0c;传统方法如谱减法、维纳滤波等在处理复杂语音信号时存在诸多局限性。这些方法通常假设噪声是平稳的&#xff0c;但实际噪声往往是非平稳的&#xff0c;导致噪声估计不准确。同时&#xff0c;为了去除噪声&#xff0…...

双曲函数(Hyperbolic functuons)公式

在python等语言里有双曲函数库和反双曲函数库&#xff0c;但是并没有包含所有的双曲函数。以numpy为例子&#xff0c;numpy只提供了sinh、cosh、tanh、arcsinh、arccosh、arctanh六种函数&#xff0c;那么其余的就需要用公式计算了。 转换公式 对于函数库不能直接计算的&#…...

【CSS/SCSS】@layer的介绍及使用方法

目录 基本用法layer 的作用与优点分离样式职责&#xff0c;增强代码可读性和可维护性防止无意的样式冲突精确控制样式的逐层覆盖提高复用性 兼容性实际示例&#xff1a;使用 import 管理加载顺序实际示例&#xff1a;混入与 layer 结合使用 layer 是 CSS 中用于组织和管理样式优…...

我为什么投身于青少年AI编程?——打造生态圈(三)

第五部分 青少年AI编程生态圈 一、生态圈 主要涵盖家庭、社区/中小学、高校高职、主管部门。 1、家庭 我们与社区/中小学一道打造让家长满意的模式。 教得好&#xff1a; 费用少&#xff1a; 家门口&#xff1a; 2、社区/中小学 社区党群服务中心和中小学都有大面积科普…...

出海要深潜,中国手机闯关全球化有了新标杆

经济全球化的大势之下&#xff0c;中国科技企业开拓海外市场已成为一种必然选择。 对于国内手机企业来说&#xff0c;推进全球商业版图扩张&#xff0c;业务潜力巨大&#xff0c;海外市场是今后的关键增长引擎。 当前中国手机厂商在海外市场的发展&#xff0c;有收获也有坎坷…...

百度SEO中的关键词密度与内容优化研究【百度SEO专家】

大家好&#xff0c;我是百度SEO专家&#xff08;林汉文&#xff09;&#xff0c;在百度SEO优化中&#xff0c;关键词密度和关键词内容的优化对提升页面排名至关重要。关键词的合理布局与内容的质量是确保网页在百度搜索结果中脱颖而出的关键因素。下面我们将从关键词密度和关键…...

如何用fastapi集成pdf.js 的viewer.html ,并支持 mjs

fastapi 框架 集成pdf.js 的 viewer.html?file=***,支持跨域,支持.mjs .wasm .pdf 给出完整示例代码 要在 FastAPI 框架中集成 pdf.js 的 viewer.html,并支持跨域访问以及 .mjs、.wasm、.pdf 文件的正确加载,可以按照以下步骤进行。下面提供一个完整的示例,包括项目结构…...

文件相对路径与绝对路径

前言&#xff1a; 在写代码绘制图像的过程中&#xff0c;发现出现cant read input file的异常&#xff0c;而且输出框没有绘制图片&#xff0c;所以寻找解决方案。先贴上之前写的简洁版绘制图像代码 1.BackGround类 import java.awt.image.BufferedImage;public class BackG…...

Linux 重启命令全解析:深入理解与应用指南

Linux 重启命令全解析&#xff1a;深入理解与应用指南 在 Linux 系统中&#xff0c;掌握正确的重启命令是确保系统稳定运行和进行必要维护的关键技能。本文将深入解析 Linux 中常见的重启命令&#xff0c;包括功能、用法、适用场景及注意事项。 一、reboot 命令 功能简介 re…...

【北京迅为】《STM32MP157开发板嵌入式开发指南》-第六十七章 Trusted Firmware-A 移植

iTOP-STM32MP157开发板采用ST推出的双核cortex-A7单核cortex-M4异构处理器&#xff0c;既可用Linux、又可以用于STM32单片机开发。开发板采用核心板底板结构&#xff0c;主频650M、1G内存、8G存储&#xff0c;核心板采用工业级板对板连接器&#xff0c;高可靠&#xff0c;牢固耐…...

Degrees of Lewdity中文本地化版本完全指南:从安装到精通

Degrees of Lewdity中文本地化版本完全指南&#xff1a;从安装到精通 【免费下载链接】Degrees-of-Lewdity-Chinese-Localization Degrees of Lewdity 游戏的授权中文社区本地化版本 项目地址: https://gitcode.com/gh_mirrors/de/Degrees-of-Lewdity-Chinese-Localization …...

浪潮服务器硬盘红灯报警?手把手教你更换RAID阵列故障盘(附同步失败解决方案)

浪潮服务器硬盘红灯报警全流程处置指南&#xff1a;从故障诊断到阵列重建 当浪潮服务器的硬盘指示灯突然亮起刺眼的红色&#xff0c;大多数运维人员的第一反应往往是心头一紧。这种视觉警报不仅意味着硬件故障&#xff0c;更可能预示着数据丢失的风险。不同于普通PC的硬盘故障…...

League Akari:英雄联盟玩家的终极智能辅助工具实战指南

League Akari&#xff1a;英雄联盟玩家的终极智能辅助工具实战指南 【免费下载链接】League-Toolkit 兴趣使然的、简单易用的英雄联盟工具集。支持战绩查询、自动秒选等功能。基于 LCU API。 项目地址: https://gitcode.com/gh_mirrors/le/League-Toolkit 你是否厌倦了在…...

告别用人“开盲盒”|江湖背调定义全生命周期风控范式

企业用人别踩坑&#xff01;传统单次背调只有入口安检&#xff0c;无法应对员工在职动态风险&#xff0c;漏洞百出江湖背调以“雇前可信、在职可控”&#xff0c;正式定义全生命周期用工风控范式&#xff0c;筑牢从招聘到离职全链路安全屏障&#xff01;传统背调vs全生命周期风…...

【实战教程】OpenClaw从零开始配置指南:从边界到稳定的分层配置策略

本文适合从零开始&#xff0c;慢慢养、安全的养小龙虾的达人们。 更深入的调优配置请参考&#xff1a;Openclaw高阶调优之配置篇、OpenClaw高阶调优之模型&#xff08;tokens&#xff09;篇 核心理念 OpenClaw 配置的核心不是堆砌字段&#xff0c;而是对系统边界的精准管控。…...

GB28181协议实战:WVP开源项目+ZLM流媒体服务联调配置详解

GB28181协议实战&#xff1a;WVP开源项目ZLM流媒体服务联调配置详解 在视频监控领域&#xff0c;GB28181协议作为国家标准协议&#xff0c;已经成为设备互联互通的重要基础。而将WVP&#xff08;Web Video Platform&#xff09;开源项目与ZLM&#xff08;ZLMediaKit&#xff09…...

WPS宏工具实战:5分钟搞定批量图片尺寸调整(JSA/VBA双版本代码)

WPS宏工具实战&#xff1a;5分钟搞定批量图片尺寸调整&#xff08;JSA/VBA双版本代码&#xff09; 在文档处理中&#xff0c;批量调整图片尺寸是个高频需求。想象一下&#xff0c;你手头有份50页的产品手册&#xff0c;每页都嵌入了不同尺寸的图片&#xff0c;而客户要求所有图…...

实战指南:如何用FAISS和GPT-4o-mini构建高效RAG系统(附开源代码)

实战指南&#xff1a;如何用FAISS和GPT-4o-mini构建高效RAG系统&#xff08;附开源代码&#xff09; 在人工智能领域&#xff0c;检索增强生成&#xff08;RAG&#xff09;技术正迅速成为连接大型语言模型与专业知识的桥梁。不同于传统LLM仅依赖预训练知识&#xff0c;RAG系统通…...

Bedtools:基因组数据分析的高效工具集

Bedtools&#xff1a;基因组数据分析的高效工具集 【免费下载链接】bedtools A powerful toolset for genome arithmetic. 项目地址: https://gitcode.com/gh_mirrors/be/bedtools 项目价值与应用场景 Bedtools作为一款专注于基因组算术操作的工具集&#xff0c;在生物…...

别再一上来就搞ETL了!聊聊我们团队在数据治理项目里踩过的第一个坑:数据资产划分

数据治理第一步&#xff1a;为什么跳过资产划分会让你的ETL工程翻车&#xff1f; 凌晨三点的办公室&#xff0c;咖啡杯已经见底&#xff0c;ETL管道却因为数据源混乱再次报错——这是许多数据团队的真实噩梦。我们团队在去年启动企业级数据治理项目时&#xff0c;也曾陷入"…...