写点什么

redis 分布式锁原理

用户头像
Skysper
关注
发布于: 2021 年 06 月 12 日

什么是分布式锁

在多线程的应用中,当我们需要访问共享变量或共享资源时,需要对变量和资源进行同步,这些都涉及到锁的使用。在单机应用中,由于共享资源、变量可识别、可控,因此通过操作系统或应用层面的锁来进行同步。但是如果应用进行多机分布式部署,共享资源识别、控制无原子性保障,无法有效控制资源状态变更,便需要分布式锁来代替原本单机上的锁来完成同步功能。


分布式锁主要是利用第三方应用来实现加锁、解锁功能,通过第三方应用实现的原子性来保证资源的访问控制。

redis 分布式锁

加锁原理

SET Key value EX seconds NX


通过上述命令,可以保证原子方式进行加锁,命令执行成功,则返回 OK,失败返回 Null


加锁过程中,key为加锁资源,value为锁持有者标识,主要用于后续解锁过程


为了防止异常原因导致锁未有效失败,加锁时,都会设置过期时间,以防止引起线程饥饿而死锁。

解锁原理

在我们锁使用完毕后,一般需要通过手动进行失败,以提高锁利用效率。


锁释放时,必须在锁持有人是自己的情况下,才能做有效的释放。


我们需要查询锁 Key 内存储的 value 值,如果是自己,则可以释放锁。


由于锁 Key 自身有过期时间,因此需要保证在释放锁的过程中,锁状态未发生变化,始终是自己持有,或其他人未持有。因此我们需要保证这个过程的原子性:


1、获取锁Key的内容2、判断锁持有人是否是自己3、删除锁
复制代码


这个过程,我们往往需要借助于 lua 脚本


if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end
复制代码


由于 redis 工作线程为单线程,lua 脚本作为一个命令被整体执行,整个 redis 对于命令的处理是串行化的,不用存在并发风险。

分布式锁可能面对的场景

因为锁应该包含超时时间,以避免持有锁的线程异常未释放锁从而导致死锁的情况产生。然后在 java 程序中如果因为 GC 暂停时间超过超时时间,则可能因为并发产生一些不安全的变更。


除了 GC 以外,会存在其他由于系统处理较慢而引起锁过期,同步代码被并发访问。


there are many other reasons why your process might get paused. Maybe your process tried to read an address that is not yet loaded into memory, so it gets a page fault and is paused until the page is loaded from disk. Maybe your disk is actually EBS, and so reading a variable unwittingly turned into a synchronous network request over Amazon’s congested network. Maybe there are many other processes contending for CPU, and you hit a black node in your scheduler tree. Maybe someone accidentally sent SIGSTOP to the process. Whatever. Your processes will get paused
复制代码


参考文献:


[1] http://pages.cs.wisc.edu/~remzi/Classes/739/Spring2003/Papers/leases-redis-problem.pdf

发布于: 2021 年 06 月 12 日阅读数: 22
用户头像

Skysper

关注

人生不在于谁更优秀,而在于谁更坚持 2016.03.29 加入

还未添加个人简介

评论

发布
暂无评论
redis分布式锁原理