87.Go Redis实现可重入、自动续期分布式锁

在 86.分布式锁理论分析 中我们介绍了分布式锁的原理、"坑"以及解决办法。本文就给一下代码示例:

一、Redis实现分布式锁

package mainimport ("fmt""github.com/go-redis/redis""time"
)var client = redis.NewClient(&redis.Options{Addr:     "localhost:6379",Password: "", DB:       0,  
})func Lock(key string, value string, expiration time.Duration) (bool, error) {return client.SetNX(key, value, expiration).Result()
}func Unlock(key string, value string) error {val, err := client.Get(key).Result()if err != nil {return err}// 避免释放它人的锁if val == value {return client.Del(key).Err()}return fmt.Errorf("key %s is locked by another value %s", key, val)
}func main() {// my-value应该保证全局唯一,如uuid,雪花算法产生的ID等ok, err := Lock("my-key", "my-value", 10*time.Second)if err != nil {// handle error}if !ok {fmt.Println("Lock failed")} else {fmt.Println("Lock success")defer Unlock("my-key", "my-value")// do your job}
}

在上面的代码中,我们定义了两个函数:LockUnlockLock函数会尝试在Redis中设置一个键值对,并设置一个过期时间。如果这个键值对已经被其他地方设置了,那么SetNX函数会返回false,否则返回true

Unlock函数则尝试删除这个键值对,但是在删除之前,会检查这个键值对的值是否符合输入的值,如果不符合,那么认为这个锁已经被其他地方获取,这时就不应该删除这个键值对。

二、可重入与自动续期

上面例子,锁缺失两个重要的性质:一个是可重入,一个是如何实现到期自动续期逻辑。

package mainimport ("sync""time""github.com/go-redis/redis""github.com/satori/go.uuid"
)var client = redis.NewClient(&redis.Options{Addr:     "localhost:6379",Password: "", // no password setDB:       0,  // use default DB
})type Lock struct {key        stringvalue      stringexpiration time.Durationmu         sync.MutexisLocked   boolcount      int
}func NewLock(key string, expiration time.Duration) *Lock {return &Lock{key:        key,value:      uuid.NewV4().String(), // 这里使用uuid作为valueexpiration: expiration,}
}func (l *Lock) Lock() (bool, error) {l.mu.Lock()defer l.mu.Unlock()if l.isLocked {l.count++return true, nil}ok, err := client.SetNX(l.key, l.value, l.expiration).Result()if err != nil || !ok {return false, err}l.isLocked = truel.count++go l.renew()return true, nil
}func (l *Lock) Unlock() error {l.mu.Lock()defer l.mu.Unlock()if !l.isLocked {return nil}l.count--if l.count > 0 {return nil}val, err := client.Get(l.key).Result()if err != nil {return err}// 保证释放的是自己的锁if val != l.value {return nil}l.isLocked = falsereturn client.Del(l.key).Err()
}func (l *Lock) renew() {ticker := time.NewTicker(l.expiration / 2)for range ticker.C {l.mu.Lock()if !l.isLocked {ticker.Stop()l.mu.Unlock()break}client.Expire(l.key, l.expiration)l.mu.Unlock()}
}func main() {lock := NewLock("my-key", 10*time.Second)locked, err := lock.Lock()if err != nil {panic(err)}if !locked {return}defer lock.Unlock()// do something
}

这段代码中,Lock结构体中新加入了muisLockedcount字段,分别表示互斥锁、是否已经锁定还有重入次数。当再次获取锁的时候,已经锁定则重入次数增加,否则尝试获取锁。在unlock时,如果重入次数大于零,则直接减少重入次数而不释放锁。

同时加入了renew函数,这个函数会每过一段时间检查这个锁是否已经被释放,未被释放则续期,并在锁释放后停止续期。

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

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

相关文章

Android Graphics 图像显示系统 - 开篇

“ 随着学习的不断深入和工作经验的积累,欲将之前在博客中整理的Android Graphics知识做进一步整理,并纠正一些理解上的错误,故开设Graphics主题系列文章 ” 序言 由于工作需要,也源于个人兴趣,终于下决心花时间整理一…

网络请求库axios

一、认识Axios库 为什么选择axios? 功能特点: 在浏览器中发送 XMLHttpRequests 请求在 node.js 中发送 http请求支持 Promise API拦截请求和响应转换请求和响应数据 补充: axios名称的由来? 个人理解没有具体的翻译. axios: ajax i/o system 二、axios发送请求 1.axios请求…

【开源】SpringBoot框架开发大病保险管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 系统配置维护2.2 系统参保管理2.3 大病保险管理2.4 大病登记管理2.5 保险审核管理 三、系统详细设计3.1 系统整体配置功能设计3.2 大病人员模块设计3.3 大病保险模块设计3.4 大病登记模块设计3.5 保险审核模块设计 四、…

2024 年 5 款适用于免费 iPhone 数据恢复的工具软件

搜索一下,你会发现许多付费或免费的iPhone数据恢复工具声称它们可以帮助你以很高的成功率找回所有丢失的数据。然而,这正是问题所在。真的很难做出选择。为了进一步帮助您解决数据丢失问题,我们在此列出了 5 款最好的免费 iPhone 恢复软件供您…

滑块识别验证

滑块识别 1. 获取图片 测试网站:https://www.geetest.com/adaptive-captcha-demo 2. 点击滑块拼图并开始验证 # 1.打开首页 driver.get(https://www.geetest.com/adaptive-captcha-demo)# 2.点击【滑动拼图验证】 tag WebDriverWait(driver, 30, 0.5).until(la…

Python API的使用简述

文章目录 Web APIGit 和 GitHub使用 API 调用请求数据安装 requests处理响应 API处理响应字典监视API的速率限制使用 Pygal 可视化仓库改进Pygal图表添加自定义工具提示 本篇文章:我们叙述如何编写一个独立的程序,并对其获取的数据进行可视化。这个程序将…

Python进阶:标准库

目录 一、前言 二、正文 1. Python 标准库的重要性 2. 常用标准库模块 a. os 模块

Eclipse导入maven项目或者创建maven项目时,报错Could not calculate build plan: Plugin

问题&#xff1a;Eclipse导入maven项目或者创建maven项目时,报错Could not calculate build plan: Plugin 1.上述问题大概是项目不能加载此maven插件&#xff0c;在pom文件中添加依赖项 <dependency><groupId>org.apache.maven.plugins</groupId><artifa…

编程相关的经典的网站和书籍

经典网站&#xff1a; Stack Overflow&#xff1a;作为全球最大的程序员问答社区&#xff0c;Stack Overflow 汇聚了大量的编程问题和解答&#xff0c;为程序员提供了极大的帮助。GitHub&#xff1a;全球最大的开源代码托管平台&#xff0c;程序员可以在上面共享自己的项目代码…

二级建造师试题答案?学生党都在用的6款搜题工具来了 #学习方法#学习方法#微信

作为大学生&#xff0c;我们应该善于利用各种学习工具&#xff0c;提高学习效率和质量。 1.灵兔搜题 这是一个公众号 包含大学网课、课后教材、选修课、mooc慕课及各类职业资格证、学历提升考试、公务员考试等常见题库。 下方附上一些测试的试题及答案 1、Uri主要由三部分组…

Python实战:用Python程序实现春晚刘谦魔术

刘谦春晚魔术是一个让人叹为观止的魔术表演&#xff0c;其中涉及到了数学、编程和创意的结合。看了春晚魔术的朋友们&#xff0c;是不是好奇春晚刘谦的魔术是怎么变的。 在这篇文章中&#xff0c;我们将通过 Python 程序实现春晚刘谦魔术&#xff0c;让读者对这个魔术有更深入…

【GAMES101】Lecture 20 光场

目录 光场&#xff08;Light Field / Lumigraph&#xff09; 广场照相机 光场&#xff08;Light Field / Lumigraph&#xff09; 我们在三维的世界中从一个观测点出发看到这么一幅二维的画面 如果有这么一副画布可以完美的显示出从观察点看到的画面&#xff0c;那用这幅画布…

idea设置terminal为git

要在IntelliJ IDEA中设置终端为Git Bash&#xff0c;请按照以下步骤操作&#xff1a; 打开 Settings&#xff08;设置&#xff09;。点击 Tools&#xff08;工具&#xff09;选项卡。进入 Terminal&#xff08;终端&#xff09;界面。在 Shell Path 下选择 Browse&#xff08;…

Redis发布订阅及事务管理

目录 一、发布订阅 1.1、常用命令 1.2、示例演示 二、事务管理 2.1 Multi、Exec、Discard 2.2 示例演示 2.3 事务的错误处理 2.4 事务的冲突问题 2.4.1 事务场景 2.4.2 悲观锁 2.4.3 乐观锁 2.4.4 事务解决冲突—WATCH 2.4.5 UNWATCH 2.4.6 Redis事务的三个特性 …

测试管理总结

前言 最近经常被问到如何对测试团队进行管理的问题。 我自己总结了一下自己的一些看法&#xff0c;希望书面记录下来&#xff0c;加深印象&#xff0c;也借机像各位同行大牛请教一下 **我从5个方面进行总结&#xff1a; 第一、团队组建** 分别从2个团队的情况来说&#xff…

突破编程_C++_面试(基础知识(9))

面试题24&#xff1a;什么是面向对象编程 面向对象编程&#xff08;Object-Oriented Programming&#xff0c;简称OOP&#xff09;是一种编程范式或编程模型&#xff0c;它基于对象的概念来设计和实现程序。在面向对象编程中&#xff0c;程序是由一系列对象组成的&#xff0c;…

ES实战-book笔记1

#索引一个文档,-XPUT手动创建索引, curl -XPUT localhost:9200/get-together/_doc/1?pretty -H Content-Type: application/json -d {"name": "Elasticsearch Denver","organizer": "Lee" } #返回结果 {"_index" : "g…

尚硅谷 Vue3+TypeScript 学习笔记(中)

目录 三、路由 3.1. 【对路由的理解】 3.2. 【基本切换效果】 3.3. 【两个注意点】 3.4.【路由器工作模式】 3.5. 【to的两种写法】 3.6. 【命名路由】 3.7. 【嵌套路由】 3.8. 【路由传参】 query参数 params参数 3.9. 【路由的props配置】 3.10. 【 replace属性…

机器学习:SVM、softmax、Dropout及最大池化max_pool介绍

一、利用线性SVM进行分类 train_data: (train_num, 3072) 训练流程 初始化权重W: (3072, 10) 梯度dW: (3072, 10)train_data和权重相乘得到score(10,)对应每个类别的分数 2.1 对于每个score中的分数i&#xff0c;如果是正确的类别对应的score跳过 2.2 如果是其他的类别&…

【GAMES101】Lecture 20 颜色

目录 光 颜色 加色系统 CIE RGB颜色匹配实验 颜色空间 CIE XYZ颜色空间 HSV颜色空间(Hue-Saturation-Value) CIELAB空间 减色系统&#xff1a;CMYK 光 光是由不同波长的光波组成的&#xff0c;其中可见光的波长范围在400nm到700nm 用谱功率密度&#xff08;Spectral…