redis分布式锁实现(golang版)

代码

.
.
.


const redisMutexLockExpTime = 15

// TryGetDistributedLock 分布式锁获取
// requestId 用于标识请求客户端,可以是随机字符串,需确保唯一
func TryGetDistributedLock(lockKey, requestId string, isNegative bool) bool {
    if isNegative { // 多次尝试获取
        retry := 1
        for {
            ok, err := cache.Do("SET", lockKey, requestId, "EX", redisMutexLockExpTime, "NX")
            // 获取锁成功
            if err == nil && ok == "OK" {
                return true
            }
            // 尝试多次没获取成功
            if retry > 10 {
                return false
            }
            time.Sleep(time.Millisecond * time.Duration(rand.Intn(1000)))
            retry += 1
        }
    } else { // 只尝试一次
        ok, err := cache.Do("SET", lockKey, requestId, "EX", redisMutexLockExpTime, "NX")
        // 获取锁成功
        if err == nil && ok == "OK" {
            return true
        }

        return false
    }
}

// ReleaseDistributedLock 释放锁,通过比较requestId,用于确保客户端只释放自己的锁,使用lua脚本保证操作的原子型
func ReleaseDistributedLock(lockKey, requestId string) (bool, error) {
    luaScript := ``  # 因为页面显示有问题,这里多加了个反引号,注意去除
    if redis.call("get",KEYS[1]) == ARGV[1]
    then
        return redis.call("del",KEYS[1])
    else
        return 0
    end``  # 因为页面显示有问题,这里多加了个反引号,注意去除

    do, err := cache.Do("eval", luaScript, 1, lockKey, requestId)
    fmt.Println(reflect.TypeOf(do))
    fmt.Println(do)

    if utils.AnyToInt64(do) == 1 {
        return true, err
    } else {
        return false, err
    }
}

// HandleBalanceDistributedLock 处理余额更新时获取锁和释放锁 如果加锁成功,使用语句 ` defer cb() ` 释放锁
func HandleBalanceDistributedLock(paramA,paramB,requestIdPrefix string) (cb func(), err error){

  lockKey := fmt.Sprintf("%s:xxx_lock:%s", paramA, paramB)
  requestId := GetDistributedLockRequestId(requestIdPrefix)
  lockOk := TryGetDistributedLock(lockKey, requestId, true)
  if !balanceLockOk {
  return nil, errors.New("系统繁忙,请稍后再试")
 }
  cb = func() {
  _, _ = ReleaseDistributedLock(lockKey, requestId)
 }
  return cb, nil
}

使用示例

// 获取锁
cb, err := HandleBalanceDistributedLock(c.GetString("mid"), utils.IntToStr(user.Info.Uid), "acq_reward")
    if err != nil {
        return err
    }
    // 加锁成功则最后释放锁
    if cb != nil {
        defer cb()
    }

参考

博客:redis应用系列一:分布式锁正确实现姿势

本作品采用《CC 协议》,转载必须注明作者和本文链接
Was mich nicht umbringt, macht mich stärker
讨论数量: 2

文中

if err == nil && ok == "OK" {
    return true
}

换成

if err != nil {
    // 记日志
    return false
}
if ok ==  "OK" {
    return true
}

如何?

2年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!