go-redsync执行报错:panic: redsync: failed to acquire lock

大佬们问个问题,redsync锁为什么执行到第二个goroutine就会报错呢?
panic: redsync: failed to acquire lock

package main

import (
    "fmt"
    "sync"
    "time"

    goredislib "github.com/go-redis/redis/v8"
    "github.com/go-redsync/redsync/v4"
    "github.com/go-redsync/redsync/v4/redis/goredis/v8"
)

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 3; i++ {
        wg.Add(1)
        go RedisLock(&wg)
    }
    wg.Wait()
}
func RedisLock(wg *sync.WaitGroup) {
    defer wg.Done()
    redisAddr := "192.168.31.51:6379"
    client := goredislib.NewClient(&goredislib.Options{
        Addr:     redisAddr,
        Password: "123456",
    })
    pool := goredis.NewPool(client)
    rs := redsync.New(pool)
    mutexname := "product@1"
    mutex := rs.NewMutex(mutexname)
    fmt.Println("Start Lock...")
    err := mutex.Lock()
    if err != nil {
        panic(err)
    }
    fmt.Println("Get Lock!")
    time.Sleep(time.Second * 3)
    fmt.Println("Unlock!")
    ok, err := mutex.Unlock()
    if !ok {
        panic("Unlock Failed!")
    }
    if err != nil {
        panic(err)
    }
    fmt.Println("Release Lock!")
}

问题:

Start Lock...
Start Lock...
Start Lock...
Get Lock!
Unlock!
Release Lock!
Get Lock!
panic: redsync: failed to acquire lock

goroutine 20 [running]:
main.RedisLock(0x0)
    /Users/ma/go/study/micro/8/test/main.go:35 +0x2b0

Go版本:1.17.3

阅读 5.2k
3 个回答

redsync 的分布式锁不是无限等待,重试几次之后就会直接失败。

你这个应该是第三个 goroutine 等太久拿不到锁,失败了。


ErrFailed

// ErrFailed is the error resulting if Redsync fails to acquire the lock after
// exhausting all retries.
var ErrFailed = errors.New("redsync: failed to acquire lock")

mutexname 不能重复

package main

import (
    "fmt"
    "sync"
    "time"

    goredislib "github.com/go-redis/redis/v8"
    "github.com/go-redsync/redsync/v4"
    "github.com/go-redsync/redsync/v4/redis/goredis/v8"
)

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 3; i++ {
        wg.Add(1)
        go RedisLock(&wg, i)
    }
    wg.Wait()
}
func RedisLock(wg *sync.WaitGroup, i int) {
    defer wg.Done()
    redisAddr := "192.168.31.51:6379"
    client := goredislib.NewClient(&goredislib.Options{
        Addr:     redisAddr,
        Password: "123456",
    })
    pool := goredis.NewPool(client)
    rs := redsync.New(pool)
    mutexname := "product@" + fmt.Sprintf("%v", i)
    mutex := rs.NewMutex(mutexname)
    fmt.Println("Start Lock...")
    err := mutex.Lock()
    if err != nil {
        panic(err)
    }
    fmt.Println("Get Lock!")
    time.Sleep(time.Second * 3)
    fmt.Println("Unlock!")
    ok, err := mutex.Unlock()
    if !ok {
        panic("Unlock Failed!")
    }
    if err != nil {
        panic(err)
    }
    fmt.Println("Release Lock!")
}

输出:
Start Lock...
Start Lock...
Start Lock...
Get Lock!
Get Lock!
Get Lock!
Unlock!
Unlock!
Unlock!
Release Lock!
Release Lock!
Release Lock!

func (r *Redsync) NewMutex(name string, options ...Option) *Mutex {
    m := &Mutex{
        name:   name,
        expiry: 8 * time.Second,
        tries:  32,
        delayFunc: func(tries int) time.Duration {
            return time.Duration(rand.Intn(maxRetryDelayMilliSec-minRetryDelayMilliSec)+minRetryDelayMilliSec) * time.Millisecond
        },
        genValueFunc:  genValue,
        driftFactor:   0.01,
        timeoutFactor: 0.05,
        quorum:        len(r.pools)/2 + 1,
        pools:         r.pools,
    }
    for _, o := range options {
        o.Apply(m)
    }
    return m
}

分析了一下源码,超时重试的机制默认是50~250ms,重试32次,也就是说最短1.6s就全部重试失败了,所以可以通过调整配置避免这种情况,如增加重试次数

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题