Redis 分布式锁通常基于以下原理
package main
import (
"fmt"
"time"
"github.com/go-redsync/redsync/v4"
"github.com/go-redsync/redsync/v4/redis/goredis/v9"
goredislib "github.com/redis/go-redis/v9"
"sync"
)
func RedisLock(wg *sync.WaitGroup) {
// 初始化锁客户端
client := goredislib.NewClient(&goredislib.Options{
Addr: "127.0.0.1:6380",
Password: "123456_redis",
Username: "root",
DB: 0,
})
pool := goredis.NewPool(client) // or, pool := redigo.NewPool(...)
rs := redsync.New(pool)
// 初始化锁
mutexname := "my-global-mutex"
mutex := rs.NewMutex(mutexname, redsync.WithExpiry(30*time.Second))
// 开始锁定
fmt.Println("Lock()....")
if err := mutex.Lock(); err != nil {
panic(err)
}
// 自己的一些业务逻辑
fmt.Println("Get Lock!!!")
time.Sleep(time.Second * 1)
// 开始解锁
fmt.Println("UnLock()")
if ok, err := mutex.Unlock(); !ok || err != nil {
panic("unlock failed")
}
fmt.Println("Released Lock!!!")
}
func main() {
// 测试程序
var wg sync.WaitGroup
for i := 0; i < 3; i++ {
wg.Add(1)
go RedisLock(&wg)
}
wg.Wait()
}
程序运行,输出
Lock()....
Lock()....
Lock()....
Get Lock!!!
UnLock()
Released Lock!!!
Get Lock!!!
UnLock()
Released Lock!!!
Get Lock!!!
UnLock()
Released Lock!!!
前三个Lock() 代表程序在排队阶段
后面接着三次输出,每次都有: Get Lock!!!, UnLock(), Released Lock!!!
每个过程都是 获取锁,解锁,释放锁
所以在高并发的时候,使用redis的分布式锁可以解决资源数据的竞争
特别注意的是: mutexname := "my-global-mutex"
这个锁的名称在 redis 中使用的时候会生成,当锁被全部释放后,就会自动释放,而且这个锁的名称最好也自行规范下
// 以下是 docker 内的redis容器cli
127.0.0.1:6379> keys *
1) "my-global-mutex"
// 稍后再次查询后,锁的key和value消失
127.0.0.1:6379> keys *
(empty array)
另外,如果锁在规定的时间内没有完成工作,那么在设定的过期时间后就会自动结束,如果不设置过期时间,走系统内的过期时间
goredis.NewPool
方法来创建一个基于 go-redis 客户端的锁池redsync.New
方法来创建一个 Redsync
实例,并使用 NewMutex
方法来创建一个分布式锁,可以为锁指定一个名称,并设置锁的过期时间。