IT袋

当前位置:主页 > 经验教程 > 建站编程 >

手动实现一个Redis分布式锁

手动实现一个Redis分布式锁 手工创建一个Redis分布式锁(2)

时间:2024-02-22 18:37:55 来源:IT袋 作者:马勇
导读:手动实现一个Redis分布式锁,对于线程 B,将超时时间 Tb = 201 通过 GetSet() 设置, 由于锁超时时间已经被 A 重新设置,所以返回 T2 = 200 ,此时不满足条件 “T1 == T2”,获取锁失败。 可

手动实现一个Redis分布式锁

  • 对于线程 B,将超时时间 Tb = 201 通过 GetSet() 设置,由于锁超时时间已经被 A 重新设置,所以返回 T2 = 200,此时不满足条件 “T1 == T2”,获取锁失败。
  • 可能有同学会继续问,之前设置的超时是 Ta = 200,现在变成了 Tb = 201,延长或缩短了锁的超时时间,不会有问题么?

    其实在现实并发场景中,能走到这一步,基本是“同时”进来的,两者的时间差非常小,可以忽略此影响。

    3、代码实战

    这里给出 Go 代码,注释都写得非常详细,即使你不会 Go,读注释也能读懂。

    // 获取分布式锁,需要考虑以下情况:
    // 1. 机器A获取到锁,但是在未释放锁之前,机器挂掉或者重启,会导致其它机器全部hang住,这时需要根据锁的超时时间,判断该锁是否需要重置;
    // 2. 当锁超时时,需要考虑两台机器同时去获取该锁,需要通过GETSET方法,让先执行该方法的机器获取锁,另外一台继续等待。
    func GetDistributeLock(key string, expireTime int64) bool {
     currentTime := time.Now().Unix()
     expires := currentTime + expireTime
     redisAlias := "jointly"
     // 1.获取锁,并将value值设置为锁的超时时间
     redisRet, err := redis.SetNx(redisAlias, key, expires)
     if nil == err && utils.MustInt64(1) == redisRet {
      // 成功获取到锁
      return true
     }
     // 2.当获取到锁的机器突然重启&挂掉时,就需要判断锁的超时时间,如果锁超时,新的机器可以重新获取锁
     // 2.1 获取锁的超时时间
     currentLockTime, err := redis.GetKey(redisAlias, key)
     if err != nil {
      return false
     }
     // 2.2 当"锁的超时时间"大于等于"当前时间",证明锁未超时,直接返回
     if utils.MustInt64(currentLockTime) >= currentTime {
      return false
     }
     // 2.3 将最新的超时时间,更新到锁的value值,并返回旧的锁的超时时间
     oldLockTime, err := redis.GetSet(redisAlias, key, expires)
     if err != nil {
      return false
     }
     // 2.4 当锁的两个"旧的超时时间"相等时,证明之前没有其它机器进行GetSet操作,成功获取锁
     // 说明:这里存在并发情况,如果有A和B同时竞争,A会先GetSet,当B再去GetSet时,oldLockTime就等于A设置的超时时间
     if utils.MustString(oldLockTime) == currentLockTime {
      return true
     }
     return false
    }

    删除锁逻辑:

    // 删除分布式锁
    // @return bool true-删除成功;false-删除失败
    func DelDistributeLock(key string) bool {
     redisAlias := "jointly"
     redisRet := redis.Del(redisAlias, key)
     if redisRet != nil {
      return false
     }
     return true
    }

    业务逻辑:

    func DoProcess(processId int) {
     fmt.Printf("启动第%d个线程\n", processId)
     redisKey := "redis_lock_key"
     for {
      // 获取分布式锁
      isGetLock := GetDistributeLock(redisKey, 10)
      if isGetLock {
       fmt.Printf("Get Redis Key Success, id:%d\n", processId)
       time.Sleep(time.Second * 3)
       // 删除分布式锁
       DelDistributeLock(redisKey)
      } else {
       // 如果未获取到该锁,为了避免redis负载过高,先睡一会
       time.Sleep(time.Second * 1)
      }
     }

    相关阅读

    • 广域网 WAN的主要特点是什么

      广域网 WAN的主要特点是什么

      如果想知道的相关介绍,接下来IT袋网小编为大家介绍。 广域网(Wide Area Network)跨越更大的地理区域,通常连接不同城市、国家甚至大洲的设备。 特点 广泛范围: WAN的范围非常广泛,可以连

    • 数据库中的acid是什么意思

      数据库中的acid是什么意思

      对于许多网友来说数据库中的acid是什么意思的相关话题,接下来IT袋网小编为大家介绍。 我们说到数据库的时候,常常提到其 ACID 属性。那么 ACID 是什么意思呢? ACID 是用来 描述数据库事务

    • 5G-Advanced优势有哪些

      5G-Advanced优势有哪些

      关于这方面的知识你知道吗?5G-Advanced优势有哪些的电脑小知识,下面为详细的介绍。 容量提升与速度飞跃 5G Advanced将继续挑战7 GHz以下和毫米波频谱的频谱效率限制。通过不断优化MIMO技术,

    • GPU是什么:GPU的基础知识与应用领域

      GPU是什么:GPU的基础知识与应用领域

      跟大家聊一聊GPU是什么的相关介绍,下面小编为您详细解答 1. GPU的基本概念 GPU(Graphics Processing Unit),中文名为图形处理器,是计算机中负责处理图形和图像运算的硬件设备。 在现代计算机