redispexpire的简单介绍
本篇文章给大家谈谈redispexpire,以及对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。
本文目录一览:
使用redis实现的分布式锁原理是什么?
一、写在前面
现在面试,一般都会聊聊分布式系统这块的东西。通常面试官都会从服务框架(Spring Cloud、Dubbo)聊起,一路聊到分布式事务、分布式锁、ZooKeeper等知识。
所以咱们这篇文章就来聊聊分布式锁这块知识,具体的来看看Redis分布式锁的实现原理。
说实话,如果在公司里落地生产环境用分布式锁的时候,一定是会用开源类库的,比如Redis分布式锁,一般就是用Redisson框架就好了,非常的简便易用。
大家如果有兴趣,可以去看看Redisson的官网,看看如何在项目中引入Redisson的依赖,然后基于Redis实现分布式锁的加锁与释放锁。
下面给大家看一段简单的使用代码片段,先直观的感受一下:
怎么样,上面那段代码,是不是感觉简单的不行!
此外,人家还支持redis单实例、redis哨兵、redis cluster、redis master-slave等各种部署架构,都可以给你完美实现。
二、Redisson实现Redis分布式锁的底层原理
好的,接下来就通过一张手绘图,给大家说说Redisson这个开源框架对Redis分布式锁的实现原理。
(1)加锁机制
咱们来看上面那张图,现在某个客户端要加锁。如果该客户端面对的是一个redis cluster集群,他首先会根据hash节点选择一台机器。
这里注意,仅仅只是选择一台机器!这点很关键!
紧接着,就会发送一段lua脚本到redis上,那段lua脚本如下所示:
为啥要用lua脚本呢?
因为一大坨复杂的业务逻辑,可以通过封装在lua脚本中发送给redis,保证这段复杂业务逻辑执行的原子性。
那么,这段lua脚本是什么意思呢?
KEYS[1]代表的是你加锁的那个key,比如说:
RLock lock = redisson.getLock("myLock");
这里你自己设置了加锁的那个锁key就是“myLock”。
ARGV[1]代表的就是锁key的默认生存时间,默认30秒。
ARGV[2]代表的是加锁的客户端的ID,类似于下面这样:
8743c9c0-0795-4907-87fd-6c719a6b4586:1
给大家解释一下,第一段if判断语句,就是用“exists myLock”命令判断一下,如果你要加锁的那个锁key不存在的话,你就进行加锁。
如何加锁呢?很简单,用下面的命令:
hset myLock
8743c9c0-0795-4907-87fd-6c719a6b4586:1 1
通过这个命令设置一个hash数据结构,这行命令执行后,会出现一个类似下面的数据结构:
上述就代表“8743c9c0-0795-4907-87fd-6c719a6b4586:1”这个客户端对“myLock”这个锁key完成了加锁。
接着会执行“pexpire myLock 30000”命令,设置myLock这个锁key的生存时间是30秒。
好了,到此为止,ok,加锁完成了。
(2)锁互斥机制
那么在这个时候,如果客户端2来尝试加锁,执行了同样的一段lua脚本,会咋样呢?
很简单,第一个if判断会执行“exists myLock”,发现myLock这个锁key已经存在了。
接着第二个if判断,判断一下,myLock锁key的hash数据结构中,是否包含客户端2的ID,但是明显不是的,因为那里包含的是客户端1的ID。
所以,客户端2会获取到pttl myLock返回的一个数字,这个数字代表了myLock这个锁key的剩余生存时间。比如还剩15000毫秒的生存时间。
此时客户端2会进入一个while循环,不停的尝试加锁。
(3)watch dog自动延期机制
客户端1加锁的锁key默认生存时间才30秒,如果超过了30秒,客户端1还想一直持有这把锁,怎么办呢?
简单!只要客户端1一旦加锁成功,就会孝扰启动一个watch dog看门狗,他是一个后台线程,会每隔10秒检查一下,如果客户端1还持有锁key,那么就会不断的延长锁key的生存时间。
(4)可重入加锁悔慎茄机制
那如果客户端1都已经持有了这把锁了,结果可重入的加锁会怎么样呢?
比如下面这种代码:
这时我们来分析一下上面那段lua脚本。
第一个if判断肯定不成立,“exists myLock”会显示锁key已经存在了。
第二个if判断会成立,因为myLock的碧察hash数据结构中包含的那个ID,就是客户端1的那个ID,也就是“8743c9c0-0795-4907-87fd-6c719a6b4586:1”
此时就会执行可重入加锁的逻辑,他会用:
incrby myLock
8743c9c0-0795-4907-87fd-6c71a6b4586:1 1
通过这个命令,对客户端1的加锁次数,累加1。
此时myLock数据结构变为下面这样:
大家看到了吧,那个myLock的hash数据结构中的那个客户端ID,就对应着加锁的次数
(5)释放锁机制
如果执行lock.unlock(),就可以释放分布式锁,此时的业务逻辑也是非常简单的。
其实说白了,就是每次都对myLock数据结构中的那个加锁次数减1。
如果发现加锁次数是0了,说明这个客户端已经不再持有锁了,此时就会用:
“del myLock”命令,从redis里删除这个key。
然后呢,另外的客户端2就可以尝试完成加锁了。
这就是所谓的分布式锁的开源Redisson框架的实现机制。
一般我们在生产系统中,可以用Redisson框架提供的这个类库来基于redis进行分布式锁的加锁与释放锁。
(6)上述Redis分布式锁的缺点
其实上面那种方案最大的问题,就是如果你对某个redis master实例,写入了myLock这种锁key的value,此时会异步复制给对应的master slave实例。
但是这个过程中一旦发生redis master宕机,主备切换,redis slave变为了redis master。
接着就会导致,客户端2来尝试加锁的时候,在新的redis master上完成了加锁,而客户端1也以为自己成功加了锁。
此时就会导致多个客户端对一个分布式锁完成了加锁。
这时系统在业务语义上一定会出现问题,导致各种脏数据的产生。
所以这个就是redis cluster,或者是redis master-slave架构的主从异步复制导致的redis分布式锁的最大缺陷:在redis master实例宕机的时候,可能导致多个客户端同时完成加锁。
[img]Redis 4种设置过期时间方式
Redis PEXPIRE 命令和 EXPIRE 命令的作用类似,但是它以毫秒为单位设置 key 的生存时间,而不像 EXPIRE 命令那样,以秒为单位。
1、2两种方式是设置一个过期的时间段,就是咱们处理验证码最常用的策略,设置三分钟陆皮高或五分钟后握敏失效,把分钟数转换成秒或毫秒存储到Redis中。
3、4两种方式是指定一个过期的时间 ,比如优惠券的过期时间是某早尺年某月某日,只是单位不一样。
Redis官方教程 Expire超时
EXPIRE key second
设置超时 key 。超时过期后,key将自动删除。在Redis术语中,通常认为具有超时的key是 不稳定的 。
只有删除或覆盖key内容的命令才能清除超时,包括 DEL , SET , GETSET 和所有 *STORE 命令。这意味着 改变 存储在key中的值而不用新key替换它的所有操作将使超时保持不变。举例来说,增加一键的值 INCR ,往列表推新值的,包括 LPUSH ,或改变了哈希的字段值 HSET ,都不会改变超时。
也可以清除超时,使用 PERSIST 命令将key重新转换为持久key。
如果使用 RENAME 重命名好粗key,则相关的生存时间将转移到新key名称。
如果一个key被 RENAME 覆盖,比如,已经存在key Key_A ,被如下命令所覆盖, RENAME Key_B Key_A ,新key Key_A 将继承所有的 Key_B 的属性,与原始 Key_A 否有超时没有关系。
请注意,使用非正数的超时时间调用 EXPIRE / PEXPIRE 或 使用一个过去时间调用 EXPIREAT / PEXPIREAT ,将导致键被 删除 而不是过期(因此,发出的 键事件 将是 del ,而不是 expired )。
可以使用已经设置超时的key作为参数调用 EXPIRE 。在这种情况下,key的生存时间将 更新 为新迅袜丛值。有许多有用的应用程序,下面的 导航会话 模式部分中记录了一个示例 。
在之前的Redis 2.1.3版本中 ,使用命令更改key来使用超时设置更改key,具有完全删除key的效果。由于复制层中的限制现在已得到修复,因此需要使用此语义。
EXPIRE 将返回0并且不会更改具有超时设置的key的超时。
整数回复 ,具体为:
假如你有一个web服务,你需要记录用户最近浏览的N个页面,每个相邻页面的浏览时间不超过60s。
你可以用redis轻松实现,每次用户打开一个页面,执行如下命令:
如果用户60s没有操作,页面就会被删除,只有60s以内的页面会被记录。
通常,创建Redis key时没有相关的过期时间。key只会永远存在,除非用户以明确的方式将其 删除 ,例如使用 DEL 命令。
EXPIRE 家族命令能够给key设置超时时间,但是会使用一些额外的内存成本。当key设置了过期时,Redis将确保在指定的时间过后删除key。
可以使用 EXPIRE 和 PERSIST 命令(或其他严格相关的命令)更新或完全删除key生存时间。
在Redis 2.4中,到期可能不精确,误差可能在0到1秒之间。
从Redis 2.6开始,到期误差从0到1毫秒。
Key到期信息存储为绝对Unix时间戳(在Redis 2.6或更高版本的情况下以毫秒为单位)。这意味着即使Redis实例未处于活动状态,时间也在流动。
为了使到期效果良好,计算机时间必须稳定。如果您从两台计时器中移动RDB文件并在其时钟中使用大型desync,则可能会发生有趣的事情(例如加载时加载的所有键都将在加载时过期)。
即使运行实例也会检查计算机时钟,例如,如果您设置的key的生存时间为1000秒,然后将计算机时间设置为当前时间向后2000秒,key将立即过期,而不是持续1000秒。
Redis key以两种方式过期:被动方式和主动方式。
当某个客户端尝试访问key时,如果发现key超时,key被动过期。
当然这还不够,因为有过期的key永远不会被再次访问。这些key无论如何都应该过期,所以周期性地Redis会在具有过期设置的key中随机测试几个key。已经过期的所有key都将从key空间中删除。
具体来说,这就是Redis每秒做10次的事情:
这是一个简单的概率算法,基本上假设我们的样本代表整个key空间,我们继续到期,直到可能过期的key百分比低于25%
这意味着在任何给定时刻,使用内存的已经过期的最大key数量亩樱最大等于每秒最大写入操作量除以4。
为了在不牺牲一致性的情况下获得正确的行为,当key到期时,在AOF文件中合成 DEL 操作并通知所有副本节点。这样,到期过程集中在主实例中,并且不存在一致性错误。
但是,连接到主服务器的副本节点不会单独地使key过期,(但会等待来自主服务器的 DEL ),但它们仍将采用数据集中存在的过期的完整状态,因此当副本被选为主服务器时它将能够独立地使密钥到期,充分充当主人。
关于redispexpire和的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。