Redis分布式锁不生效

Posted

技术标签:

【中文标题】Redis分布式锁不生效【英文标题】:Redis distributed lock does not take effect 【发布时间】:2021-11-05 02:31:48 【问题描述】:

我正在使用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

我认为同时只有一个会话可以得到锁

【问题讨论】:

你也可以发布getNewDistributeLock方法吗? @NuLo 我更新了 你可以使用像redislock这样的包它应该为你简化事情 【参考方案1】:

问题似乎与锁定功能有关。它不检查值是否存在,它只是检查错误。

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)
    // do something

【讨论】:

以上是关于Redis分布式锁不生效的主要内容,如果未能解决你的问题,请参考以下文章

redis分布式锁-基本概念与实现方式对比

redis实现可重入分布式锁

Redis 分布式锁完善这把“锁”

Redis 分布式锁完善这把“锁”

大厂面试题详解:如何用Redis实现分布式锁?

Redis实现分布式锁与Zookeeper实现分布式锁区别