公司分布式锁加锁错误原因

news2025/2/27 1:45:06

目录

  • 一、问题
  • 二、问题复现
  • 三、为什么产生这个错误
  • 四、解决方案

一、问题

第一次设置锁成功, 但是返回false, 后续在循环获取的时候, 因为已经设置成功, 调用setIfAbsent不会返回true, 导致等锁3s失败
private boolean lockWait(String key, long wait, long expire) {
long totalWait = 0L;
long interval = 200L;

boolean isOk;
while(true) {
    Boolean setResult = this.masterRedisTemplate.opsForValue().setIfAbsent(key, "1", expire, TimeUnit.SECONDS);
    isOk = setResult == null ? false : setResult;
    if (isOk || totalWait > wait) {
        break;
    }

    try {
        Thread.sleep(interval);
        totalWait += interval;
    } catch (InterruptedException var13) {
        break;
    }
}

return isOk;

}

二、问题复现

为复现场景,我们编写以下代码进行测试,使用3个线程,每个线程循环1000次setIfAbsent指令,当遇到失败情况时打印日志。
测试代码
@SneakyThrows
@RequestMapping(value = “/test”)
public void test() {
run();
}

@Resource(name = "frequenceMasterRedisTemplate")
private RedisTemplate<String, String> frequenceMasterRedisTemplate;

private void run() throws InterruptedException {
    new TestThread("A", frequenceMasterRedisTemplate).start();
    new TestThread("B", frequenceMasterRedisTemplate).start();
    new TestThread("C", frequenceMasterRedisTemplate).start();
}

static class TestThread extends Thread {
    String keyPrefix;
    RedisTemplate<String, String> redisTemplate;
    long allStart = System.currentTimeMillis();

    public TestThread(String keyPrefix, RedisTemplate<String, String> redisTemplate) {
        this.keyPrefix = keyPrefix;
        this.redisTemplate = redisTemplate;
    }

    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            String key = keyPrefix + "-" + i;
            long start = System.currentTimeMillis();
            Boolean lock = redisTemplate.opsForValue().setIfAbsent(key, "1", 3, TimeUnit.SECONDS);
            long now = System.currentTimeMillis();
            if (lock == null || !lock) {
                log.error("lockFalse {} {} {} {} {}", key, lock, now - allStart, now - start, redisTemplate.opsForValue().get(key) == null);
                break;
            } else {
                log.info("lock {} {} {}", key, lock, now - start);
            }
        }
    }
}

当我们调用接口的时候,会发现你的控制面板始终能打印lockFalse日志,这说明我们复现了错误!

三、为什么产生这个错误

这个问题php使用相同指令执行没有问题,怀疑过是Luttuce客户端问题,达哥也在github提过Issue,作者不认为这是Luttuce问题,所以我们项目本身的问题可能性更大,经过洪州提示配置在这个类LettuceConfig
LuttuceConfig
@Configuration
@Slf4j
public class LettuceConfig {

public static ClientResources createClientResources() {
    return ClientResources.builder()
            .nettyCustomizer(new NettyCustomizer() {
                @Override
                public void afterChannelInitialized(Channel channel) {

                    int readerIdleTimeSeconds = 12;
                    int writerIdleTimeSeconds = 12;
                    int allIdleTimeSeconds = 12;

                    channel.pipeline().addLast(new IdleStateHandler(readerIdleTimeSeconds, writerIdleTimeSeconds, allIdleTimeSeconds));
                    channel.pipeline().addLast(new ChannelDuplexHandler() {
                        @Override
                        public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
                            if (evt instanceof IdleStateEvent) {
                                ctx.channel().disconnect();
                            } else {
                                super.userEventTriggered(ctx, evt);
                            }
                        }
                    });
                }
            }).commandLatencyCollector(CommandLatencyCollector.disabled())
            .commandLatencyPublisherOptions(DefaultEventPublisherOptions.disabled())
            .commandLatencyCollectorOptions(DefaultCommandLatencyCollectorOptions.disabled()).build();
}

@Bean(name = "commonClientResources", destroyMethod = "shutdown")
public ClientResources commonClientResources() {
    return createClientResources();
}

@Bean(name = "commonClientOptions")
public ClientOptions commonClientOptions() {
    return ClientOptions.builder()
            .socketOptions(SocketOptions.builder().keepAlive(true).build())
            .build();
}

}

我们可以看到,主要配置了Luttuce的连接读空闲,写空闲,和读写空闲时间,作用是可以检测和处理空闲连接,当我们程序中长时间没有进行读操作,写操作时,将会自动触发一个IdleState事件,这时我们可以执行自己的操作,比如关闭连接。
正常情况下的Redis这样配置没有问题,然而在我们项目中,frequenceMasterRedisTemplate实例只是用来做分布式锁,其他场景和业务不会使用这个实例,也就是只会使用setIfAbsent指令,这是一个写操作。
简单来说就是,我们长时间没有使用frequenceMasterRedisTemplate进行读操作,比如get,系统自动触发了一个读空闲超时,然后程序将连接给关闭了,这将会导致正在进行的Redis操作产生意外的结果,比如我们前文所说,执行成功但是返回失败,实际测试中我也发现有可能执行失败,返回也失败。

四、解决方案

既然是配置问题,那么就明朗了,我们只需要清楚 readerIdleTimeSeconds,writerIdleTimeSeconds,allIdleTimeSeconds 三个参数配置后具体会做什么就可以了。
• readerIdleTime: 表示读空闲时间,即多长时间没有读取就会触发事件,默认值为0,表示禁用读空闲检测。
• writerIdleTime: 表示写空闲时间,即多长时间没有写入就会触发事件,默认值为0,表示禁用写空闲检测。
• allIdleTime: 表示读写空闲时间,即多长时间没有读取或写入就会触发事件,默认值为0,表示禁用读写空闲检测。
显然,对于frequenceMasterRedisTemplate的使用场景,我们设置readerIdleTimeSeconds=0,writerIdleTimeSeconds=0,allIdleTimeSeconds=12相对来说比较合理。
参考下Dubbo是如何配置的参数:
在这里插入图片描述
在这里插入图片描述

总之,没有固定的配置模板,根据项目特点和使用场景选择适当的配置参数即可。
另外,Redis分布式锁市面已经有成熟的方案,可以学习下Redisson是怎么做的加解锁,看下我们自研的分布式锁还有哪些问题。

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

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

相关文章

【CV】Latent diffusion model 扩散模型体验

note 文章目录note一、diffusion模型1.1 Stable Diffusion简介1.2 和GAN对比的优势二、Latent diffusion model原理2.1 潜在空间(Lantent Space)2.2 自动编码器和U-Net2.3 文本编码器三、代码实践3.1 模型权重checkpoints3.2 Stable Diffusion v1模型推理3.3 安装Stable Diffus…

再见了,我的C!

本人的第一篇博客发布于1月份&#xff0c;现在已经4月份了&#xff0c;历时3个月&#xff0c;&#xff0c;已经将C语言涵盖的大多数C语言知识点系统性的整理了出来&#xff0c;在这个期间自己收获了很多&#xff0c;这是C语言的最后一篇文章&#xff0c;接下来我们来回顾一下我…

13.Java面向对象----嵌套类

Java面向对象—嵌套类、内部类、匿名类 一、static静态 在《Java编程思想》有这样一段话&#xff1a;   “static方法就是没有this的方法。在static方法内部不能调用非静态方法&#xff0c;反过来是可以的。而且可以在没有创建任何对象的前提下&#xff0c;仅仅通过类本身来…

计及需求侧响应日前、日内两阶段鲁棒备用优化【IEEE6节点】(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

3.3 二维随机变量条件分布

学习目标&#xff1a; 要学习二维随机变量的条件分布&#xff0c;我可能会采取以下步骤&#xff1a; 复习边缘分布和联合分布&#xff1a;首先需要了解二维随机变量的边缘分布和联合分布的概念以及相应的公式。 复习条件概率&#xff1a;学习条件概率的定义和计算公式&#x…

Java使用elasticjob实现定时任务(v2.1.5)

elastic是一个定时任务库 https://shardingsphere.apache.org/elasticjob/index_zh.html 项目结构 ​依赖 <dependency><groupId>com.dangdang</groupId><artifactId>elastic-job-lite-core</artifactId><version>2.1.5</version>&…

【linux】——进程和计划任务管理

文章目录1.进程 VS 线程1.1 程序和进程的关系1.2 线程1.3 进程和线程的关系2.查看进程2.1 查看进程信息ps2.2 查看进程信息top2.3 查看进程信息pgrep2.4 查看进程树pstree3.控制进程3.1 进程的启动方式3.2 进程的前后台调度3.3 终止进程的运行kill3.4 终止进程的运行pkill4.计划…

【华为OD机试】1039 - 迷宫问题

文章目录一、题目&#x1f538;题目描述&#x1f538;输入输出&#x1f538;样例1&#x1f538;样例2二、代码参考作者&#xff1a;KJ.JK&#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &am…

CASA(Carnegie-Ames-Stanford Approach)模型应用

植被作为陆地生态系统的重要组成部分对于生态环境功能的维持具有关键作用。植被净初级生产力&#xff08;Net Primary Productivity, NPP&#xff09;是指单位面积上绿色植被在单位时间内由光合作用生产的有机质总量扣除自养呼吸的剩余部分。植被NPP是表征陆地生态系统功能及可…

全网最详细,Jmeter性能测试-性能基础详解,控制器不同选择(四)

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 逻辑控制器 提前说…

机器学习实战:Python基于支持向量机SVM-RFE进行分类预测(三)

文章目录1 前言1.1 支持向量机的介绍1.2 支持向量机的应用2 demo数据集演示2.1 导入函数2.2 构建数据集拟合2.3 预测模型及可视化3 实例演示分类&#xff08;非SVM&#xff09;3.1 导入函数和数据3.2 简单线性分类3.3 最大间隔决定分类4 实例演示分类&#xff08;SVM&#xff0…

面试之Java的SPI机制详细讲解你会吗?

很多小伙伴对SPi不是很熟悉&#xff0c;今天我给大家详细讲解分享下&#xff1a; Java之SPI机制详细目录 1: SPI机制简介 2: SPI原理 3: 使用场景 4: 源码论证 5: 实战 6: 优缺点 6.1 优点 6.2 缺点 Java之SPI机制详解 1: SPI机制简介 SPI 全称是 Service Provider Interface…

Django整合mysqlclinet步骤

准备工作 要在 Django 中使用 MySQL 数据库&#xff0c;您需要完成以下步骤&#xff1a; 安装 MySQL 服务器和客户端。你可以从官方网站下载并安装&#xff1a;https://www.mysql.com/downloads/ 安装 mysqlclient。mysqlclient 是一个 Python 的第三方库&#xff0c;用于连接…

chapter-7数据库事务

以下课程来源于MOOC学习—原课程请见&#xff1a;数据库原理与应用 考研复习 DBMS保证系统中一切事务的原子性、一致性、隔离性和持续性 DBMS必须对事务故障、系统故障和介质故障进行恢复 恢复中最经常使用的技术&#xff1a;数据库转储和登记日志文件 恢复的基本原理&#…

十二、网络规划与设计

&#xff08;一&#xff09;网络设计基础 1、网络系统生命周期 &#xff08;1&#xff09;四阶段周期&#xff08;重叠&#xff09; 构思与规划阶段、分析与设计阶段、实施与构建阶段、运行与维护阶段 特点&#xff1a;能够快速适应新的需求变化&#xff0c;成本低&#xf…

【SQL 初阶教程】一文轻松玩转 SQL

目录 一、SQL 通用语法 二、SQL 语句的分类 三、DDL语句 DDL——数据库操作 查询所有数据库 语句&#xff1a; SHOW DATABASES;&#xff08;大小写均可&#xff0c;建议大写&#xff09; 创建数据库HSK 语句&#xff1a;CREATE DATABASE HSK; 删除数据库HSK 语句 &#…

关于本地git通过ssh链接github时 time out问题的解决方法

目录问题描述解决方法问题描述 我们如果想要用git ssh链接到远端github&#xff0c;进行repo的clone等操作时&#xff0c;会进行如下的操作&#xff1a; 首先在ssh端命令生成rsa秘钥&#xff0c;命令如下&#xff1a; ssh-keygen -t rsa -C “你的git绑定的邮箱名字”然后在g…

【HBase-读写流程】HBase的读写流程与内部执行机制

【HBase-读写流程】HBase的读写流程与内部执行机制1&#xff09;HBase 读取数据流程1.1.文字描述1.2.流程图2&#xff09;HBase 写入数据流程2.1.文字描述2.2.流程图3&#xff09;flush 机制与 compact 机制的原理3.1.文字描述3.2.流程图1&#xff09;HBase 读取数据流程 1.1.…

游戏开发之Unity2021URP项目场景的构建

地面的修改和编辑&#xff1a;地面插件的使用 打开包管理器&#xff0c;在左边的包那里选择“Unity注册表”&#xff0c;在右边进行搜索“Polybrush”&#xff0c;之后选择右下角的安装 安装完之后要选择样本中的URP进行导入&#xff0c;因为我们的项目是URP渲染管线的&#x…

IronOCR for .NET crack,IronOCR的独特功能

IronOCR for .NET crack,IronOCR的独特功能  在IronTesseract上添加了新的“ReadPdfAndOverlayText”方法&#xff0c;该方法允许您添加文本并保留原始PDF书签/注释。 添加了对存储在应用程序子文件夹中的.config和.json文件中的许可证密钥的支持。 将IronSoftware.System.Dra…