赞
踩
项目最近涉及到自动弹缩,因此涉及到分布式锁相关的处理;
项目redis采用go-redis
库(点击跳转)进行操作;因此基于此实现了一个分布式锁,做一个记录;
如有缺陷,欢迎指正
SETNX
命令的特性来完成的, 即:仅首次设置值时才能够设置成功MULTI/EXEC
,同时 WATCH
锁保证不会错误的释放锁;package fwRedis import ( "errors" "fmt" "github.com/go-redis/redis/v7" "github.com/satori/go.uuid" "leiax00.com/fxWeb/util" "time" ) func GetLock(lockName string, acquireTimeout, lockTimeOut time.Duration) (string, error) { code := uuid.NewV4().String() endTime := util.FwTimer.CalcMillis(time.Now().Add(acquireTimeout)) for util.FwTimer.CalcMillis(time.Now()) <= endTime { if success, err := fwRedisClient.SetNX(lockName, code, lockTimeOut).Result(); err != nil && err != redis.Nil { return "", err } else if success { return code, nil } else if fwRedisClient.TTL(lockName).Val() == -1 { //-2:失效;-1:无过期; fwRedisClient.Expire(lockName, lockTimeOut) } time.Sleep(time.Millisecond) } return "", errors.New("timeout") } //var count = 0 // test assist func ReleaseLock(lockName, code string) bool { txf := func(tx *redis.Tx) error { if v, err := tx.Get(lockName).Result(); err != nil && err != redis.Nil { return err } else if v == code { _, err := tx.Pipelined(func(pipe redis.Pipeliner) error { //count++ //fmt.Println(count) pipe.Del(lockName) return nil }) return err } return nil } for { if err := fwRedisClient.Watch(txf, lockName); err == nil { return true } else if err == redis.TxFailedErr { fmt.Println("watch key is modified, retry to release lock. err:", err.Error()) } else { fmt.Println("err:", err.Error()) return false } } }
完整代码实例 ==> please click me
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。