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 相关文章推荐
golang interface判断为空nil的实现代码
Apr 24 Golang
goland 恢复已更改文件的操作
Apr 28 Golang
golang 实现两个结构体复制字段
Apr 28 Golang
Golang 如何实现函数的任意类型传参
Apr 29 Golang
浅谈golang 中time.After释放的问题
May 05 Golang
golang 实现时间戳和时间的转化
May 07 Golang
go xorm框架的使用
May 22 Golang
Golang标准库syscall详解(什么是系统调用)
May 25 Golang
Go语言实现Snowflake雪花算法
Jun 08 Golang
再次探讨go实现无限 buffer 的 channel方法
Jun 13 Golang
golang中的struct操作
Nov 11 Golang
深入理解 Golang 的字符串
May 04 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
php异常处理技术,顶级异常处理器
2012/06/13 PHP
php 使用html5实现多文件上传实例
2016/10/24 PHP
PHP实现从上往下打印二叉树的方法
2018/01/18 PHP
javascript 读取图片文件的大小
2009/06/25 Javascript
JS模块与命名空间的介绍
2013/03/22 Javascript
JavaScript加强之自定义event事件
2013/09/21 Javascript
JavaScript实现的类字典插入或更新方法实例
2015/07/10 Javascript
JS简单限制textarea内输入字符数量的方法
2015/10/14 Javascript
jquery+json实现分页效果
2016/03/07 Javascript
学习vue.js条件渲染
2016/12/03 Javascript
原生javascript实现的全屏滚动功能示例
2017/09/19 Javascript
vue项目引入字体.ttf的方法
2018/09/28 Javascript
js贪心算法 钱币找零问题代码实例
2019/09/11 Javascript
js+css3实现简单时钟特效
2020/09/13 Javascript
[47:43]完美世界DOTA2联赛PWL S3 Magama vs GXR 第二场 12.19
2020/12/24 DOTA
详解Django中Request对象的相关用法
2015/07/17 Python
Ubuntu 下 vim 搭建python 环境 配置
2017/06/12 Python
Python编程实现使用线性回归预测数据
2017/12/07 Python
Python决策树分类算法学习
2017/12/22 Python
python 实现对数据集的归一化的方法(0-1之间)
2018/07/17 Python
pandas 空的dataframe 插入列名的示例
2018/10/30 Python
python把1变成01的步骤总结
2019/02/27 Python
自适应线性神经网络Adaline的python实现详解
2019/09/30 Python
python中有函数重载吗
2020/05/28 Python
Kmeans均值聚类算法原理以及Python如何实现
2020/09/26 Python
Django URL参数Template反向解析
2020/11/24 Python
Django集成MongoDB实现过程解析
2020/12/01 Python
Herschel美国官网:背包、手提袋及配件
2020/03/10 全球购物
EJB2和EJB3在架构上的不同点
2014/09/29 面试题
韩语专业本科生求职信
2013/10/01 职场文书
经济信息系毕业生自荐信
2014/06/02 职场文书
2014领导干部四风问题查摆思想汇报
2014/09/13 职场文书
个人对照检查材料思想汇报
2014/09/26 职场文书
三十年同学聚会致辞
2015/07/28 职场文书
人生哲理妙语30条:淡写流年,笑过人生
2019/09/04 职场文书
python 办公自动化——基于pyqt5和openpyxl统计符合要求的名单
2021/05/25 Python