Go 语言下基于Redis分布式锁的实现方式


Posted in Golang onJune 28, 2021

分布式锁一般有三种实现方式:1. 数据库乐观锁;2. 基于Redis的分布式锁;3. 基于ZooKeeper的分布式锁。本篇博客将介绍第二种方式,基于Redis实现分布式锁。虽然网上已经有各种介绍Redis分布式锁实现的博客,然而他们的实现却有着各种各样的问题,为了避免误人子弟,本篇博客将详细介绍如何正确地实现Redis分布式锁。

项目地址: https://github.com/Spongecaptain/redisLock

1. Go 原生的互斥锁

Go 原生的互斥锁即 sync 包下的 Mutex 结构体,利用此结构体的 Lock 以及 Unlock 方法能够实现锁的占据以及释放。

关于 sync.Mutex,我们可以总结出如下的特性:

  • 支持自旋锁,在并发冲突不严重的背景下提高锁的使用效率;
  • 支持锁的公平性,能够避免锁导致的线程饥饿问题;
  • 不支持锁的重入,持有锁的协程再次申请锁资源会导致死锁;
  • 任何协程都可以调用 Mutex.Unlock 方法来解锁,并不只允许占据锁资源的协程进行解锁;
  • 不支持超时锁获取,也不支持 TryLock 机制

Go 语言中 sync.Mutex 的特性与 Java 中 java.util.concurrent.locks.Lock 相比,API 语义简单不少,这也符合 Go 语言对于简单化的追求。

下面看看本项目-基于 Redis 的分布式锁能够提供哪些分布锁特性。

2. redisLock 的特性

github-redisLock 是一个基于 go-redis/redis 客户端的 Redis 分布式锁。其拥有的如下的特性:

  • 原子性:利用 Lua 脚本实现原子性语义;
  • 阻塞唤醒:利用 Redis 的发布订阅来实现锁的阻塞唤醒;
  • 锁自动过期:避免因为宕机导致的死锁问题;
  • 锁的自动续期:利用 Go 协程实现锁资源的自动续期,避免出现业务时间>锁超时时间导致并发安全问题
  • TryLock:尝试获取一次锁,获取失败后阻塞
  • 自旋锁:提供自旋锁 API 来实现分布式锁的自旋获取

github-redisLock 同时不支持如下特性:

重入性:分布式锁不可重入,Go 语言并没有优雅的方式来实现 Java 中的 ThreadLocal 机制
非公平性:分布式锁存在非公平问题,在极端情况下会导致饥饿问题

3. Quick Start

Install redisLock:

go get github.com/Spongecaptain/redisLock


 

Create redis client:

import(
 "github.com/go-redis/redis"
)
var redisClient = redis.NewClient(&redis.Options{
 Addr:     "localhost:6379",
 Password: "", // no password set
 DB:       0,  // use default DB
})

Create redisLock:

key := "reids-lock-key"
value := "redis-lock-value"
lock := redisLock.NewRedisLock(redisClient, key, value)

err := lock.Lock()
if err != nil {
  fmt.Println(err.Error())
  return
}
fmt.Println("get redis lock success")
defer func() {
  err = lock.Unlock()
  if err != nil {
    fmt.Println(err.Error())
    return
  }
  fmt.Println("release redis lock success")
}()

4. API 说明

(1)构造分布式锁实例
利用 NewRedisLock 以及 NewRedisLockWithExpireTime 函数能够构造出一个分布式锁实例,NewRedisLockWithExpireTime 的区别在于其能够自定义锁的过期时间。

NewRedisLock 方法接收的 key 决定了分布式锁的粒度,value 决定了只有 value 值相同才能够进行解锁。

(2)TryLock
TryLock 仅尝试一次锁的获取,如果失败,那么不会阻塞,直接返回。

(3)Lock
Lock 会不断尝试索取分布式锁,这会导致调用此方法的协程阻塞。

(4)Unlock
Unlock 方法用于解锁,由于涉及网络通信,解锁可能失败, error!=nil 意味着解锁失败。

(5)LockWithTimeout
Lock 方法会在获取锁资源成功或者超时后返回。

(6)SpinLock
支持指定次数地进行自旋式的锁获取。

以上就是Go 语言下基于 Redis 的分布式锁的详细内容,更多关于Go 分布式锁的资料请关注三水点靠木其它相关文章!

Golang 相关文章推荐
Go各时间字符串使用解析
Apr 02 Golang
golang判断key是否在map中的代码
Apr 24 Golang
基于go interface{}==nil 的几种坑及原理分析
Apr 24 Golang
golang中的空slice案例
Apr 27 Golang
彻底理解golang中什么是nil
Apr 29 Golang
golang协程池模拟实现群发邮件功能
May 02 Golang
golang elasticsearch Client的使用详解
May 05 Golang
Golang: 内建容器的用法
May 05 Golang
基于Golang 高并发问题的解决方案
May 08 Golang
Go语言设计模式之结构型模式
Jun 22 Golang
Go语言基础知识点介绍
Jul 04 Golang
Golang 链表的学习和使用
Apr 19 Golang
go语言使用Casbin实现角色的权限控制
Go语言设计模式之结构型模式
浅谈Go语言多态的实现与interface使用
Jun 16 #Golang
再次探讨go实现无限 buffer 的 channel方法
Jun 13 #Golang
Go遍历struct,map,slice的实现
Jun 13 #Golang
go web 预防跨站脚本的实现方式
Jun 11 #Golang
Golang生成Excel文档的方法步骤
You might like
input 和 textarea 输入框最大文字限制的jquery插件
2011/10/27 Javascript
js设置cookie过期及清除浏览器对应名称的cookie
2013/10/24 Javascript
jquery取消选择select下拉框示例代码
2014/02/22 Javascript
Javascript实现简单二级下拉菜单实例
2014/06/15 Javascript
jQuery实现防止提交按钮被双击的方法
2015/03/24 Javascript
使用Javascript写的2048小游戏
2015/11/25 Javascript
JS中判断字符串中出现次数最多的字符及出现的次数的简单实例
2016/06/03 Javascript
Bootstrap中的表单验证插件bootstrapValidator使用方法整理(推荐)
2016/06/21 Javascript
AngularJs自定义服务之实现签名和加密
2016/08/02 Javascript
基于jQuery ligerUI实现分页样式
2016/09/18 Javascript
JavaScript中立即执行函数实例详解
2017/11/04 Javascript
理顺8个版本vue的区别(小结)
2018/09/17 Javascript
angular4笔记系列之内置指令小结
2018/11/09 Javascript
微信小程序事件对象中e.target和e.currentTarget的区别详解
2019/05/08 Javascript
浅谈redux, koa, express 中间件实现对比解析
2019/05/23 Javascript
js图片查看器插件用法示例
2019/06/22 Javascript
Vuejs中的watch实例详解(监听者)
2020/01/05 Javascript
前端开发基础javaScript的六大作用
2020/08/06 Javascript
vue element实现表格合并行数据
2020/11/30 Vue.js
Python实现将文本生成二维码的方法示例
2017/07/18 Python
Python有序查找算法之二分法实例分析
2017/12/11 Python
Python爬虫学习之翻译小程序
2019/07/30 Python
Python学习笔记之列表推导式实例分析
2019/08/13 Python
基于python实现把图片转换成素描
2019/11/13 Python
CSS3条纹背景制作的实战攻略
2016/05/31 HTML / CSS
使用css3做0.5px的细线的示例代码
2018/01/18 HTML / CSS
html5摇一摇代码优化包括DeviceMotionEvent等等
2014/09/01 HTML / CSS
Russell Stover巧克力官方网站:美国领先的精美巧克力制造商
2016/11/27 全球购物
Opodo英国旅游网站:预订廉价航班、酒店和汽车租赁
2018/07/14 全球购物
随机分配座位,共50个学生,使学号相邻的同学座位不能相邻
2014/01/18 面试题
js正则匹配markdown里的图片标签的实现
2021/03/24 Javascript
《池塘边的叫声》教学反思
2014/04/12 职场文书
县委务虚会发言材料
2014/10/20 职场文书
红色电影观后感
2015/06/18 职场文书
医德医风学习心得体会
2016/01/25 职场文书
2016年社区植树节活动总结
2016/03/16 职场文书