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
}
windows技术爱好者
Original: https://www.cnblogs.com/majiang/p/15621088.html
Author: dz45693
Title: go redis锁
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/528886/
转载文章受原作者版权保护。转载请注明原作者出处!