MENU

Redis分布式锁(一)

面试题

Redis除了拿来做缓存,你还见过基于Redis的什么用法?
数据共享,分布式Session
分布式锁
全局ID
计算器、点赞位统计
购物车
轻量级消息队列---list、stream
抽奖
点赞、签到、打卡
差集交集并集,用户关注、可能认识的人,推荐模型
热点新闻、热搜排行榜
Redis 做分布式锁的时候有需要注意的问题?
你们公司自己实现的分布式锁是否用的setnx命令实现(大厂一定不可以)?这个是最合适的吗?你如何考虑分布式锁的可重入问题?
如果是Redis是单点部署的,会带来什么问题?
Redis集群模式下,比如主从模式,CAP方面有没有什么问题呢?
那你简单的介绍一下Redlock吧?你简历上写redisson,你谈谈
Redis分布式锁如何续期?看门狗知道吗?

锁的种类

单机版同一个JVM虚拟机内,synchronized或者Lock接口
分布式多个不同JⅣM虚拟机,单机的线程锁机制不再起作用,资源类在不同的服务器之间共享了。

一个靠谱分布式锁需要具备的条件和刚需

独占性----OnlyOne,任何时刻只能有且仅有一个线程持有

高可用----若redis集群环境下,不能因为某一个节点挂了而出现获取锁和释放锁失败的情况----高并发请求下,依l旧性能OK好使

防死锁----杜绝死锁,必须有超时控制机制或者撤销操作,有个兜底终止跳出方案

不乱抢----防止张冠李戴,不能私下unlock别人的锁,只能自己加锁自己释放,自己约的锁含着泪也要自己解

重入性----同一个节点的同一个线程如果获得锁之后,它也可以再次获取这个锁。

分布式锁

image-20230617222825683

setnx key value

image-20230614002438221

set key value [EX seconds] [Px milliseconds] [NX|XX]

image-20230614002542889

JUC中A锁的规范落地参考+可重入锁考虑+Lua脚本+Redis命令一步步实现分布式锁

Lua脚本

Lua是—种轻量小巧的脚本语言用标准C语言编写并以源代码形式开放,其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。
Lua是巴西里约热内卢天主教大学(Pontifical Catholic University of Rio de Janeiro)里的一个研究小组于1993年开发的,该小组成员有:Roberto lerusalimschy、waldemar Celes和Luiz Henrique de Figueiredo。
设计目的:其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。
Lua特性
轻量级:它用标准C语言编写并以源代码形式开放,编译后仅仅一百余K,可以很方便的嵌入别的程序里。
可扩展: Lua提供了非常易于使用的扩展接口和机制:由宿主语言(通常是C或C++)提供这些功能,Lua可以使用它们,就像是本来就内置的功能一样。

Redis调用Lua脚本通过eval命令保证代码执行的原子性,直接用return返回脚本执行后的结果值

入门级:reids中
eval luascript numkeys [key [key ...]] [arg [arg ...]]
EVAL "return 'hello lua'" 0
-----------------------------------------------------------
set k1 v1
expire k1 30
get k1
EVAL "redis.call('set','k1','v1') redis.call('expire','k1','30') return redis.call('get','k1')" 0
-----------------------------------------------------------
mset k1 v1 k2 v2
EVAL "redis.call('mset','k1','v1','k2','v2')" 0
//动态的 上面案例 后面的0代表 没有传任何参数  
EVAL "redis.call('mset',KEYS[1],ARGV[1],KEYS[2],ARGV[2])" 2 k1 k2 v1 v2
升级 这个没用到redis中
条件判断:if(布尔条件) then
            业务代码
        elseif(布尔条件) then
            业务代码
else
    业务代码
end
------------------------------------------------------------
EVAL "if KEYS[2]>KEYS[2] then return ARGV[1] elseif KEYS[1]<KEYS[2] then return ARGV[2] else ARGV[3] end" 2 5 7 1 2 3
// if(5>7){
return 1
}else if(5<7){
return 2  
}else{
return 3
}
//结果"2"

image-20230616011508877