redis分布式锁(原理,实现以及测试)

本文介绍了Redis分布式锁的工作原理,包括使用setnx、getset、expire和del命令实现锁的加锁和解锁过程。文章强调了分布式锁的互斥性、防死锁、持锁人解锁和可重入性等关键要点,并提供了加锁和解锁的详细步骤。通过Lua脚本来保证解锁的原子性。最后,作者分享了基于Redis的秒杀测试的代码实现和测试结果,期待读者提供反馈和指正。
摘要由CSDN通过智能技术生成

redis分布式锁原理

分布式锁,是控制分布式系统之间同步访问共享资源的一种方式。在分布式系统中,常常需要协调他们的动作。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥来防止彼此干扰来保证一致性,在这种情况下,便需要使用到分布式锁。

使用setnx、getset、expire、del这4个redis命令实现

  1. setnx 是『SET if Not eXists』(如果不存在,则 SET)的简写。 命令格式:SETNX key value;使用:只在键 key 不存在的情况下,将键 key 的值设置为 value 。若键 key 已经存在, 则 SETNX 命令不做任何动作。返回值:命令在设置成功时返回 1 ,设置失败时返回 0 。
  2. etset 命令格式:GETSET key value,将键 key 的值设为 value ,并返回键 key 在被设置之前的旧的value。返回值:如果键 key 没有旧值, 也即是说, 键 key 在被设置之前并不存在, 那么命令返回 nil 。当键 key 存在但不是字符串类型时,命令返回一个错误。
  3. expire 命令格式:EXPIRE key seconds,使用:为给定 key 设置生存时间,当 key 过期时(生存时间为 0 ),它会被自动删除。返回值:设置成功返回 1 。 当 key 不存在或者不能为 key 设置生存时间时(比如在低于 2.1.3 版本的 Redis 中你尝试更新 key 的生存时间),返回 0 。
  4. del 命令格式:DEL key [key …],使用:删除给定的一个或多个 key ,不存在的 key 会被忽略。返回值:被删除 key 的数量。

原理图如下所示:
在这里插入图片描述

Redis分布式锁要注意的地方

  1. 互斥性:在任意时间都只能有一个客户端可以获取锁
  2. 防死锁:加入一个客户端在持有锁的时候崩溃了,没有释放锁,那么别的客户端无法获得锁,就会造成死锁,所以一定要保证客户端一定要释放锁。
  3. 持锁人解锁;加锁和解锁必须是同一个客户端,客户端不能解开别的客户端的锁
  4. 可重入:当一个客户端获取锁对象之后,这个客户端可以再次获取这个对象上的锁。

加锁和解锁

加锁:

  • 1)setnx命令加锁
    set if not exists 我们会用到Redis的命令setnx,setnx的含义就是只有锁不存在的 情况下才会设置成功。
  • 2)设置锁的有效时间,防止死锁 expire
    不过为了保证原子性,这里使用
    set(key, id, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime)

END_TIME代表获取锁的时间,若是时间到了就放弃获取锁。
SET IF NOT EXIST,即当key不存在时,我们进行set操作;若key已经存在,则不做任何操作
SET_WITH_EXPIRE_TIME,给这个key加一个过期的设置,具体时间由第五个参数决定
LOCK_SUCCESS和RELESE_SUCCESS分别和jedis.set的返回值和jedis.eval的返回值进行比较

解锁:

1)检查是否自己持有锁(判断唯一标识);
2)删除锁。
解锁也是两步,同样也要保证解锁的原子性,把两步合为一步。
这就无法借助于Redis了,只能依靠Lua脚本来实现。

if Redis.call("get",key==argv[1])then
	    return Redis.call("del",key)
	else return 0 end

这就是一段判断是否自己持有锁并释放锁的Lua脚本
为什么Lua脚本是原子性呢?因为Lua脚本是jedis用eval()函数执行的,如果执行则会全部执行完成。

代码实现:

其中RedisPool是自己封装的连接池,具体实现在上一篇博客
RedisPool连接池实现

/**
 * redis分布式锁
 * @author by zzj
 * @date 2019/11/28.
 */


public class JedisDistributeLock {
   
    private static final int END_TIME = 1000;
    private static final String SET_IF_NOT_EXIST = "NX";
    private static final String SET_WITH_EXPIRE_TIME = "PX";
  
  • 1
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
回答: Redis分布式锁适用于多个应用实例之间需要协调互斥访问同一个资源的场景。它可以帮助我们控制分布式系统中对共享资源的访问,避免并发问题和重复操作。常见的使用场景包括: 1. 分布式任务调度:多个应用实例需要定时执行某个任务,通过使用分布式锁可以确保只有一个实例执行任务,避免重复执行。 2. 分布式缓存更新:多个应用实例需要同时更新某个缓存数据,通过使用分布式锁可以保证只有一个实例进行更新,避免数据不一致。 3. 分布式资源竞争:多个应用实例需要竞争某个资源,例如分布式锁可以用于实现分布式限流、分布式排他性操作等场景。 需要注意的是,分布式锁实现需要考虑到高并发、死、误删等问题,需要根据具体的应用场景进行优化和测试。\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* *3* [Redis 分布式锁实现原理和应用场景](https://blog.csdn.net/weixin_43025343/article/details/131081958)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Redis实现分布式锁及其应用场景](https://blog.csdn.net/Crime11/article/details/130132324)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值