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


 前言:分布式锁是分布式系统中一个极为重要的工具。目前有多种分布式锁的设计方案,比如借助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-j

maven配置

<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获取同一个对象锁:







有任何问题或建议请Email:donnie4w@gmail.comhttps://tlnet.top/contact  发信给我,谢谢!