分布式锁
Redis 分布式锁基于 SET NX EX 命令实现。
基本实现
SET NX EX
bash
# 获取锁
SET lock:resource unique_value NX EX 10
# 释放锁(Lua 脚本保证原子性)
EVAL "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end" 1 lock:resource unique_valueGo 实现
go
package main
import (
"context"
"time"
"github.com/redis/go-redis/v9"
)
type RedisLock struct {
client *redis.Client
key string
value string
}
func (l *RedisLock) Acquire(timeout time.Duration) bool {
ctx := context.Background()
return l.client.SetNX(ctx, l.key, l.value, timeout).Val()
}
func (l *RedisLock) Release() error {
ctx := context.Background()
script := `
if redis.call("get", KEYS[1]) == ARGV[1] then
return redis.call("del", KEYS[1])
else
return 0
end
`
return l.client.Eval(ctx, script, []string{l.key}, l.value).Err()
}
// 使用示例
func main() {
rdb := redis.NewClient(&redis.Options{Addr: "localhost:6379"})
lock := &RedisLock{
client: rdb,
key: "lock:my-resource",
value: "unique-id",
}
if lock.Acquire(10 * time.Second) {
defer lock.Release()
// 执行关键操作
}
}Redlock 算法
Redis 官方提出的分布式锁算法,基于多个 Redis 实例。
原理
- 获取当前时间戳
- 依次向 N 个 Redis 实例请求锁
- 计算获取锁消耗的时间
- 只有大多数实例成功才算成功
- 锁的有效时间 = 设置时间 - 获取时间
Go 实现
go
import "github.com/go-redsync/redsync/v4"
// 使用 redsync 库
rs := redsync.New(redsync.NewPool(rdb1), redsync.NewPool(rdb2), redsync.NewPool(rdb3))
mutex := rs.NewMutex("lock:resource")
if err := mutex.Lock(); err != nil {
panic(err)
}
defer mutex.Unlock()最佳实践
- 锁超时:设置合理的过期时间
- 锁续期:长时间操作需要续期
- 唯一值:每个锁请求使用唯一标识
- 释放验证:只释放自己持有的锁
- 故障处理:使用 Redlock 提高可靠性
在下一章中,我们将学习性能优化。