Redis分布式锁无效

huangapple go评论76阅读模式
英文:

Redis distributed lock does not take effect

问题

我正在使用go-redis distributed lock实现互斥访问,我的服务器是单线程服务器。但是同时有很多请求获取到了distributed lock

获取锁的代码如下:

func (redisMgrPtr *RedisMgr) getLock(key string) (int32) {
    encodeKey := transcoding.Base64Encode(key)
    _, err := redisMgrPtr.redisClient.SetNX(redisMgrPtr.ctx, encodeKey, 1, TIMEOUT).Result()
    if err != nil {
        return -1
    }
    return 0
}

func (redisMgrPtr *RedisMgr) delLock(key string, sessionId string) {
    encodeKey := transcoding.Base64Encode(key)
    redisMgrPtr.redisClient.Del(redisMgrPtr.ctx, encodeKey)
    Log.Errorf("session[%s] del lock", sessionId)
}

获取锁的代码如下:

func (redisMgrPtr *RedisMgr) GetServer(name string, session string) () {
    for { 
        locRes := redisMgrPtr.getLock(name) 
        if locRes == 0 {
            break
        } else {
            time.Sleep(5 * time.Millisecond)
            continue
        }
    }
    defer redisMgrPtr.delLock(sceneLock, sessionId)
    Log.Errorf("session[%s] get lock", sessionId)
    // do something
}

我发现很多请求同时获取到了锁,结果如下:

2021-09-08T15:05:21.073+0800 session[51776955325] get lock
2021-09-08T15:05:21.073+0800 session[91776955325] get lock
2021-09-08T15:05:21.073+0800 session[71776955325] get lock

我认为在同一时间只有一个会话可以获取到锁。

英文:

I am using go-redis distributed lock to realize mutual exclusion access, my server is a single thread server. But at the same time, many requests get the distributed lock.

func (redisMgrPtr *RedisMgr) getLock(key string) (int32) {
    encodeKey := transcoding.Base64Encode(key)
    _, err := redisMgrPtr.redisClient.SetNX(redisMgrPtr.ctx, 
    encodeKey, 1, TIMEOUT).Result()
    if err != nil {
        return -1
    }
    return 0
}

func (redisMgrPtr *RedisMgr) delLock(key string, sessionId string) {
    encodeKey := transcoding.Base64Encode(key)
    redisMgrPtr.redisClient.Del(redisMgrPtr.ctx, encodeKey)
    Log.Errorf("session[%s] del lock", sessionId)
}

Get lock code is like this:

func (redisMgrPtr *RedisMgr) GetServer(name string, session string) () {
    for { 
        locRes := redisMgrPtr.getLock(name) 
        if locRes == 0 {
            break
        } else {
            time.Sleep(5 * time.Millisecond)
            continue
        }
    }
    defer redisMgrPtr.delLock(sceneLock, sessionId)
    Log.Errorf("session[%s] get lock", sessionId)
    // do something
}

I find many requests get the lock at the same time, result is

2021-09-08T15:05:21.073+0800 session[51776955325] get lock
2021-09-08T15:05:21.073+0800 session[91776955325] get lock
2021-09-08T15:05:21.073+0800 session[71776955325] get lock

I think at the same time only one session can get the lock

答案1

得分: 2

问题似乎出在锁定函数上。它没有检查值是否存在,只是检查了错误。

func (redisMgrPtr *RedisMgr) getLock(key string) (int32) {
    encodeKey := transcoding.Base64Encode(key)
    wasSet, err := redisMgrPtr.redisClient.SetNX(redisMgrPtr.ctx, encodeKey, 1, TIMEOUT).Result()
    if err != nil || !wasSet {
        return -1
    }
    return 0
}

... 或者使用布尔值使其更易于理解:

func (redisMgrPtr *RedisMgr) getLock(key string) (ok bool) {
    encodeKey := transcoding.Base64Encode(key)
    wasSet, err := redisMgrPtr.redisClient.SetNX(redisMgrPtr.ctx, encodeKey, 1, TIMEOUT).Result()
    return err == nil && wasSet
}

使用布尔值版本,GetServer 可以这样写:

func (redisMgrPtr *RedisMgr) GetServer(name string, session string) () {
    for { 
        if ok := redisMgrPtr.getLock(name); ok {
            break
        }
        time.Sleep(5 * time.Millisecond)
    }
    defer redisMgrPtr.delLock(sceneLock, sessionId)
    Log.Errorf("session[%s] get lock", sessionId)
    // 做一些操作
}
英文:

The problem seems to be with the lock function. It does not check if the value existed or not, it just checks the error.

func (redisMgrPtr *RedisMgr) getLock(key string) (int32) {
    encodeKey := transcoding.Base64Encode(key)
    wasSet, err := redisMgrPtr.redisClient.SetNX(redisMgrPtr.ctx, encodeKey, 1, TIMEOUT).Result()
    if err != nil || !wasSet {
        return -1
    }
    return 0
}

... or using a boolean to make it easier to reason about:

func (redisMgrPtr *RedisMgr) getLock(key string) (ok bool) {
    encodeKey := transcoding.Base64Encode(key)
    wasSet, err := redisMgrPtr.redisClient.SetNX(redisMgrPtr.ctx, encodeKey, 1, TIMEOUT).Result()
    return err == nil && wasSet
}

With the boolean version GetServer could look like this:

func (redisMgrPtr *RedisMgr) GetServer(name string, session string) () {
    for { 
        if ok := redisMgrPtr.getLock(name); ok {
            break
        }
        time.Sleep(5 * time.Millisecond)
    }
    defer redisMgrPtr.delLock(sceneLock, sessionId)
    Log.Errorf("session[%s] get lock", sessionId)
    // do something
}

huangapple
  • 本文由 发表于 2021年9月8日 18:03:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/69101000.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定