在并发场景中,我们经常需要对一些临界资源串行化。对于单节点部署的服务来说,可以使用内存锁进行阻塞控制,但是在多节点服务的情况下,由于机器 || 进程之间的内存无法共享。就需要引入分布式 。
基于 redis 实现分布式锁是常见的一种思路。原理是 redis 的 setnx 在值存在时无法成功设置。
上锁:set lockKey uniqVal nx ex ${lockTTL}
解锁:get lockKey 、 compare value、 del value。
● 解锁时为什么要先get 再del ?
当发生激烈的锁竞争时,会导致误删其他线程持有的锁。其他线程想续期时,会拿不到锁。
举个列子。线程 A 首先持有了锁,并预期5s内会释放锁(EX=5s)但是执行时超过了5s,但是key会在 5s 被 redis 自动过期,这时假设线程 B 来抢锁,由于Key 已过期,所以抢锁成功,并执行逻辑。这时 线程A 执行完了,他直接删除了这个key,那么就相当于为B线程解锁了,因为这个锁目前是被线程B持有的;这时B想要续期他的锁,发现自己已经没有持有锁了,会发生异常。所以解锁时先要compare 当前线程是否还持有锁,并安全地删除key,并且会使用一个lua脚本来保证 get、compare、del 这三个操作是原子化的。
基于 redis 客户端 github.com/garyburd/redigo/redis 。
代码已上传 github 。
https://github.com/ainiou/distribute_lock