redis经常用作分布式锁,这里记录一个简单的锁代码如下:
package main import ( "crypto/rand" "encoding/base64" "fmt" "github.com/go-redis/redis" "io" "sync" "time" ) func main() { addr := "192.168.100.30:6379" rdb := redis.NewUniversalClient(&redis.UniversalOptions{ Addrs: []string {addr}, Password: "", // no password set DB: 0, // use default DB }) defer func() { _ = rdb.Close() }() key := "gavin-lock" uid, err := Lock(rdb, key, time.Second*1, time.Second*2) if err == nil { _ = Unlock(rdb, key, uid) } } var randMutex sync.Mutex var randBytes []byte // 获取随机字串 func randToken() string { randMutex.Lock() defer randMutex.Unlock() if len(randBytes) == 0 { randBytes = make([]byte, 16) } if _, err := io.ReadFull(rand.Reader, randBytes); err != nil { return "" } return base64.RawURLEncoding.EncodeToString(randBytes) } func Lock(redisClient redis.UniversalClient, lockKey string, acquireTimeOut, lockTimeOut time.Duration) (token string, err error) { token = randToken() var acquireDuration = acquireTimeOut for acquireDuration > 0 { ok, err := redisClient.SetNX(lockKey, token, lockTimeOut).Result() if err != nil { fmt.Printf("redis锁 - 加锁失败 key: %s, token: %s, ttl: %v, err: %v\r\n", lockKey, token, lockTimeOut, err) return "", err } if ok { fmt.Printf("redis锁 - 加锁成功 key: %s, token: %s, ttl: %v\r\n", lockKey, token, lockTimeOut) return token, nil } time.Sleep(time.Millisecond * 100) // next: sleep 500ms acquireDuration -= time.Millisecond * 100 } fmt.Printf("redis锁 - 加锁超时 key: %s, token: %s, ttl: %v\r\n", lockKey, token, acquireTimeOut) return "", fmt.Errorf("获取redis锁超时: %v\r\n", acquireTimeOut) } func Unlock(redisClient redis.UniversalClient, lockKey, token string) error { const script = `if redis.call('GET', KEYS[1]) == ARGV[1] then return redis.call('DEL', KEYS[1]) else return 0 end` ret, err := redisClient.Eval(script, []string{lockKey}, token).Result() if err != nil { fmt.Printf("redis锁 - 解锁失败 key: %s, token: %s, err: %v\r\n", lockKey, token, err) return err } if v, ok := ret.(int64); ok && v == 1 { fmt.Printf("redis锁 - 解锁成功 key: %s, token: %s\r\n", lockKey, token) return nil } fmt.Printf("redis锁 - 解锁失败 key: %s, token: %s, key已经过期\r\n", lockKey, token) return nil }