iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >Redis分布式锁怎么实现及应用场景是什么
  • 159
分享到

Redis分布式锁怎么实现及应用场景是什么

2023-06-29 10:06:09 159人浏览 八月长安
摘要

本篇内容介绍了“Redis分布式锁怎么实现及应用场景是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!引言锁是开发过程中十分常见的工具,你

本篇内容介绍了“Redis分布式怎么实现及应用场景是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

    引言

    锁是开发过程中十分常见的工具,你一定不陌生,悲观锁,乐观锁,排它锁,公平锁,非公平锁等等,很多概念,如果你对java里的锁还不了解,可以参考这一篇:不可不说的Java“锁”事,这一篇写的很全面了,但是对于初学者,知道这些锁的概念,由于缺乏实际工作经验,可能并不了解锁的实际使用场景,Java中可以通过Volatile、Synchronized、ReentrantLock 三个关键字来实现线程安全,这部分知识在第一轮基础面试里一定会问(要熟练掌握哦)。

    分布式系统中Java这些锁技术是无法同时锁住两台机器上的代码,所以要通过分布式锁来实现,熟练使用分布式锁也是大厂开发必会的技能。

    1、面试官:

    你有遇到需要使用分布式锁的场景吗?

    问题分析:这个问题主要作为引子,先要了解什么场景下需要使用分布式锁,分布式锁要解决什么问题,在此前提下有助于你更好的理解分布式锁的实现原理。

    使用分布式锁的场景一般需要满足以下场景:

    • 系统是一个分布式系统,java的锁已经锁不住了。

    • 操作共享资源,比如库里唯一的用户数据。

    • 同步访问,即多个进程同时操作共享资源。

    答:说一个我在项目中使用分布式锁场景的例子:

    消费积分在很多系统里都有,信用卡,电商网站,通过积分换礼品等,这里“消费积分”这个操作是需要使用锁的典型场景。

    事件A:

     以积分兑换礼品为例来讲,完整的积分消费过程简单分成3步:

    A1:用户选中商品,发起兑换提交订单。

    A2:系统读取用户剩余积分:判断用户当前积分是否充足。

    A3:扣掉用户积分。

    事件B: 

    系统给用户发放积分也简单分成3步:

    B1:计算用户当天应得积分

    B2:读取用户原有积分

    B3:在原有积分上增加本次应得积分

    那么问题来了,如果用户消费积分和用户累加积分同时发生(同时用户积分进行操作)会怎样?

    假设:用户在消费积分的同时恰好离线任务在计算积分给用户发放积分(如根据用户当天的消费额),这两件事同时进行,下面的逻辑有点绕,耐心理解。

    用户U有1000积分(记录用户积分的数据可以理解为共享资源),本次兑换要消耗掉999积分。

    不加锁的情况:事件A程序在执行到第2步读积分时,A:2操作读到的结果是1000分,判断剩余积分够本次兑换,紧接着要执行第3步A:3操作扣积分(1000 - 999 = 1),正常结果应该是用户还是1分。但是这个时候事件B也在执行,本次要给用户U发放100积分,两个线程同时进行(同步访问),不加锁的情况,就会有下面这种可能,A:2 -> B:2 -> A:3 -> B:3 ,在A:3尚未完成前(扣积分,1000 - 999),用户U总积分被事件B的线程读取了,最后用户U的总积分变成了1100分,还白白兑换了一个999积分的礼物,这显然不符合预期结果。

    有人说怎么可能这么巧同时操作用户积分,cpu那么快,只要用户足够多,并发量足够大,墨菲定律迟早生效,出现上述bug只是时间问题,还有可能被黑产行业卡住这个bug疯狂薅羊毛,这个时候作为开发人员要解决这个隐患就必须了解锁的使用。

    (写代码是一项严谨的事儿!)

    Java本身提供了两种内置的锁的实现,一种是由JVM实现的synchronized 和 jdk 提供的 Lock,以及很多原子操作类都是线程安全的,当你的应用是单机或者说单进程应用时,可以使用这两种锁来实现锁。

    但是当下互联网公司的系统几乎都是分布式的,这个时候Java自带的 synchronized 或 Lock 已经无法满足分布式环境下锁的要求了,因为代码会部署在多台机器上,为了解决这个问题,分布式锁应运而生,分布式锁的特点是多进程,多个物理机器上无法共享内存,常见的解决办法是基于内存层的干涉,落地方案就是基于Redis的分布式锁 or ZooKeeper分布式锁。

    (我分析的不能更详细了,面试官再不满意?)

    2、面试官:

    Redis分布式锁实现方法

    问题分析:目前分布式锁的实现方式主要有两种,1.基于Redis Cluster模式。2.基于Zookeeper 集群模式。

    优先掌握这两种,应付面试基本没问题了。

    答:

    1、基于Redis的分布式锁

    方法一:使用setnx命令加锁

    public static void wrongGetLock1(Jedis jedis, String lockKey, String requestId, int expireTime) {// 第一步:加锁    Long result = jedis.setnx(lockKey, requestId);    if (result == 1) {        // 第二步:设置过期时间        jedis.expire(lockKey, expireTime);    }}

    代码解释:

    setnx命令,意思就是 set if not exist,如果lockKey不存在,把key存入Redis,保存成功后如果result返回1,表示设置成功,如果非1,表示失败,别的线程已经设置过了。

    expire(),设置过期时间,防止死锁,假设,如果一个锁set后,一直不删掉,那这个锁相当于一直存在,产生死锁。

    (讲到这里,我还要和面试官强调一个“但是”)

    思考,我上面的方法哪里与缺陷?继续给面试官解释…

    加锁总共分两步,第一步jedis.setnx,第二步jedis.expire设置过期时间,setnx与expire不是一个原子操作,如果程序执行完第一步后异常了,第二步jedis.expire(lockKey, expireTime)没有得到执行,相当于这个锁没有过期时间,有产生死锁的可能。正对这个问题如何改进?

    改进:

    public class RedisLockDemo {    private static final String SET_IF_NOT_EXIST = "NX";    private static final String SET_WITH_EXPIRE_TIME = "PX";        public static boolean getLock(Jedis jedis, String lockKey, String requestId, int expireTime) {// 两步合二为一,一行代码加锁并设置 + 过期时间。        if (1 == jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime)) {            return true;//加锁成功        }        return false;//加锁失败    }}

    代码解释:

    将加锁和设置过期时间合二为一,一行代码搞定,原子操作。

    (没等面试官开口追问,面试官很满意了)

    3、面试官: 那解锁操作呢?

    答:

    释放锁就是删除key

    使用del命令解锁

    public static void unLock(Jedis jedis, String lockKey, String requestId) {    // 第一步: 使用 requestId 判断加锁与解锁是不是同一个客户端    if (requestId.equals(jedis.get(lockKey))) {        // 第二步: 若在此时,这把锁突然不是这个客户端的,则会误解锁        jedis.del(lockKey);    }}

    代码解释: 通过 requestId 判断加锁与解锁是不是同一个客户端和 jedis.del(lockKey) 两步不是原子操作,理论上会出现在执行完第一步if判断操作后锁其实已经过期,并且被其它线程获取,这是时候在执行jedis.del(lockKey)操作,相当于把别人的锁释放了,这是不合理的。当然,这是非常极端的情况,如果unLock方法里第一步和第二步没有其它业务操作,把上面的代码扔到线上,可能也不会真的出现问题,原因第一是业务并发量不高,根本不会暴露这个缺陷,那么问题还不大。

    但是写代码是严谨的工作,能完美则必须完美。针对上述代码中的问题,提出改进。

    代码改进:

    public class RedisTool {    private static final Long RELEASE_SUCCESS = 1L;        public static boolean releaseDistributedLock(Jedis jedis, String lockKey, String requestId) {        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";        Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));        if (RELEASE_SUCCESS.equals(result)) {            return true;        }        return false;    }}

    代码解释:

    通过 jedis 客户端的 eval 方法和 script 脚本一行代码搞定,解决方法一中的原子问题。

    3、面试官:

    基于 ZooKeeper 的分布式锁实现原理

    答:还是积分消费与积分累加的例子:事件A和事件B同时需要进行对积分的修改操作,两台机器同时进行,正确的业务逻辑上让一台机器先执行完后另外一个机器再执行,要么事件A先执行,要么事件B先执行,这样才能保证不会出现A:2 -> B:2 -> A:3 -> B:3这种积分越花越多的情况(想到这种bug一旦上线,老板要生气了,我可能要哭了)。

    怎么办?使用 zookeeper 分布式锁。

    一个机器接收到了请求之后,先获取 zookeeper 上的一把分布式锁(zk会创建一个 znode),执行操作;然后另外一个机器也尝试去创建那个 znode,结果发现自己创建不了,因为被别人创建了,那只能等待,等第一个机器执行完了方可拿到锁。

    使用 ZooKeeper 的顺序节点特性,假如我们在/lock/目录下创建3个节点,ZK集群会按照发起创建的顺序来创建节点,节点分为/lock/0000000001、/lock/0000000002、/lock/0000000003,最后一位数是依次递增的,节点名由zk来完成。

    ZK中还有一种名为临时节点的节点,临时节点由某个客户端创建,当客户端与ZK集群断开连接,则该节点自动被删除。EPHEMERAL_SEQUENTIAL为临时顺序节点。

    根据ZK中节点是否存在,可以作为分布式锁的锁状态,以此来实现一个分布式锁,下面是分布式锁的基本逻辑:

    • 客户端调用create()方法创建名为“/dlm-locks/lockname/lock-”的临时顺序节点。

    • 客户端调用getChildren(“lockname”)方法来获取所有已经创建的子节点。

    • 客户端获取到所有子节点path之后,如果发现自己在步骤1中创建的节点是所有节点中序号最小的,就是看自己创建的序列号是否排第一,如果是第一,那么就认为这个客户端获得了锁,在它前面没有别的客户端拿到锁。

    • 如果创建的节点不是所有节点中需要最小的,那么则监视比自己创建节点的序列号小的最大的节点,进入等待。直到下次监视的子节点变更的时候,再进行子节点的获取,判断是否获取锁。

    释放锁的过程相对比较简单,就是删除自己创建的那个子节点即可,不过也仍需要考虑删除节点失败等异常情况。

    额外补充

    分布式锁还可以从数据库下手解决问题

    方法一:

    利用 Mysql 的锁表,创建一张表,设置一个 UNIQUE KEY 这个 KEY 就是要锁的 KEY,所以同一个 KEY 在Mysql表里只能插入一次了,这样对锁的竞争就交给了数据库,处理同一个 KEY 数据库保证了只有一个节点能插入成功,其他节点都会插入失败。

    这样 lock 和 unlock 的思路就很简单了,伪代码:

    def lock :    exec sql: insert into locked—table (xxx) values (xxx)    if result == true :        return true    else :        return falsedef unlock :    exec sql: delete from lockedOrder where order_id='order_id'

    方法二:

    使用流水号+时间戳做幂等操作,可以看作是一个不会释放的锁。

    “Redis分布式锁怎么实现及应用场景是什么”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

    --结束END--

    本文标题: Redis分布式锁怎么实现及应用场景是什么

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

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

    本篇文章演示代码以及资料文档资料下载

    下载Word文档到电脑,方便收藏和打印~

    下载Word文档
    猜你喜欢
    • Redis分布式锁怎么实现及应用场景是什么
      本篇内容介绍了“Redis分布式锁怎么实现及应用场景是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!引言锁是开发过程中十分常见的工具,你...
      99+
      2023-06-29
    • 分布式面试分布式锁实现及应用场景
      目录引言1、面试官:你有遇到需要使用分布式锁的场景吗?事件A:事件B: 2、面试官:Redis分布式锁实现方法1、基于Redis的分布式锁3、面试官: 那解锁操作...
      99+
      2024-04-02
    • 分布式锁的原理及Redis怎么实现分布式锁
      这篇文章主要介绍“分布式锁的原理及Redis怎么实现分布式锁”,在日常操作中,相信很多人在分布式锁的原理及Redis怎么实现分布式锁问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解...
      99+
      2023-02-02
      redis
    • 分布式锁redis实现方式是什么
      分布式锁的Redis实现方式有两种:基于SETNX命令和基于RedLock算法。1. 基于SETNX命令:使用Redis的SETNX...
      99+
      2023-09-12
      redis
    • 怎么用Redis实现分布式锁
      本文小编为大家详细介绍“怎么用Redis实现分布式锁”,内容详细,步骤清晰,细节处理妥当,希望这篇“怎么用Redis实现分布式锁”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。单机...
      99+
      2024-04-02
    • Redis分布式锁怎么应用
      这篇文章主要讲解了“Redis分布式锁怎么应用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Redis分布式锁怎么应用”吧!分布式锁在单进程应用中,当一段代码同一时间内只能由一个线程执行时,...
      99+
      2023-06-21
    • Redis怎么实现分布式锁
      这篇文章主要介绍“Redis怎么实现分布式锁”,在日常操作中,相信很多人在Redis怎么实现分布式锁问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Redis怎么实现分布式锁”的疑惑有所帮助!接下来,请跟着小编...
      99+
      2023-06-02
    • Redis分布式锁怎么实现
      这篇文章给大家分享的是有关Redis分布式锁怎么实现的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。分布式锁一般有三种实现方式:1、数据库乐观锁;2、基于Redis的分布式锁;3、...
      99+
      2024-04-02
    • MySQL锁机制及应用场景是什么
      本文小编为大家详细介绍“MySQL锁机制及应用场景是什么”,内容详细,步骤清晰,细节处理妥当,希望这篇“MySQL锁机制及应用场景是什么”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。锁的概述MySQL锁是操作My...
      99+
      2023-07-05
    • 怎么用Go+Redis实现分布式锁
      这篇文章主要介绍怎么用Go+Redis实现分布式锁,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!为什么需要分布式锁用户下单锁住 uid,防止重复下单。库存扣减锁住库存,防止超卖。余额扣减锁住账户,防止并发操作。分布式...
      99+
      2023-06-22
    • redis分布式锁的实现原理是什么
      这篇文章主要讲解了“redis分布式锁的实现原理是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“redis分布式锁的实现原理是什么”吧!借助于redis...
      99+
      2024-04-02
    • Redis实现分布式锁的方法是什么
      本篇内容介绍了“Redis实现分布式锁的方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!在一个分布...
      99+
      2024-04-02
    • Redis分布式锁实现的方法是什么
      本篇内容主要讲解“Redis分布式锁实现的方法是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Redis分布式锁实现的方法是什么”吧!一、分布式锁是什么分布式锁是 满足分布式系统或集群模式下...
      99+
      2023-07-05
    • 为什么使用redis实现分布式锁
      使用redis实现分布式锁的原因:使用redis不会有线程安全问题。redis数据存在内存中,使效率有一定的提升。redis还支持丰富数据类型。redis可以在缓存、消息传递队列中使用,在应用程序如 Web 应用程序会话、网站页面点击数等任...
      99+
      2024-04-02
    • spring redis分布式锁怎么实现
      在Spring中实现Redis分布式锁可以使用RedisTemplate来操作Redis进行加锁和解锁。 首先,我们需要定义一个分布...
      99+
      2023-10-27
      spring redis
    • Redis怎么样实现分布式锁
      这篇文章主要介绍了Redis怎么样实现分布式锁,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。在一个分布式系统中,会遇到一些需要对多个节点共享的资源加锁的情况,这个时候需要用到...
      99+
      2023-06-21
    • Redis分布式锁的原理是什么和怎么实现
      这篇文章主要介绍了Redis分布式锁的原理是什么和怎么实现的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Redis分布式锁的原理是什么和怎么实现文章都会有所收获,下面我们一起来看看吧。1 一人一单并发安全问题之...
      99+
      2023-07-04
    • Redis中怎么实现分布式锁
      本篇内容介绍了“Redis中怎么实现分布式锁”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!为什么需要分布式...
      99+
      2024-04-02
    • Redis的应用场景是什么
      小编给大家分享一下Redis的应用场景是什么,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!一丶Redis介绍Redis是一个开源...
      99+
      2024-04-02
    • Redis数据类型及应用场景是什么
      小编给大家分享一下Redis数据类型及应用场景是什么,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!1. string类型1-1 ...
      99+
      2024-04-02
    软考高级职称资格查询
    编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
    • 官方手机版

    • 微信公众号

    • 商务合作