Golang使用etcd构建分布式锁案例

在本教程中,我们将学习如何使用Go和etcd构建分布式锁系统。分布式锁系统对于管理对分布式系统中共享资源的并发访问至关重要。它有助于维护一致性,防止竞争条件,并确保在任何给定时间只有一个进程独占访问资源。

我们将使用Go作为编程语言,并使用etcd作为分布式键值存储。Go的并发特性和对分布式系统的出色支持使其成为本教程的理想选择。Etcd是一种高度可靠的分布式键值存储,被许多大型系统(如Kubernetes)用于配置管理和服务发现。

在本教程结束时,你将能够构建一个分布式锁系统,Go开发人员可以使用该系统来管理对其应用程序中共享资源的访问。

环境准备

要学习本教程,你应该具备:

  • 具备Go编程语言基础知识
  • 在你的系统上安装Etcd或访问Etcd服务器
  • Go安装在你的系统上(版本1.13或更高版本)

新建Go项目

首先,让我们用必要的依赖项创建一个新的Go项目:

$ mkdir distributed-lock && cd distributed-lock
$ go mod init example.com/distributed-lock
$ go get go.etcd.io/etcd/clientv3

这将设置一个新的Go项目并下载etcd客户端库。
在这里插入图片描述

实现加锁和解锁功能

现在是时候实现Lock和Unlock函数了。我们将创建名为lock的新文件。首先导入必要的包并定义结构来保存锁信息:

package mainimport ("context""log""time""go.etcd.io/etcd/clientv3"
)type DistributedLock struct {Key        stringValue      stringLeaseID    clientv3.LeaseIDetcdClient *clientv3.Client
}

接下来,我们将实现Lock函数。该函数将执行以下步骤:

  1. 创建具有指定TTL(生存时间)的新租约
  2. 将锁键值对存入附带租约的etcd中
  3. 如果锁已被占用,则处理错误并重试
func (dl *DistributedLock) Lock(ctx context.Context, ttl int64) error {lease, err := dl.etcdClient.Grant(ctx, ttl)if err != nil {return err}_, err = dl.etcdClient.Put(ctx, dl.Key, dl.Value, clientv3.WithLease(lease.ID))if err != nil {return err}dl.LeaseID = lease.IDlog.Printf("Lock acquired: %s", dl.Key)return nil
}
  • ctx context.Context:这是 Go 语言中用于传递上下文信息的参数,常用于控制操作的超时、取消等情况,比如在分布式环境中协调多个操作的生命周期,确保它们能按照预期执行或者在合适的时候被取消。

  • ttl int64:代表 “Time To Live”(存活时间),通常是以秒为单位的时间长度,用于指定分布式锁的有效时长,过了这个时长,锁可能会自动释放,以防止锁被长期占用导致死锁等问题。

  • 这里使用dl.etcdClient再次调用Put方法,它的作用是向etcd中写入键值对(Key-Value)。具体来说,写入的键是dl.Key(从代码推测应该是用于标识这个分布式锁的唯一键,是DistributedLock结构体中的一个字段),值是dl.Value(同样是结构体中的字段,可能是和锁相关的一些其他附属信息等)。

  • 关键的一点是通过clientv3.WithLease(lease.ID)这个选项将前面申请到的租约的ID关联到这个要写入的键值对上,意思是这个键值对的存在时长会受租约的控制,当租约到期(达到ttl设定的时间)时,etcd会自动删除这个键值对,从而实现了分布式锁的自动释放机制。和前面获取租约类似,Put操作也可能出错,所以同样进行错误判断,如果err不为空,就返回错误给调用者。

现在,让我们实现Unlock函数。该函数将执行以下步骤:

  1. 删除etcd中的锁键值对
  2. 解除租赁
func (dl *DistributedLock) Unlock(ctx context.Context) error {_, err := dl.etcdClient.Delete(ctx, dl.Key)if err != nil {return err}_, err = dl.etcdClient.Revoke(ctx, dl.LeaseID)if err != nil {return err}log.Printf("Lock released: %s", dl.Key)return nil
}

测试分布式锁

最后,让我们创建一个简单的测试应用程序来查看分布式锁的实际情况。基本上。Go文件,添加以下代码:

package mainimport ("context""fmt""os""time""go.etcd.io/etcd/clientv3"
)func main() {endpoints := []string{"localhost:2379"}cfg := clientv3.Config{Endpoints:   endpoints,DialTimeout: 5 * time.Second,}client, err := clientv3.New(cfg)if err != nil {fmt.Printf("Error connecting to etcd: %v", err)os.Exit(1)}defer client.Close()ctx := context.Background()lockKey := "my-lock"lockValue := "my-value"dl := DistributedLock{Key:        lockKey,Value:      lockValue,etcdClient: client,}err = dl.Lock(ctx, 10)if err != nil {fmt.Printf("Error acquiring lock: %v", err)os.Exit(1)}// Simulate a critical sectiontime.Sleep(5 * time.Second)err = dl.Unlock(ctx)if err != nil {fmt.Printf("Error releasing lock: %v", err)os.Exit(1)}
}

使用以下命令运行测试应用程序:

$ go run main.go

如果一切正常,您应该看到锁在5秒睡眠后被获取和释放。

重构实现失败重试

以下是在原代码基础上添加申请锁失败重试机制的示例代码,在 Go 语言中可以使用循环结合退避策略等方式来实现,以下是一种常见的实现思路及代码示例,假设使用了time包来进行时间控制以及添加了适当的错误处理和重试次数限制等逻辑:

package mainimport ("context""fmt""go.etcd.io/etcd/clientv3""log""time"
)type DistributedLock struct {etcdClient *clientv3.ClientKey        stringValue      stringLeaseID    clientv3.LeaseID
}func (dl *DistributedLock) Lock(ctx context.Context, ttl int64) error {maxRetries := 3       // 最大重试次数,可根据实际情况调整retryDelay := 1 * time.Second // 初始重试间隔时间,可根据实际情况调整for retry := 0; retry < maxRetries; retry++ {lease, err := dl.etcdClient.Grant(ctx, ttl)if err!= nil {if retry == maxRetries-1 {return fmt.Errorf("failed to grant lease after %d retries: %v", maxRetries, err)}// 等待一段时间后重试,这里可以采用退避策略,比如指数退避等,此处简单使用固定间隔time.Sleep(retryDelay)continue}_, err = dl.etcdClient.Put(ctx, dl.Key, dl.Value, clientv3.WithLease(lease.ID))if err!= nil {if retry == maxRetries-1 {return fmt.Errorf("failed to put key-value with lease after %d retries: %v", maxRetries, err)}// 释放本次申请到的租约,避免资源浪费,虽然租约到期也会自动释放,但及时释放更好_, _ = dl.etcdClient.Revoke(ctx, lease.ID)time.Sleep(retryDelay)continue}dl.LeaseID = lease.IDlog.Printf("Lock acquired: %s", dl.Key)return nil}return fmt.Errorf("exceeded max retries for lock acquisition")
}

出来重试部分,其他逻辑不变,这里解释第二部分重试逻辑:

  • 当租约申请成功后,尝试将键值对写入etcd并关联租约,若这个操作出现错误(err不为nil),同样有如下处理:
  • 先判断是否达到最大重试次数,如果是,返回带有详细失败信息的error告知调用者设置键值关联租约操作经过多次重试后失败以及具体错误原因。
  • 如果没达到最大重试次数,为了避免已经申请到的租约一直占用资源(虽然租约到期会自动释放,但及时主动释放更合理),调用dl.etcdClient.Revoke方法来撤销(释放)刚刚申请到的租约,然后让当前协程暂停执行retryDelay设定的时间间隔后,通过continue进入下一次循环,再次尝试整个申请锁的流程。

总结

在本教程中,我们使用Go等语言构建了简单分布式锁系统。该系统可用于远程Go开发人员管理对其应用程序中共享资源的访问,确保分布式系统中的一致性和防止竞争条件。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/487604.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数字IC后端实现常见的physical only cell都有哪些?如何添加这些cell?

数字IC后端实现阶段常见功能cell有哪些&#xff1f;比如AND&#xff0c;AOI&#xff0c;NAND等。 physical cell有哪些&#xff1f;都是干什么用的&#xff1f; 数字后端零基础入门系列 | Innovus零基础LAB学习Day9 &#xff08;1&#xff09; well tap cells&#xff1a;防止…

【NVIDIA orin nx 安装ultralytics yolov11】

注意:不同用户安装的python可能会在不同的路径,因此不同的pip管理会导致安装的 torch和torchvision会在不同的路径下 记得区分用户来运行yolo 一、确认系统 JetPack 版本 此处使用5.1.1 1、查看JetPack 版本 jtop二、安装 ultralytics、pytorch、torchvision、onnxruntime…

CANDENCE:过孔设置 及 如何放置过孔

过孔设置 1、 2、 3、弹出如下对话框 4、选择需要的过孔尺寸&#xff0c;双击 5、调节过孔优先级 6、点击 ”OK“ 完成设置 放置过孔 及 过孔选择 在PCB设计窗口 切换到走线模式 走线时&#xff0c;侧边栏可以选择过孔尺寸 选择好后&#xff0c; 双击左键放置过孔 也…

React 和 Vue _使用区别

目录 一、框架介绍 1.Vue 2.React ?二、框架结构 1.创建应用 2.框架结构 三、使用区别 1.单页面组成 2.样式 3.显示响应式数据 4.响应式html标签属性 5.控制元素显隐 6.条件渲染 7.渲染列表 react和vue是目前前端比较流行的两大框架&#xff0c;前端程序员应该将…

基于多视角深度学习技术的乳腺X线分类:图神经网络与Transformer架构的研究|文献速递-生成式模型与transformer在医学影像中的应用速递

Title 题目 Mammography classification with multi-view deep learning techniques:Investigating graph and transformer-based architectures 基于多视角深度学习技术的乳腺X线分类&#xff1a;图神经网络与Transformer架构的研究 01 文献速递介绍 乳腺X线检查是乳腺癌…

SQL项目实战与综合应用——项目设计与需求分析

项目设计与需求分析是软件开发过程中的核心环节&#xff0c;尤其在涉及数据库的应用时&#xff0c;良好的设计将直接影响到项目的可扩展性、性能和维护性。本文将深入探讨数据库设计的最佳实践&#xff0c;结合 C 与 SQL 的实际应用场景&#xff0c;涵盖项目需求收集、数据库设…

【HarmonyOS学习日志(13)】计算机网络之TCP/IP协议族(二)

文章目录 TCP/IP协议族ARPDNS标志字段&#xff1a;协商具体的通信方式和反馈通信状态DNS查询问题的格式资源记录&#xff08;Resource Record, RR&#xff09;格式&#xff1a;被用于应答字段、授权字段和额外信息字段 IP协议IP服务的特点无状态无连接不可靠 IP头部结构IPv4头部…

GO并发编程

一、并发编程初体验和问题 关于 Go 语言和线程的关系 Go 语言中存在线程。Go 语言的并发模型是基于 Goroutine、Processor&#xff08;P&#xff09;和 Machine&#xff08;M&#xff0c;操作系统线程&#xff09;的 GMP 模型。Goroutine 是 Go 语言中轻量级的执行单元&#xf…

初次使用uniapp编译到微信小程序编辑器页面空白,真机预览有内容

uniapp微信小程序页面结构 首页页面代码 微信小程序模拟器 模拟器页面为空白时查了下&#xff0c;有几个说是“Hbuilder编译的时候应该编译出来一个app.js文件 但是却编译出了App.js”&#xff0c;但是我的小程序结构没问题&#xff0c;并且真机预览没有问题 真机调试 根据defi…

车载语音的台架和实车测试分析

在车载测试过程中免不了要对一些特殊的业务进行深度的专项测试。比如语音识别&#xff0c;这个技术在汽车上也不算什么新技术&#xff0c;但是涉及到用户的使用&#xff0c;更加涉及操作的安全性&#xff0c;所以这块测试还是很重要的。 那么要做好语音识别的业务专项测试&…

【蓝桥杯每日一题】砍竹子

砍竹子 2024-12-7 蓝桥杯每日一题 砍竹子 STL 贪心 题目大意 这天, 小明在砍竹子, 他面前有 nn 棵竹子排成一排, 一开始第 ii 棵竹子的 高度为 h i h_i hi​. 他觉得一棵一棵砍太慢了, 决定使用魔法来砍竹子。魔法可以对连续的一 段相同高度的竹子使用, 假设这一段竹子的高度为…

Vue实现购物车(纯操作数据,不操作dom)注意:自己引入Vue.js哦

代码&#xff1a; <!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>Document</title>&l…

ThinkPHP开发的原生微信小程序二手物品回收小程序管理系统源码

二手物品回收小程序 一款基于ThinkPHP开发的原生微信小程序二手物品回收小程序管理系统。支持线上下单、免费上门取件、评估价格等功能。提供全部无加密源码&#xff0c;支持私有化部署。

C#实现一个HttpClient集成通义千问-多轮对话功能实现

多轮对话功能实现 视频教程实现原理消息的类型 功能开发消息类修改请求体修改发送请求函数修改用户消息输入 多轮对话的token消息完整文档消息类型 视频教程 .NetAI开发入门HttpClient实现通义千问集成-多轮对话功能实现 实现原理 一直保留更新messages 现在设置的meessages只…

vite5+vue3+Ts5 开源图片预览器上线

images-viewer-vue3&#xff1a;一款Vue3的轻量级图像查看器&#xff0c;它基于Flip动画技术&#xff0c;支持PC和h5移动网页预览照片&#xff0c;如果它是Vue3开发的产品。 npm开源地址:https://www.npmjs.com/package/images-viewer-vue3?activeTabreadme Flip 动画 < …

Axure RP在智慧农场可视化大屏系统设计中的应用

随着科技的飞速发展&#xff0c;智慧农业已成为现代农业的重要发展方向。智慧农场可视化大屏系统作为智慧农业的重要组成部分&#xff0c;正逐步成为农场管理、决策和展示的核心工具。Axure RP&#xff0c;作为一款强大的原型设计工具&#xff0c;其在智慧农场可视化大屏系统的…

Docker多架构镜像构建踩坑记

背景 公司为了做信创项目的亮点&#xff0c;需要将现有的一套在X86上运行的应用系统迁移到ARM服务器上运行&#xff0c;整个项目通过后端Java&#xff0c;前端VUEJS开发通过CICD做成Docker镜像在K8S里面运行。但是当前的CICD产品不支持ARM的镜像构建&#xff0c;于是只能手工构…

文档解析:如何从PDF中解析出表格结构和数据?

从PDF中解析出表格结构和数据&#xff0c;可以采用以下几种方法&#xff1a;从PDF中解析出表格结构和数据&#xff0c;主要用到以下算法和技术&#xff1a; OCR技术&#xff1a;光学字符识别技术&#xff0c;用于从扫描的PDF文件中提取文本信息&#xff0c;包括表格数据。这项…

克服大规模语言模型限制,构建新的应用方法——LangChain

大模型 大模型的出现和落地开启了人工智能(AI)新一轮的信息技术革命&#xff0c;改变了人们的生 活方式、工作方式和思维方式。大模型的落地需要数据、算力和算法三大要素。经过几 年发展&#xff0c;大模型的数据集(包括多模态数据集)制作已经形成了规约&#xff0c;Meta、Go…

两种距离度量简记

一、Lp距离/Minkowski 距离&#xff08;Minkowski distance&#xff09; 1、Lp距离&#xff1a; 特征空间中两个实例点的距离是两个实例点相似程度的反映。Lp距离是一种一般化的距离度量 设特征空间x是n维实数向量空间Rn xi&#xff0c;xj的Lp距离定义为&#xff08;p>1&…