Redis的分布式锁问题(九)Redis + Lua 脚本实现分布式锁

news2025/1/23 4:43:48

Redis的分布式锁问题(九)Redis + Lua 脚本实现分布式锁

上集回顾

Lua的简单介绍 

redis调用函数  

set name jack 

set name Rose,再执行get name 

redis的 EVAL 命令 

Lua脚本解决unLock业务流程 

代码实现 

unLock.lua 

RedisTemplate调用Lua脚本的API 

Lua 解决unLock问题


Redis的分布式锁问题(九)Redis + Lua 脚本实现分布式锁

上集回顾

Redis的分布式锁问题(八)基于Redis的分布式锁_面向鸿蒙编程的博客-CSDN博客icon-default.png?t=M85Bhttps://blog.csdn.net/weixin_43715214/article/details/127967364我们在上一个章节中解决了“分布式锁误删问题”,改进后的代码逻辑如下所示:

但是这仍然不是最佳的实现方案,它在极端的情况下还是会发生问题!

public void unlock() {
    // 获取线程标示
    String threadId = ID_PREFIX + Thread.currentThread().getId();
    // 获取锁中的标示
    String id = stringRedisTemplate.opsForValue().get(KEY_PREFIX + name);
    // 判断标示是否一致
    if(threadId.equals(id)) {
        // 释放锁
        stringRedisTemplate.delete(KEY_PREFIX + name);
    }
}

如上述代码,如果“判断锁标识”和“释放锁”,之间发生了阻塞呢?JVM触发FULL GC

那么之前一节所讲的“锁误删”就有可能发生!!!

所以,我们的解决思路是要保证这两个操作的原子性

我们可以使用Redis的事务+乐观锁来解决这个问题,但是这样子做非常复杂!这里我们使用 Lua 脚本来实现分布式锁

Lua的简单介绍 

Redis提供了Lua脚本功能,在一个脚本中编写多条Redis命令,确保多条命令执行时的原子性 

Lua 教程 | 菜鸟教程 (runoob.com)icon-default.png?t=M85Bhttps://www.runoob.com/lua/lua-tutorial.html

if(0)
then
    print("0 为 true")
end

redis调用函数  

set name jack 

set name Rose,再执行get name 

redis的 EVAL 命令 

如果脚本中的keyvalue不想写死,可以作为参数传递。key类型参数会放入KEYS数组,其它参数会放入ARGV数组,在脚本中可以从KEYSARGV数组获取这些参数:

在Lua中,数组的下标是从1开始的!!!

Lua脚本解决unLock业务流程 

  1. 获取锁中的线程标示
  2. 判断是否与指定的标示(当前线程标示)一致
  3. 如果一致则释放锁(删除)
  4. 如果不一致则什么都不做

代码实现 

unLock.lua 

-- 获取锁标识,是否与当前线程一致?
if(redis.call('get', KEYS[1]) == ARGV[1]) then
    -- 一致,删除
    return redis.call('del', KEYS[1])
end
-- 不一致,直接返回
return 0

RedisTemplate调用Lua脚本的API 

Lua 解决unLock问题

/**
 * redis的分布式锁
 * 实现ILock接口
 */
public class SimpleRedisLock implements ILock {

    // 不同的业务有不同的锁名称
    private String name;
    private StringRedisTemplate stringRedisTemplate;
    private static final String KEY_PREFIX = "lock:";
    private static final String ID_PREFIX = UUID.randomUUID().toString(true) + "-";
    // DefaultRedisScript,
    private static final DefaultRedisScript<Long> UNLOCK_SCRIPT;

    public SimpleRedisLock(String name, StringRedisTemplate stringRedisTemplate) {
        this.name = name;
        this.stringRedisTemplate = stringRedisTemplate;
    }

    // 初始化 UNLOCK_SCRIPT,用静态代码块的方式,一加载SimpleRedisLock有会加载unlock.lua
    // 避免每次调unLock() 才去加载,提升性能!!!
    static {
        UNLOCK_SCRIPT = new DefaultRedisScript<>();
        // setLocation() 设置脚本位置
        UNLOCK_SCRIPT.setLocation(new ClassPathResource("unlock.lua"));
        // 返回值类型
        UNLOCK_SCRIPT.setResultType(Long.class);
    }

    /**
     * 获取锁
     */
    @Override
    public boolean tryLock(long timeoutSec) {
        // 获取线程标示
        String threadId = ID_PREFIX + Thread.currentThread().getId();
        // 获取锁
        // set lock thread1 nx ex 10
        // nx : setIfAbsent(如果不存在) , ex : timeoutSec(秒)
        Boolean success = stringRedisTemplate.opsForValue()
                .setIfAbsent(KEY_PREFIX + name, threadId, timeoutSec, TimeUnit.SECONDS);
        // 自动拆箱(Boolean -> boolean)!!!可能有风险
        return Boolean.TRUE.equals(success);
    }

    /**
     * 解决判断(锁标识、释放锁)这两个动作,之间产生阻塞!!!
     * JVM的 FULL GC
     * 要让这两个动作具有原子性
     */
    @Override
    public void unlock() {
        // 调用lua脚本
        stringRedisTemplate.execute(
                UNLOCK_SCRIPT,
                Collections.singletonList(KEY_PREFIX + name),
                ID_PREFIX + Thread.currentThread().getId());
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/25980.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

APS自动排程在制药行业的应用

制药企业&#xff0c;作为流程工业的一种&#xff0c;既有流程工业所具有的共性也有特殊性&#xff0c;通过发酵、萃取、灌装等生物、化学、物理变化&#xff0c;产生新物质达到增值目的。通常以批量或连续的方式进行生产&#xff0c;需要严格的过程控制和安全措施。生产运行、…

hadoop 3.x大数据集群搭建系列4-安装Spark

文章目录一. 下载spark和scala并解压二. 配置SPARK_HOME环境变量三. 修改配置3.1 修改 spark-defaults.conf3.2 修改spark-env.sh3.3 修改slaves文件四. 将spark目录分发到其他节点五. 启动Spark集群六. 在web界面查看Spark UI七. 测试八. Yarn模式8.1 启动hdfs、yarn服务8.2 修…

笔记本电脑自带录屏吗?笔记本电脑怎么录屏

​现如今&#xff0c;电脑屏幕录制功能越来越成为我们生活中不可或缺的一部分。比如网课录制、游戏画面、软件教程等。很多小伙伴可能知道笔记本电脑拥有录屏功能&#xff0c;但是却不知道笔记本电脑怎么录屏。下面就让小编详细介绍一下&#xff0c;笔记本电脑录屏的方法。 一&…

骨传导耳机的利与弊有哪些?骨传导耳机到底好不好?

耳机大家应该都知道&#xff0c;但是骨传导耳机&#xff0c;大家或许就有点陌生了。目前网上也有很多关于骨传导耳机的科普和盘点&#xff0c;但是个人认为都过于零碎不明了&#xff0c;而我今天就用我玩骨传导耳机好几年的经验和知识&#xff0c;以骨传导用户的角度写了这篇文…

接口幂等设计

文章目录如何设计幂等幂等设计的基本流程建防重表根据状态机分布式锁获取 token如何设计幂等 既然这么多场景需要考虑幂等&#xff0c;那我们如何设计幂等呢&#xff1f; 幂等意味着 一条请求的唯一性。不管是你哪个方案去设计幂等&#xff0c;都需要一个全局唯一的ID&#xf…

【第五部分 | JS WebAPI】2:DOM 元素操作

目录 1-1 改变元素内容&#xff08;去除html和空格换行&#xff09; 1-2 改变元素内容&#xff08;保留html和空格换行 用的最多&#xff09; 1-3 获取元素的内容 [ 更多其它可操作的元素属性 ] 2-1 修改元素的属性 2-2 修改表单元素属性 2-3 使用this指向函数调用者 3…

day35 XSS跨站反射存储DOM盲打劫持

前言 #知识点&#xff1a; 1、XSS跨站-原理&攻击&分类等 2、XSS跨站-反射型&存储型&DOM型等 3、XSS跨站-攻击手法&劫持&盗取凭据等 4、XSS跨站-攻击项目&XSS平台&Beef-XSS 1、原理 指攻击者利用网站程序对用户输入过滤不足&#xff0c;输…

redis<二>spring使用redis,配置远程登录和密码

使用默认的redis配置 改pom, 加入redis依赖,版本可以不需要写&#xff0c;由spring的父工程控制。 <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis --> <!--整合redis--> <dependency><groupId>…

Spring Bean基础-4

1. 定义Bean: 什么是BeanDefinition? 什么是BeanDefinition?BeanDefinition 是 Spring Framework 中定义 Bean 的配置元信息接口, 包含: Bean 的类名Bean 行为配置元素, 如作用域、自动绑定的模式、生命周期回调等其他 Bean 引用, 又可称作合作者 (Collaborators) 或者依赖 …

Feign的简介及使用

一、Feign简介 Feign是一个声明式的http客户端&#xff0c;官方地址:https://github.com/OpenFeign/feign 其作用就是帮助我们优雅的实现http请求的发送&#xff0c;解决代码可读性差&#xff0c;编程体验不统一、参数复杂URL难以维护的问题。 二、使用Feign的步骤 1.引入依赖…

网络原理(Java网络编程)

1.局域网和广域网 局域网LAN: 即 Local Area Network,简称LAN. 局域网内的主机之间能方便的进行网络通信,又称为内网;局域网和局域网之间在没有连接的情况下,是无法通信的.局域网一般可以由交换机或路由器组建. 广域网WAN: 即 Wide Area Network,简称WAN. 广域网是将多个局域网…

【28-业务开发-基础业务-属性管理-SKU和SPU基本概念-SKU和SPU关联关系-属性实体之间的关联关系-批量菜单创建】

一.知识回顾 【0.三高商城系统的专题专栏都帮你整理好了&#xff0c;请点击这里&#xff01;】 【1-系统架构演进过程】 【2-微服务系统架构需求】 【3-高性能、高并发、高可用的三高商城系统项目介绍】 【4-Linux云服务器上安装Docker】 【5-Docker安装部署MySQL和Redis服务】…

力扣(LeetCode)32. 最长有效括号(C++)

栈模拟 合法的括号序列满足两条性质&#xff1a; 1.左括号数等于右括号数 2.任意前缀里&#xff0c;左括号数大于等于右括号数。 括号匹配和栈很般配&#xff0c;遇到左括号&#xff0c;下标入栈&#xff0c;遇到右括号&#xff0c;弹栈匹配。 这题的前缀里有两种不合法&…

【LSTM回归预测】attention机制LSTM时间序列回归预测【含Matlab源码 1992期】

⛄一、attention机制LSTM预测 1 总体框架 数字货币预测模型分为两部分&#xff0c;由LSTM模块和Attention模块组成。 2 LSTM模块 长短期记忆网络&#xff08;LSTM&#xff09;是一种特殊的递归神经网络&#xff08;RNN&#xff09;模型&#xff0c;是为了解决RNN模型梯度消失…

【Codeforces Round #835 (Div. 4)】A——G题解

文章目录A Medium Number题意思路代码B Atillas Favorite Problem题意思路代码C Advantage题意思路代码D Challenging Valleys题意思路代码E Binary Inversions题意思路代码F Quests题意思路代码G SlavicGs Favorite Problem题意思路代码A Medium Number 题意 三个数&#xf…

窗口-视口转换(详细)

在QPainter中&#xff0c;绘制图像使用逻辑坐标绘制&#xff0c;然后再转化为绘图设备的物理坐标。 窗口&#xff08;window&#xff09;&#xff1a;表示逻辑坐标下的相同矩形视口&#xff08;viewport&#xff09;&#xff1a;表示物理坐标下的指定的一个任意矩形默认情况&am…

中国互联网大会天翼云展区大揭秘!

11月15日&#xff0c;由工业和信息化部、深圳市人民政府主办&#xff0c;中国互联网协会、广东省通信管理局、深圳市工业和信息化局等单位承办的2022&#xff08;第二十一届&#xff09;中国互联网大会在深圳开幕。本届大会以“发展数字经济 促进数字文明”为主题&#xff0c;聚…

单商户商城系统功能拆解34—应用中心—分销应用

单商户商城系统&#xff0c;也称为B2C自营电商模式单店商城系统。可以快速帮助个人、机构和企业搭建自己的私域交易线上商城。 单商户商城系统完美契合私域流量变现闭环交易使用。通常拥有丰富的营销玩法&#xff0c;例如拼团&#xff0c;秒杀&#xff0c;砍价&#xff0c;包邮…

在IDEA中搭建Spring5.2.x版本源码(~附带完整过程和图示~)

1.开发环境 JDK8IntelliJ IDEA 2019.1.4 gradle 5.6.4git 2.33.0 2.操作步骤 下载并安装git 进入https://git-scm.com/downloads&#xff0c;下载对应操作系统的git版本一直点击next安装即可记得配置环境变量 获取Spring源码 使用clone的方式将源码拉取到本地&#xff0c;方便…

Java递归查询树形结构(详解)

一.数据准备 数据库表结构如下所示&#xff0c; INSERT INTO jg_user.com_type(type_id, parent_id, type_name) VALUES (1, 0, 合伙企业); INSERT INTO jg_user.com_type(type_id, parent_id, type_name) VALUES (2, 0, 有限公司); INSERT INTO jg_user.com_type(type_id, p…