返回顶部
首页 > 资讯 > 数据库 >Redis中怎样实现一个分布式锁
  • 395
分享到

Redis中怎样实现一个分布式锁

2024-04-02 19:04:59 395人浏览 薄情痞子
摘要

这期内容当中小编将会给大家带来有关Redis中怎样实现一个分布式锁,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。方案使用 SETNX 和 EXPIRE 命令SETNX&n

这期内容当中小编将会给大家带来有关Redis中怎样实现一个分布式,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。

方案

使用 SETNX 和 EXPIRE 命令

SETNX key value  EXPIRE key seconds  DEL key  if (setnx("item_1_lock", 1)) {      expire("item_1_lock", 30);      try {          ... 逻辑      } catch {          ...      } finally {          del("item_1_lock");      }  }

这种方法看起来可以解决问题,但是有一定的风险,因为 SETNX 和 EXPIRE 这波操作是非原子性的,如果 SETNX 成功之后,出现错误,导致 EXPIRE 没有执行,导致锁没有设置超时时间形成死锁。

Redis中怎样实现一个分布式锁

针对这种情况,我们可以使用 lua 脚本来保持操作原子性,保证 SETNX 和 EXPIRE 两个操作要么都成功,要么都不成功。

if (redis.call('setnx', KEYS[1], ARGV[1]) < 1)  then return 0;  end;  redis.call('expire', KEYS[1], tonumber(ARGV[2]));  return 1;

通过这样的方法,我们初步解决了竞争锁的原子性问题,虽然其他功能还未实现,但是应该不会造成死锁???。

Redis 2.6.12 以上可灵活使用 SET 命令

SET key value NX EX 30  DEL key  if (set("item_1_lock", 1, "NX", "EX", 30)) {      try {          ... 逻辑      } catch {          ...      } finally {          del("item_1_lock");      }  }

改进后的方法不需要借助 lua 脚本就解决了 SETNX 和 EXPIRE 的原子性问题。现在我们再仔细琢磨琢磨,如果 A 拿到了锁顺利进入代码块执行逻辑,但是由于各种原因导致超时自动释放锁。在这之后 B 成功拿到了锁进入代码块执行逻辑,但此时如果 A 执行逻辑完毕再来释放锁,就会把 B 刚获得的锁释放了。就好比用自己家的钥匙开了别家的门,这是不可接受的。

Redis中怎样实现一个分布式锁

为了解决这个问题我们可以尝试在 SET 的时候设置一个锁标识,然后在 DEL 的时候验证当前锁是否为自己的锁。

String value = UUID.randomUUID().toString().replaceAll("-", "");  if (set("item_1_lock", value, "NX", "EX", 30)) {      try {          ... 逻辑      } catch {          ...      } finally {          ... lua 脚本保证原子性      }  }  if (redis.call('get', KEYS[1]) == ARGV[1])  then return redis.call('del', KEYS[1])  else return 0  end

到这里,我们终于解决了竞争锁的原子性问题和误删锁问题。但是锁一般还需要支持可重入、循环等待和超时自动续约等功能点。下面我们学习使用一个非常好用的包来解决这些问题。

入门 Redisson

Redission 的锁,实现了可重入和超时自动续约功能,它都帮我们封装好了,我们只要按照自己的需求调用它的 api 就可以轻松实现上面所提到的几个功能点。详细功能可以查看 Redisson 文档

在项目中安装 Redisson

<dependency>      <groupId>org.redisson</groupId>      <artifactId>redisson</artifactId>      <version>3.13.2</version>  </dependency>
implementation 'org.redisson:redisson:3.13.2'

Maven 或者 Gradle 构建,目前最新版本为 3.13.2,也可以在这里 Redisson 找到你需要的版本。

简单尝试

RedissonClient redissonClient = Redisson.create();  RLock lock = redissonClient.getLock("lock");  boolean res = lock.lock();  if (res) {     try {       ... 逻辑     } finally {         lock.unlock();     }  }

Redisson 将底层逻辑全部做了一个封装 ?,我们无需关心具体实现,几行代码就能使用一把完美的锁。下面我们简单折腾折腾源码 ???。

加锁

private void lock(long leaseTime, TimeUnit unit, boolean interruptibly) throws InterruptedException {      long threadId = Thread.currentThread().getId();      Long ttl = tryAcquire(leaseTime, unit, threadId);      if (ttl == null) {          return;      }      RFuture<RedissonLockEntry> future = subscribe(threadId);      if (interruptibly) {          commandExecutor.syncSubscriptionInterrupted(future);      } else {          commandExecutor.syncSubscription(future);      }      try {          while (true) {              ttl = tryAcquire(leaseTime, unit, threadId);              if (ttl == null) {                  break;              }              if (ttl >= 0) {                  try {                      future.getNow().getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);                  } catch (InterruptedException e) {                      if (interruptibly) {                          throw e;                      }                      future.getNow().getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);                  }              } else {                  if (interruptibly) {                      future.getNow().getLatch().acquire();                  } else {                      future.getNow().getLatch().acquireUninterruptibly();                  }              }         }      } finally {          unsubscribe(future, threadId);      }  }

Redis中怎样实现一个分布式锁

获取锁

private <T> RFuture<Long> tryAcquireAsync(long leaseTime, TimeUnit unit, long threadId) {      if (leaseTime != -1) {          return tryLockInnerAsync(leaseTime, unit, threadId, RedisCommands.EVAL_LONG);      }      RFuture<Long> ttlRemainingFuture = tryLockInnerAsync(commandExecutor.getConnectionManager().getCfg().getLockWatchdogTimeout(), TimeUnit.MILLISECONDS, threadId, RedisCommands.EVAL_LONG);      ttlRemainingFuture.onComplete((ttlRemaining, e) -> {          if (e != null) {              return;          }          if (ttlRemaining == null) {              scheduleExpirationRenewal(threadId);          }      });      return ttlRemainingFuture;  }  <T> RFuture<T> tryLockInnerAsync(long leaseTime, TimeUnit unit, long threadId, RedisStrictCommand<T> command) {      internalLockLeaseTime = unit.toMillis(leaseTime);      return evalWriteAsync(getName(), LonGCodec.INSTANCE, command,              "if (redis.call('exists', KEYS[1]) == 0) then " +                      "redis.call('hincrby', KEYS[1], ARGV[2], 1); " +                      "redis.call('pexpire', KEYS[1], ARGV[1]); " +                      "return nil; " +                      "end; " +                      "if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then " +                      "redis.call('hincrby', KEYS[1], ARGV[2], 1); " +                      "redis.call('pexpire', KEYS[1], ARGV[1]); " +                      "return nil; " +                      "end; " +                      "return redis.call('pttl', KEYS[1]);",              Collections.singletonList(getName()), internalLockLeaseTime, getLockName(threadId));  }

Redis中怎样实现一个分布式锁

删除锁

public RFuture<Void> unlockAsync(long threadId) {      RPromise<Void> result = new RedissonPromise<Void>();      RFuture<Boolean> future = unlockInnerAsync(threadId);      future.onComplete((opStatus, e) -> {          cancelExpirationRenewal(threadId);          if (e != null) {              result.tryFailure(e);              return;          }          if (opStatus == null) {              IllegalMonitorStateException cause = new IllegalMonitorStateException("attempt to unlock lock, not locked by current thread by node id: "                      + id + " thread-id: " + threadId);              result.tryFailure(cause);              return;          }          result.trySuccess(null);      });      return result;  }  protected RFuture<Boolean> unlockInnerAsync(long threadId) {      return evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,              "if (redis.call('hexists', KEYS[1], ARGV[3]) == 0) then " +                      "return nil;" +                      "end; " +                      "local counter = redis.call('hincrby', KEYS[1], ARGV[3], -1); " +                      "if (counter > 0) then " +                      "redis.call('pexpire', KEYS[1], ARGV[2]); " +                      "return 0; " +                      "else " +                      "redis.call('del', KEYS[1]); " +                      "redis.call('publish', KEYS[2], ARGV[1]); " +                      "return 1; " +                      "end; " +                      "return nil;",              Arrays.asList(getName(), getChannelName()), LockPubSub.UNLOCK_MESSAGE, internalLockLeaseTime, getLockName(threadId));  }

上述就是小编为大家分享的Redis中怎样实现一个分布式锁了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注编程网数据库频道。

您可能感兴趣的文档:

--结束END--

本文标题: Redis中怎样实现一个分布式锁

本文链接: https://lsjlt.com/news/57836.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Redis中怎样实现一个分布式锁
    这期内容当中小编将会给大家带来有关Redis中怎样实现一个分布式锁,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。方案使用 SETNX 和 EXPIRE 命令SETNX&n...
    99+
    2024-04-02
  • Redis怎么样实现分布式锁
    这篇文章主要介绍了Redis怎么样实现分布式锁,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。在一个分布式系统中,会遇到一些需要对多个节点共享的资源加锁的情况,这个时候需要用到...
    99+
    2023-06-21
  • Redis中怎么实现分布式锁
    本篇内容介绍了“Redis中怎么实现分布式锁”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!为什么需要分布式...
    99+
    2024-04-02
  • Redis——》实现分布式锁
    推荐链接:     总结——》【Java】     总结——》【Mysql】     总结——》【Redis】     总结——》【Kafka】     总结——》【Spring】     总结—...
    99+
    2023-09-03
    redis 分布式 过期 lua
  • Redis实现分布式锁
    单体锁存在的问题 在单体应用中,如果我们对共享数据不进行加锁操作,多线程操作共享数据时会出现数据一致性问题。 (下述实例是一个简单的下单问题:从redis中获取库存,检查库存是否够,>0才允许下单) 我们的解决办法通常是加锁。如下加单体锁...
    99+
    2023-08-16
    分布式 java jvm
  • Redis分布式锁怎么实现
    这篇文章给大家分享的是有关Redis分布式锁怎么实现的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。分布式锁一般有三种实现方式:1、数据库乐观锁;2、基于Redis的分布式锁;3、...
    99+
    2024-04-02
  • Redis怎么实现分布式锁
    这篇文章主要介绍“Redis怎么实现分布式锁”,在日常操作中,相信很多人在Redis怎么实现分布式锁问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Redis怎么实现分布式锁”的疑惑有所帮助!接下来,请跟着小编...
    99+
    2023-06-02
  • Redisson中怎么实现Redis分布式锁
    Redisson中怎么实现Redis分布式锁,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。Redis几种架构Redis发展到现在,几种常见的部署架构有:单机模式;主从模式;...
    99+
    2023-06-20
  • 分布式锁的原理及Redis怎么实现分布式锁
    这篇文章主要介绍“分布式锁的原理及Redis怎么实现分布式锁”,在日常操作中,相信很多人在分布式锁的原理及Redis怎么实现分布式锁问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解...
    99+
    2023-02-02
    redis
  • redis分布式锁的实现
    一、使用分布式锁要满足的几个条件:1、系统是一个分布式系统(关键是分布式,单机的可以使用ReentrantLock或者synchronized代码块来实现)2、共享资源(各个系统访问同一个资源,资源的载体可...
    99+
    2024-04-02
  • Redis Template实现分布式锁
    今天就跟大家聊聊有关Redis Template实现分布式锁,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。可靠性首先,为了确保分布式锁可用,我们至少...
    99+
    2024-04-02
  • PHP+Redis实现分布式锁
    目录 一、分布式锁概述 二、redis实现锁的命令 1、redis实现锁的命令 3、释放锁的步骤 三、PHP+redis分布式锁示例 四、redis集群分布式锁 一、分布式锁概述         在分布式环境下,各个线程通过对公共资...
    99+
    2023-09-15
    分布式锁
  • Redis实现分布式锁(SETNX)
    目录 1、什么是分布式锁 2、分布式锁应具备的条件         3、为什么使用分布式锁 4、SETNX介绍 5、分布式锁实现 6、效果演示 7、Redisson分布式锁详解 8、Lua脚本实现可重入分布式锁 1、什么是分布式锁  ...
    99+
    2023-10-21
    redis 分布式 java spring boot 后端
  • python实现redis分布式锁
    #!/usr/bin/env python # coding=utf-8 import time import redis class RedisLock(object): def __init__(self, key): ...
    99+
    2023-01-31
    分布式 python redis
  • Redis中如何实现分布式锁
    这篇文章给大家介绍Redis中如何实现分布式锁,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。Redis要实现分布式锁,以下条件应该得到满足互斥性 在任意时刻,只有一个客户端能持有锁。不能死锁 客户端...
    99+
    2023-06-16
  • 怎么用Redis实现分布式锁
    本文小编为大家详细介绍“怎么用Redis实现分布式锁”,内容详细,步骤清晰,细节处理妥当,希望这篇“怎么用Redis实现分布式锁”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。单机...
    99+
    2024-04-02
  • spring redis分布式锁怎么实现
    在Spring中实现Redis分布式锁可以使用RedisTemplate来操作Redis进行加锁和解锁。 首先,我们需要定义一个分布...
    99+
    2023-10-27
    spring redis
  • redis和zookeeper中怎么实现分布式锁
    redis和zookeeper中怎么实现分布式锁,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。   一、基于redis的分布...
    99+
    2024-04-02
  • Redis分布式锁的实现方式
    目录一、分布式锁是什么1、获取锁2、释放锁二、代码实例上面代码存在锁误删问题:三、基于SETNX实现的分布式锁存在下面几个问题1、不可重入2、不可重试3、超时释放4、主从一致性四、Redisson实现分布式锁1、pom2...
    99+
    2023-04-03
    Java Redis分布式锁实现方式 实现Redis分布式锁 Redis分布式锁实现
  • redis中分布式锁的实现方法
    小编给大家分享一下redis中分布式锁的实现方法,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!redis分布式锁:1、实现原理利...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作