全新的分布式锁,功能简单且强大

作者:donnie4w

链接:https://my.oschina.net/donnie4w/blog/10114233


前言:分布式锁是分布式系统中一个极为重要的工具。目前有多种分布式锁的设计方案,比如借助 redis,mq,数据库,zookeeper 等第三方服务系统来设计分布式锁。tldb 提供的分布式锁,主要是要简化这个设计的过程,提供一个简洁可靠,类似使用程序中对象锁的方式来获取分布式锁。

tldb 提供分布式锁使用方法:

  1. lock 阻塞式请求锁
  2. trylock 尝试加锁,若锁已被占用,则失败返回,反之,则获取该锁
  3. unlock 释放已经获取的锁tldb 提供的分布式锁功能主要在 MQ 模块中实现,调用的方法在 MQ 客户端实现,客户端的实现实际非常简单,除了目前已经实现的几种语言 java,golang,python,javaScript 写的 simpleClient,其实其他开发者有兴趣也可以实现其他语言的 MQ 客户端,完全没有技术门槛。分布式锁由 tldb 服务器控制,所以它相对客户端来说,也是跨语言的,如,用 java 客户端上锁的对象,其他语言同样无法获取该对象锁。

Lock (string,int) 方法的使用

tldb 提供的是以字符串为锁对象的独占锁, 如,lock ("abc",3) 必须提供两个参数:

  1. 第一个参数为锁对象,即服务器对 “abc” 对象分配一个锁,所有对 "abc" 对象请求加锁的线程争用一个独占锁,该方法为一个阻塞方法,请求到锁则返回,如果锁被其他线程占用,则一直阻塞直至获取到锁。
  2. 第二个参数为持有该分布式锁的最长时间,单位为秒,例如 lock ("abc",3),意思是,如果超过 3 秒还没有调用 unlock 释放该锁,服务器将强制释放该锁,继续将锁分配给其他请求的线程。

UnLock (string) 方法的使用

  • UnLock 为释放分布式锁时调用的方法。客户端在成功获取分布式锁后,服务器会返回一个该锁的 key,客户端执行完逻辑代码的最后,必须显式调用 UnLock (key) 来释放该分布式锁。如果没有调用 unlock 释放锁,tldb 将等待锁释放的超时时间直至超时后强制释放该锁。

TryLock (string,int) 方法的使用

  • trylock 与 lock 相似,但是 lock 方法阻塞的,调用 lock 方法请求分布式锁时,如果该锁已经被占用,那么 lock 方法将一直等待直至 tldb 服务器将锁分配给它,这与程序中获取独占锁的方式一致。而 trylock 时非阻塞的,调用 trylock 后会立即返回,如果获取到锁,tldb 会将标识该锁的 key 一并返回,如何该锁已经被占用,服务器将返回空数据。

以下以 go 为例使用分布式锁

因为 tldb 分布式的实现是在 MQ 模块,所以 go 程序必须使用 tlmq-go, tldb 的 mq 客户端进行调用锁方法。

   import  "github.com/donnie4w/tlmq-go/cli"

调用 lock 的程序:lock 方法是阻塞的

sc := cli.NewMqClient("ws://127.0.0.1:5001", "mymq=123")
sc.Connect()
//以上为 客户端连接MQ服务器
key, err := sc.Lock("testlock", 3)
//lock中两个参数,第一个参数为字符串,即tldb服务器为“testlock”分配一个全局的分布式锁
//第二个参数3为客户端持有该锁的最长时间,表示超过3秒没有释放锁时,tldb服务器将在服务端强制释放该锁,并分配给其他请求锁的线程
if err!=nil{
//获取锁失败,需查看tldb能正常访问
}else{
defer sc.UnLock(key) //获取锁成功后,必须在程序最后调用Unlock
//执行业务逻辑程序
}
调用 tryLock 的程序,trylock 是非阻塞的
sc := cli.NewMqClient("ws://127.0.0.1:5001", "mymq=123")
sc.Connect()

if key, ok := sc.TryLock("testlock2", 3); ok {
//ok为true,表示已经成功获取到分布式锁
defer sc.UnLock(key) //在程序最后释放锁对象
...
}

go 用自旋的方式使用 trylock 获取分布式锁,实现程序的阻塞等待

sc := cli.NewMqClient("ws://127.0.0.1:5001", "mymq=123")
sc.Connect()
var key string
for {
if v, ok := sc.TryLock("testlock", 3); ok {
key = v
break
} else {
<-time.After(100* time.Millisecond)
}
}
defer sc.UnLock(key)
...//业务逻辑代码
这段程序应该比较易于理解,就是每隔 100 毫秒,循环获取字符串 “testlock” 的分布式锁直至成功。以下以 java 为例 java 客户端为 tlmq-j :https://github.com/donnie4w/tlmq-jmaven 配置
<dependency>        
<groupId>io.github.donnie4w</groupId>
<artifactId>tlmq-j</artifactId>
<version>0.0.2</version>
</dependency>

调用 lock 方法

MqClient mc = new SimpleClient("ws://127.0.0.1:5001", "mymq=123");
mc.connect();
//java连接服务器
String key = null;
try{
key = mc.lock("testlock", 3); //获取分布式
... //执行业务逻辑程序
}finally {
if (key!=null){
mc.unLock(key); //释放分布式锁
}
}

调用 trylock 方法

MqClient mc = new SimpleClient("ws://127.0.0.1:5001", "mymq=123");
mc.connect();
String key = null;
try{
key = mc.tryLock("testlock", 3); //获取分布式
... //执行业务逻辑程序
} finally {
if (key!=null){
mc.unLock(key); //释放分布式锁
}
}
以下是 tldb 分布式锁的功能测试数据: 多线程并发 调用 lock 获取同一个对象锁后,程序的运行数据:多线程并发使用自旋的方式调用 trylock 与 lock 获取同一个对象锁: 


往期推荐



Next.js支持在前端代码中写SQL,开倒车还是遥遥领先?
3202年了,为啥SSR并没有预想中的流行?微软CEO:放弃Windows Phone和移动业务,错了!

这里有最新开源资讯、软件更新、技术干货等内容

点这里 ↓↓↓ 记得 关注✔ 标星⭐ 哦


相关推荐

  • Windows 11已原生支持11种文件存档格式,包括7-Zip和RAR
  • 关于开源创业的15件小事
  • jQuery 4.0,开发进度已完成99%
  • 十月实践总结:粗看LLM+KG知识图谱研发和落地中的虚与实
  • ChatGPT测试上传文件功能;百川推出192K长文本大模型;通义千问App安卓版上线丨AIGC大事日报
  • 昆仑万维开源130亿参数大模型!0门槛商用、多榜超Llama 2,预训练数据也开源
  • 大模型又改变一个行业!解构AIoT巨头大华股份研发体系,技术大进化
  • 杭州/北京内推 | 阿里云人工智能平台深度学习团队招聘算法研究实习生
  • ICCV 2023 | 用“自编码器+多模态学习”更有效地解决3D物体可供性问题
  • 百川智能再发新模型,超越Claude2将上下文窗口做到了全球第一
  • 【ICCV2023】开放世界 TTT 的鲁棒性:自训练与动态原型扩展
  • 清华大学《高级机器学习》资料和院士特邀报告(附pdf下载)
  • 老板说我能力不行,怎么办?
  • 32.5K Star开源一款免费,没广告的音乐软件
  • 使用Python类型提示,保持代码整洁,提高可读性
  • 权威赛事、高额奖金,文心一言插件开发邀你来挑战!
  • Jenkins + Docker 一键自动化部署 SpringBoot 应用最精简流程
  • 7个理由:从Java8升级到Java17
  • 基于Transformer和注意力的可解释核苷酸语言模型,用于pegRNA优化设计
  • 像搭乐高一样做数学定理证明题,GPT-3.5证明成功率达新SOTA