redis分佈式鎖的實現 golang

代碼

獲得鎖 釋放鎖

分佈式鎖可用必須滿足一下四個條件

  • 互斥性 在任意時刻 只有一個客戶端能獲取到鎖
  • 不會發生死鎖 即使有一個客戶端 在持有鎖的期間奔潰而沒有主動解鎖, 也能保證後續客戶端能解鎖
  • 具有容錯性 只要大部分的redis 節點正常運行, 客戶端就可以加鎖和解鎖
  • 解鎖加鎖同一個客戶端。 加鎖和解鎖必須是同一個客戶端,客戶端不能把別人加的鎖給解除了。

package main

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

// https://www.w3cschool.cn/redis/redis-yj3f2p0c.html
// redis 分佈式鎖實現
func init() {
	initRedis()
}

var redisPool *redis.Pool

func initRedis() {
	redisPool = &redis.Pool{
		MaxIdle:     10,
		MaxActive:   10,
		IdleTimeout: 5 * time.Second,
		Dial: func() (conn redis.Conn, e error) {
			conn, err := redis.Dial("tcp", "127.0.1.1:6379")
			if err != nil {
				return nil, err
			}
			conn.Do("select", 0)
			return conn, err
		},
	}
}

const LockName = "LockName"
const StringSetIfNotExist = "NX"
const StringSetWithExpireTime = "EX"

func getLock(id string) bool {
	// 獲得鎖
	// 一個命令原子操作  爲了防止執行了nx 之後程序突然奔潰 則就會無法設置過期時間發生死鎖
	conn := redisPool.Get()
	defer conn.Close()
	_, err := redis.String(conn.Do("set", LockName, id, StringSetIfNotExist, StringSetWithExpireTime, 10))
	if err == nil {
		return true
	}
	return false

}

const luaScript = `
if redis.call('get', KEYS[1])==ARGV[1] then
	return redis.call('del', KEYS[1])
else
	return 0
end
`

func releaseDistributedLock(id string) bool {
	// 釋放分佈式鎖
	// 也必須是原子操作 藉助於lua 腳本實現
	// 誰 上鎖誰解鎖
	conn := redisPool.Get()
	defer conn.Close()
	lua := redis.NewScript(1, luaScript) // 定義參數的個數 
	_, err := redis.Int(lua.Do(conn, LockName, id)) // 上面定義幾個參數conn 後面幾個都是參數, 參數的後面就是值 按照順序
	if err == nil {
		return true
	}
	return false
}
func main() {
	theId := "yang"
	flag := getLock(theId)
	fmt.Println(flag)
	releaseFlag := releaseDistributedLock(theId)
	fmt.Println("releaseFlag: ", releaseFlag)
}

發佈了164 篇原創文章 · 獲贊 54 · 訪問量 19萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章