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;
	}
	
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章