Golang实现redis分布式锁

分布式的业务中共享资源需要安全的被访问和处理 , 就需要分布式锁

  1. 「锁的互斥性」:在分布式集群应用中共享资源的锁在同一时间只能被一个对象获取。

  2. 「可重入」:为了避免死锁,这把锁是可以重入的并且可以设置超时。

  3. 「高效的加锁和解锁」:能够高效的加锁和解锁,获取锁和释放锁的性能也好。

  4. 「阻塞、公平」:可以根据业务的需要,考虑是使用阻塞还是非阻塞,公平还是非公平的锁。

redis实现分布式锁主要靠SET key value EX * NX命令

  1. 当key存在时写入失败 , 保证互斥性

  2. 设置了key超时 , 避免死锁

  3. 利用mutex保证当前程序不存在并发冲突问题

  4. 此方法弊端是对超时时间的设置有要求,需要根据具体业务设置一个合理的经验值,避免锁超时时间到了,业务没执行完的问题。

代码方案1:

package redis

import (
    "context"
    "log"
    "sync"
    "time"

    "github.com/go-redis/redis/v8"
)

var rdb *redis.Client
var ctx = context.Background()
var mutex sync.Mutex

func NewRedis() {
    rdb = redis.NewClient(&redis.Options{
        Addr:     "192.168.1.7:6379",
        Password: "", // no password set
        DB:       0,  // use default DB
    })
}

func Lock(key string) bool {
    mutex.Lock()
    defer mutex.Unlock()
    //SET key value EX 10 NX
    bool, err := rdb.SetNX(ctx, key, 1, 10*time.Second).Result()
    if err != nil {
        log.Println(err.Error())
    }
    return bool
}
func UnLock(key string) int64 {
    nums, err := rdb.Del(ctx, key).Result()
    if err != nil {
        log.Println(err.Error())
        return 0
    }
    return nums
}

代码方案2:

package mian

import (
    "fmt"
    "time"
	
	"github.com/gomodule/redigo/redis"
)

func main(){
	rds, err := redis.Dial("tcp", "192.168.1.7:6379")
	if err != nil {
		fmt.Println("Fail to conn redis: ", err)
		return
	}
	defer rds.Close()
	
	for {
		ret, err := rds.Do("SET", "lock", 1, "EX", 5, "NX")
		if err != nil {
			fmt.Println("Fail to set lock: ", err)
		}
		
		ret, err = redis.String(ret, err)
		//加锁失败
		if ret != "OK"{
			fmt.Println("Fail to lock")
			time.Sleep(5 * time.Second)
			continue
		}
		
		//加锁成功
		fmt.Println("work start...")
		
		fmt.Println("work end...")
		
		//业务处理结束后释放锁
		ret, err := rds.Do("del", "lock")
		break;
	}
	
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章