Golang | redis实现分布式锁
概述
网上有很多Golang操作redis的例子,我使用github.com/gomodule/redigo/redis
包写一个关于redis分布式锁的问题。
redis分布式锁
锁需要的几个组件
- 获取锁- 删除锁 分布式锁还需要
- 给锁加上唯一id (只能获取和删除自己的锁)- 给锁加上过期时间 (防止死锁)
golang代码
推荐使用redis的连接池
pool := redis.Pool{
MaxIdle: 8,
MaxActive: 0,
IdleTimeout: 100,
Dial: func() (redis.Conn, error) {
return redis.Dial("tcp", "127.0.0.1:6100")
},
}
通过lua脚本保证获取锁/加过期时间
和获取锁的值/删除锁
为原子操作
var (
updateLockExpireUidScript = redis.NewScript(1, `
local res = redis.call("SETNX", KEYS[1], ARGV[1])
if res == 1 then
return redis.call("EXPIRE", KEYS[1], ARGV[2])
end
return res
`)
deleteLockByUidScript = redis.NewScript(1, `
local res = redis.call("GET", KEYS[1])
if res == ARGV[1] then
return redis.call("DEL", KEYS[1])
end
return res
`)
)
golang完整代码
package main
import (
"fmt"
"github.com/gomodule/redigo/redis"
"time"
)
func getLock(conn redis.Conn, key []string, uid int, expire int) bool {
lock := false
for !lock {
res, err := updateLockExpireUidScript.Do(conn, key, uid, expire)
if err != nil {
fmt.Println(err.Error())
break
}
if res.(int64) == 1 {
lock = true
fmt.Println("获取锁成功")
return true
}
}
fmt.Println("获取锁失败")
return false
}
func delLock(conn redis.Conn, key []string, uid int) bool {
_, err := deleteLockByUidScript.Do(conn, key, uid)
if err != nil {
fmt.Println("删除锁失败")
fmt.Println(err.Error())
return false
}
fmt.Println("删除锁成功")
return true
}
var (
updateLockExpireUidScript = redis.NewScript(1, `
local res = redis.call("SETNX", KEYS[1], ARGV[1])
if res == 1 then
return redis.call("EXPIRE", KEYS[1], ARGV[2])
end
return res
`)
deleteLockByUidScript = redis.NewScript(1, `
local res = redis.call("GET", KEYS[1])
if res == ARGV[1] then
return redis.call("DEL", KEYS[1])
end
return res
`)
)
func main() {
pool := redis.Pool{
MaxIdle: 8,
MaxActive: 0,
IdleTimeout: 100,
Dial: func() (redis.Conn, error) {
return redis.Dial("tcp", "127.0.0.1:6100")
},
}
key := []string{"distribute"}
uid := 1
expire := 20
fmt.Println(time.Now())
for i:= 1; i< 100; i++ {
go func() {
conn := pool.Get()
if getLock(conn, key, uid, expire) {
fmt.Println("开始执行逻辑...")
fmt.Println("逻辑结束,删除锁")
delLock(conn, key, uid)
}
}()
}
fmt.Println(time.Now())
time.Sleep(time.Second * 20)
}
--完--
- 原文作者: 留白
- 原文链接: https://zfunnily.github.io/2021/06/distribute/
- 更新时间:2024-04-16 01:01:05
- 本文声明:转载请标记原文作者及链接