redis 分布式锁原理
什么是分布式锁
在多线程的应用中,当我们需要访问共享变量或共享资源时,需要对变量和资源进行同步,这些都涉及到锁的使用。在单机应用中,由于共享资源、变量可识别、可控,因此通过操作系统或应用层面的锁来进行同步。但是如果应用进行多机分布式部署,共享资源识别、控制无原子性保障,无法有效控制资源状态变更,便需要分布式锁来代替原本单机上的锁来完成同步功能。
分布式锁主要是利用第三方应用来实现加锁、解锁功能,通过第三方应用实现的原子性来保证资源的访问控制。
redis 分布式锁
加锁原理
SET Key value EX seconds NX
通过上述命令,可以保证原子方式进行加锁,命令执行成功,则返回 OK,失败返回 Null
加锁过程中,key
为加锁资源,value
为锁持有者标识,主要用于后续解锁过程
为了防止异常原因导致锁未有效失败,加锁时,都会设置过期时间,以防止引起线程饥饿而死锁。
解锁原理
在我们锁使用完毕后,一般需要通过手动进行失败,以提高锁利用效率。
锁释放时,必须在锁持有人是自己的情况下,才能做有效的释放。
我们需要查询锁 Key 内存储的 value 值,如果是自己,则可以释放锁。
由于锁 Key 自身有过期时间,因此需要保证在释放锁的过程中,锁状态未发生变化,始终是自己持有,或其他人未持有。因此我们需要保证这个过程的原子性:
这个过程,我们往往需要借助于 lua 脚本
由于 redis 工作线程为单线程,lua 脚本作为一个命令被整体执行,整个 redis 对于命令的处理是串行化的,不用存在并发风险。
分布式锁可能面对的场景
因为锁应该包含超时时间,以避免持有锁的线程异常未释放锁从而导致死锁的情况产生。然后在 java 程序中如果因为 GC 暂停时间超过超时时间,则可能因为并发产生一些不安全的变更。
除了 GC 以外,会存在其他由于系统处理较慢而引起锁过期,同步代码被并发访问。
参考文献:
[1] http://pages.cs.wisc.edu/~remzi/Classes/739/Spring2003/Papers/leases-redis-problem.pdf
版权声明: 本文为 InfoQ 作者【Skysper】的原创文章。
原文链接:【http://xie.infoq.cn/article/2e8e0673d6ac906620e08163b】。文章转载请联系作者。
评论