golang 實現Redis分布式鎖


 

package main

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

type Redis struct {
pool *redis.Pool
key string
value string
timeout int
}

var redisPool *Redis

func initRedis() {
redisPool = new(Redis)
redisPool.pool = &redis.Pool{
MaxIdle: 256, //池中最大空閑連接數。
MaxActive: 0, //給定時間池分配的最大連接數。 如果為零,則池中的連接數沒有限制。
IdleTimeout: time.Duration(120), //在此期間保持空閑后關閉連接。 如果該值為零,則不關閉空閑連接。 應用程序應將超時設置為小於服務器超時的值。
Dial: func() (redis.Conn, error) { //撥號是應用程序提供的用於創建和配置連接的功能。 從Dial返回的連接不得處於特殊狀態(已訂閱pubsub通道,事務已開始,...)。
return redis.Dial(
"tcp",
"127.0.0.1:7240",
redis.DialReadTimeout(time.Duration(1000)*time.Millisecond), //DialReadTimeout指定讀取單個命令答復的超時。
redis.DialWriteTimeout(time.Duration(1000)*time.Millisecond), //DialWriteTimeout制定寫入單個命令答復的超時時間
redis.DialConnectTimeout(time.Duration(1000)*time.Millisecond), //DialConnectTimeout指定在未指定DialNetDial選項時連接到Redis服務器的超時時間。
redis.DialDatabase(0),
//red.DialPassword(""),
)
},
}
}

func (r *Redis) Lock() (ok bool, err error) {
c := r.pool.Get()
defer c.Close()
//設置鎖key-value和過期時間
_, err = redis.String(c.Do("SET", r.key, r.value, "EX", r.timeout, "NX"))
if err != nil {
if err == redis.ErrNil {
return false, nil
}
return false, err
}
return true, nil
}

func (r *Redis) Unlock(value string) (err error) {
c := r.pool.Get()
defer c.Close()
//獲取鎖value
setValue, err := redis.String(c.Do("GET", r.key))
if err != nil {
return
}
//判斷鎖是否屬於該釋放鎖的線程
if setValue != value {
err = errors.New("非法用戶,無法釋放該鎖")
return
}
//屬於該用戶,直接刪除該key
_, err = c.Do("DEL", r.key)
return
}

//延期,應該判斷value后再延期

func (r *Redis) AddTimeout() (ok bool, err error) {
c := r.pool.Get()
defer c.Close()

//獲取key的剩余有效時間 當key不存在時返回-2 當未設置過期時間的返回-1
ttl_time, err := redis.Int64(c.Do("TTL", r.key))
if err != nil {
fmt.Println("redis get fail:", err)
return
}
if ttl_time > 0 {
_, err = redis.String(c.Do("SET", r.key, r.value, "EX", r.timeout))
if err == redis.ErrNil {
return false, nil
}
if err != nil {
return false, err
}
}
return true, nil
}

func main() {
//初始化redis連接池
initRedis()

r := &Redis{
key: "hello",
value: "lock",
timeout: 10,
pool: redisPool.pool,
}
ok, _ := r.Lock()
if ok {
fmt.Println("加鎖成功:")

//創建協程,定時延期鎖的過期時間
go func(r *Redis) {
for {
select {
case <-time.After(time.Duration(r.timeout-1) * time.Second):
r.AddTimeout()
}
}
}(r)
err := r.Unlock("haha")
if err != nil {
fmt.Println("釋放鎖失敗:", err)
} else {
fmt.Println("成功釋放鎖:")
}
} else {
fmt.Println("加鎖失敗:")
}

//阻塞進程,避免退出
select {}
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM