Redis系列(二):Redis的分布式锁解析及应用

在开发中,一个进程中多个线程需要竞争某一资源的时候,我们通常会用一把锁来保证只有一个线程获取到资源。如加上synchronize关键字或ReentrantLock锁等操作。但如果是多个进程相互竞争一个资源,如何保证资源只会被一个操作者持有呢?

比如在微服务的架构下,多个应用服务要同时对同一条数据做修改,要确保数据的正确性,那就只能有一个应用修改成功。

Redis实现分布式锁

上一篇文章中在String-字符串类型中可以用作分布式锁,那么具体是如何实现的呢?

首先 Redis 是一个单独的非业务服务,不会受到其他业务服务的限制,所有的业务服务都可以向Redis发送写入命令,且只有一个业务服务可以写入命令成功,那么这个写入命令成功的服务即获得了锁,可以进行后续对资源的操作,其他未写入成功的服务,则进行阻塞处理。

String类型实现

使用setnx(SET if Not Exists)指令实现,即如果 key 不存在,才会设置它的值,否则什么也不做。

假设有两个客户端同时竞争锁,即向Redis写入lock_key,A客户端写入成功则A先获取到锁,客户端B写入失败则B未获取到锁。A客户端在使用完资源后,将redis中lock_key删除,即释放锁。

# A执行写入
> setnx lock_key true
(integer) 1
# A获得锁,执行A的业务
> del lock_key
(integer) 1
# B执行写入
> setnx lock_key true
(integer) 0
# B未获取锁,阻塞

但这样是存在一些问题的,试想如果A客户端在获取锁后,出现了故障,导致del语句没有调用,这样lock_key就一直得不到释放,即该资源锁一直存在,那么其他服务也就永远得不到该资源了。那么如何避免呢?

避免死锁

在Redis写入数据时,可以设置数据过期时间,这样即便在服务故障,锁也能自动释放。

> setnx lock_key true
(integer) 1
> expire lock_key 5
(integer) 1
#  执行业务
> del lock_key
(integer) 1

通过expire指令实现锁过期时间害存在一些问题,试想如果expire出错,没有成功执行,那么也将会造成前面的死锁情况。

因为 setnx 和 expire 是两条指令而不是原子指令,在Redis2.8版本中,可以通过set key velue ex timeout nx来实现setnx和expire两条指令。

> set lock_key true ex 5 nx
OK
#  执行业务
> del lock_key
(integer) 1

虽然解决了死锁,但这样又引入了新问题,试想A的业务执行过长,超过了锁的过期时间,A锁已经被释放,但此时B重新又获得了锁,A执行完后释放锁,可能就释放了B刚获取到的锁。这就出现了锁过期,释放其他服务锁的问题

避免锁超时问题

每个服务在设置value的时候,带上自己服务的唯一标识,如UUID,或者一些业务上的独特标识。这样在删除key的时候,只删除自己服务之前添加的key就可以了。

但匹配value和删除key是两条指令,不是原子操作,且redis中没有提供set这样的扩展参数,没法直接通过指令实现原子操作。

这里就需要使用Lua脚本处理,Lua脚本可以保证连续多个指令的原子性执行,将这两个操作合并成一个操作,就可以保证其原子性了。

# delifequals
if redis.call("get",KEYS[1]) == ARGV[1] then
    return redis.call("del",KEYS[1])
else
    return 0
end
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鳄鱼儿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值