代碼
獲得鎖 釋放鎖
分佈式鎖可用必須滿足一下四個條件
- 互斥性 在任意時刻 只有一個客戶端能獲取到鎖
- 不會發生死鎖 即使有一個客戶端 在持有鎖的期間奔潰而沒有主動解鎖, 也能保證後續客戶端能解鎖
- 具有容錯性 只要大部分的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)
}