前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Redis系列(二):Redis的分布式锁解析及应用

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

作者头像
鳄鱼儿
发布2024-05-21 17:09:29
1470
发布2024-05-21 17:09:29
举报

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

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

Redis实现分布式锁

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

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

String类型实现

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

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

代码语言:javascript
复制
# A执行写入
> setnx lock_key true
(integer) 1
# A获得锁,执行A的业务
> del lock_key
(integer) 1
代码语言:javascript
复制
# B执行写入
> setnx lock_key true
(integer) 0
# B未获取锁,阻塞

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

避免死锁

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

代码语言:javascript
复制
> 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两条指令。

代码语言:javascript
复制
> 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脚本可以保证连续多个指令的原子性执行,将这两个操作合并成一个操作,就可以保证其原子性了。

代码语言:javascript
复制
# delifequals
if redis.call("get",KEYS[1]) == ARGV[1] then
    return redis.call("del",KEYS[1])
else
    return 0
end
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-05-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Redis实现分布式锁
    • String类型实现
      • 避免死锁
        • 避免锁超时问题
        相关产品与服务
        云数据库 Redis
        腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档