【分布式锁】利用Redis实现分布式锁

1. go-zero 分布式锁实现

看下 go-zero 中 redis 分布式锁的实现

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
var (
	lockScript = NewScript(`if redis.call("GET", KEYS[1]) == ARGV[1] then
    redis.call("SET", KEYS[1], ARGV[1], "PX", ARGV[2])
    return "OK"
else
    return redis.call("SET", KEYS[1], ARGV[1], "NX", "PX", ARGV[2])
end`)
	delScript = NewScript(`if redis.call("GET", KEYS[1]) == ARGV[1] then
    return redis.call("DEL", KEYS[1])
else
    return 0
end`)
)

加锁和解锁的过程都是通过 lua 脚本实现的,因为 lua 脚本能够保证 redis 的原子性。

2. 分布式锁必须拥有的属性

  • 排他性(只能有一个协程持有)
  • 可重入(已经获取锁的协程能再次访问)
  • 防死锁(必须有超时时间,达到后持有者自动释放)
  • 高性能高可用

3. go-zero 分布式锁加锁流程

1
2
3
4
5
6
7
8
# 判断ARGV[1]是否等于KEY[1]的值
# 如果相等,说明是该锁的持有者重入,更新锁的过期时间,返回OK
# 如果不想等,说明锁不存在或者该用户不是锁的持有者,用set nx px命令操作该key
lockScript = NewScript(`if redis.call("GET", KEYS[1]) == ARGV[1] then
    redis.call("SET", KEYS[1], ARGV[1], "PX", ARGV[2])
    return "OK"
else
    return redis.call("SET", KEYS[1], ARGV[1], "NX", "PX", ARGV[2])

4. go-zero 分布式锁解锁流程

1
2
3
4
5
6
7
# 判断ARGV[1]是否等于KEY[1]的值
# 如果相等,说明是锁的拥有者,删除分布式锁的KEY
# 如果不想等,说明不是锁的拥有者,返回0
delScript = NewScript(`if redis.call("GET", KEYS[1]) == ARGV[1] then
    return redis.call("DEL", KEYS[1])
else
    return 0
Licensed under CC BY-NC-SA 4.0
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计