当前位置: 首页 > 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;牢固耐…...

【网络】每天掌握一个Linux命令 - iftop

在Linux系统中&#xff0c;iftop是网络管理的得力助手&#xff0c;能实时监控网络流量、连接情况等&#xff0c;帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...

docker详细操作--未完待续

docker介绍 docker官网: Docker&#xff1a;加速容器应用程序开发 harbor官网&#xff1a;Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台&#xff0c;用于将应用程序及其依赖项&#xff08;如库、运行时环…...

Oracle查询表空间大小

1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...

【解密LSTM、GRU如何解决传统RNN梯度消失问题】

解密LSTM与GRU&#xff1a;如何让RNN变得更聪明&#xff1f; 在深度学习的世界里&#xff0c;循环神经网络&#xff08;RNN&#xff09;以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而&#xff0c;传统RNN存在的一个严重问题——梯度消失&#…...

Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务

通过akshare库&#xff0c;获取股票数据&#xff0c;并生成TabPFN这个模型 可以识别、处理的格式&#xff0c;写一个完整的预处理示例&#xff0c;并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务&#xff0c;进行预测并输…...

如何将联系人从 iPhone 转移到 Android

从 iPhone 换到 Android 手机时&#xff0c;你可能需要保留重要的数据&#xff0c;例如通讯录。好在&#xff0c;将通讯录从 iPhone 转移到 Android 手机非常简单&#xff0c;你可以从本文中学习 6 种可靠的方法&#xff0c;确保随时保持连接&#xff0c;不错过任何信息。 第 1…...

微服务商城-商品微服务

数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...

Java多线程实现之Thread类深度解析

Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...

Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)

在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马&#xff08;服务器方面的&#xff09;的原理&#xff0c;连接&#xff0c;以及各种木马及连接工具的分享 文件木马&#xff1a;https://w…...

重启Eureka集群中的节点,对已经注册的服务有什么影响

先看答案&#xff0c;如果正确地操作&#xff0c;重启Eureka集群中的节点&#xff0c;对已经注册的服务影响非常小&#xff0c;甚至可以做到无感知。 但如果操作不当&#xff0c;可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...