当前位置: 首页 > news >正文

Redis 分布式锁过期了,还没处理完怎么办?

为了防止死锁,我们会给分布式锁加一个过期时间,但是万一这个时间到了,我们业务逻辑还没处理完,怎么办?

这是一个分布式应用里很常见到的需求,关于这个问题,有经验的程序员会怎么处理呢,今天的文章,V 哥来详细说一说,把这个问题彻底讲清楚。开干!

首先,我们在设置过期时间时要结合业务场景去考虑,尽量设置一个比较合理的值,就是理论上正常处理的话,在这个过期时间内是一定能处理完毕的。

之后,我们再来考虑对这个问题进行兜底设计。

关于这个问题,目前常见的解决方法有两种:

  1. 守护线程“续命”:额外起一个线程,定期检查线程是否还持有锁,如果有则延长过期时间。Redisson 里面就实现了这个方案,使用“看门狗”定期检查(每1/3的锁时间检查1次),如果线程还持有锁,则刷新过期时间。

  2. 超时回滚:当我们解锁时发现锁已经被其他线程获取了,说明此时我们执行的操作已经是“不安全”的了,此时需要进行回滚,并返回失败。

同时,需要进行告警,人为介入验证数据的正确性,然后找出超时原因,是否需要对超时时间进行优化等等。下面V哥分别用案例来介绍以上两种解决方法。对于进一步理解比较有帮助,请继续往下看。

守护线程“续命”

Redisson 是一个基于 Java 的 Redis 客户端库,它提供了多种分布式数据结构和服务,包括实现为 Redisson 对象的分布式锁。使用 Redisson 可以简化分布式锁的实现和管理,特别是它的自动续期功能,可以避免锁在业务执行期间过期。

以下是使用 Redisson 库实现自动续期的 Java 案例代码,以及详细流程步骤的解释:

  1. 添加 Redisson 依赖

首先,需要在项目的 pom.xml 文件中添加 Redisson 的依赖:

<dependencies><!-- 其他依赖... --><dependency><groupId>org.redisson</groupId><artifactId>redisson-spring-boot-starter</artifactId><version>3.15.3</version> <!-- 请使用最新版本 --></dependency>
</dependencies>
  1. 配置 Redisson

在 Spring Boot 应用中,可以通过配置类来配置 Redisson:

@Configuration
public class RedissonConfig {@Value("${spring.redis.host}")private String host;@Value("${spring.redis.port}")private int port;@Beanpublic Config redissonConfig() {Config config = new Config();SingleServerConfig singleServerConfig = config.useSingleServer();singleServerConfig.setAddress(String.format("%s:%d", host, port));singleServerConfig.setPassword("your-password"); // 如果需要密码return config;}
}
  1. 使用 RedissonLock

在业务代码中,通过注入 RLock 来使用分布式锁:

@Service
public class SomeService {private final RLock lock;public SomeService(RLock lock) {this.lock = lock;}public void someMethod() {lock.lock(); // 加锁try {// 执行业务逻辑// ...} finally {lock.unlock(); // 释放锁}}
}
  1. 自动续期机制

Redisson 的 RLock 对象会自动处理锁的续期。当一个线程获取了锁,Redisson 会在后台启动一个定时任务(看门狗),用于在锁即将过期时自动续期。
详细流程步骤:

  • 获取锁:当调用 lock.lock() 时,Redisson 会尝试在 Redis 中创建一个具有过期时间的锁。

  • 锁的自动续期:Redisson 会启动一个后台线程(看门狗),它会在锁的过期时间的一半时检查锁是否仍然被当前线程持有。

  • 续期锁:如果锁仍然被持有,看门狗会延长锁的过期时间。这确保了即使业务逻辑执行时间较长,锁也不会过期。

  • 执行业务逻辑:在锁的保护下,执行业务逻辑。

  • 释放锁:当业务逻辑执行完毕后,调用 lock.unlock() 释放锁。如果当前线程是最后一个持有锁的线程,Redisson 会从 Redis 中删除锁。

  • 异常处理:如果在执行业务逻辑时发生异常,finally 块中的 unlock() 调用确保了锁能够被释放,防止死锁。

  • 看门狗线程终止:一旦锁被释放,看门狗线程会停止续期操作,并结束。

通过这种方式,Redisson 提供了一个简单而强大的机制来处理分布式锁的自动续期,从而减少了锁过期导致的问题。

超时回滚

使用超时回滚机制处理 Redis 分布式锁过期的情况,是指当一个线程因为执行时间过长导致持有的分布式锁过期,而其他线程又获取了同一把锁时,原线程需要能够检测到这一情况并执行业务逻辑的回滚操作。以下是使用 Java 实现的一个业务场景案例,以及详细流程步骤的解释:

  1. 业务场景设定

假设我们有一个电商网站,需要处理订单支付的业务。为了保证在支付过程中数据的一致性,我们需要使用分布式锁来避免并发问题。

  1. 定义分布式锁

我们首先定义一个分布式锁的接口 DistributedLock,然后实现这个接口:

public interface DistributedLock {boolean tryLock(String key, String requestId, long timeout, TimeUnit unit);boolean releaseLock(String key, String requestId);
}public class RedisDistributedLock implements DistributedLock {private final RedisTemplate<String, String> redisTemplate;private static final String LOCK_SCRIPT ="if redis.call('get', KEYS[1]) == ARGV[1] then " +"return redis.call('del', KEYS[1]) " +"else " +"return 0 " +"end";public RedisDistributedLock(RedisTemplate<String, String> redisTemplate) {this.redisTemplate = redisTemplate;}@Overridepublic boolean tryLock(String key, String requestId, long timeout, TimeUnit unit) {long expireTime = unit.toMillis(timeout);// 使用 Lua 脚本来确保原子性return redisTemplate.execute(new StringRedisSerializer(), new StringRedisSerializer(),new DefaultRedisScript<>(LOCK_SCRIPT, Boolean.class),Arrays.asList(key), requestId);}// 省略 releaseLock 方法的实现...
}
  1. 业务逻辑实现

接下来,我们实现订单支付的业务逻辑:

@Service
public class OrderService {private final DistributedLock distributedLock;private final OrderRepository orderRepository;public OrderService(DistributedLock distributedLock, OrderRepository orderRepository) {this.distributedLock = distributedLock;this.orderRepository = orderRepository;}public void processPayment(String orderId) {String lockKey = "order:" + orderId;String requestId = UUID.randomUUID().toString();boolean isLocked = distributedLock.tryLock(lockKey, requestId, 30, TimeUnit.SECONDS);if (!isLocked) {throw new RuntimeException("Could not acquire lock for order: " + orderId);}try {// 执行支付逻辑Order order = orderRepository.findById(orderId).orElseThrow(() -> new RuntimeException("Order not found"));if (order.getStatus() == OrderStatus.PENDING) {// 执行扣款等操作...order.setStatus(OrderStatus.COMPLETED);orderRepository.save(order);}} catch (Exception e) {// 回滚逻辑// 根据业务需求进行回滚,例如恢复库存、撤销交易等throw e;} finally {// 释放锁distributedLock.releaseLock(lockKey, requestId);}}
}
  1. 超时回滚流程步骤:
  • 尝试获取锁:在执行业务逻辑之前,首先尝试获取分布式锁。

  • 执行业务逻辑:如果成功获取锁,则执行支付逻辑,包括检查订单状态、扣款、更新订单状态等。

  • 异常处理:如果在执行过程中发生异常,执行回滚逻辑,撤销已经进行的操作,以保证数据的一致性。

  • 释放锁:无论业务逻辑是否成功执行,都需要在 finally 块中释放锁,以避免死锁。

  • 超时回滚检测:如果业务逻辑执行时间过长导致锁过期,其他线程可能会获取到同一把锁并执行业务逻辑。在这种情况下,原线程在执行回滚逻辑时需要检测锁的状态,如果发现锁已经被其他线程持有,则需要根据业务需求进行相应的处理。

  • 锁释放后的处理:在释放锁之后,如果业务逻辑执行失败,可能需要通知用户或者记录日志,以便进一步处理。

通过这种方式,我们可以确保即使在分布式锁过期的情况下,业务逻辑也能够通过超时回滚机制来保证数据的一致性和完整性。

搞定。关注“威哥爱编程”,一起消灭项目中一个一个问题,成长路上,我们搀扶前行。

相关文章:

Redis 分布式锁过期了,还没处理完怎么办?

为了防止死锁&#xff0c;我们会给分布式锁加一个过期时间&#xff0c;但是万一这个时间到了&#xff0c;我们业务逻辑还没处理完&#xff0c;怎么办&#xff1f; 这是一个分布式应用里很常见到的需求&#xff0c;关于这个问题&#xff0c;有经验的程序员会怎么处理呢&#xff…...

Vue2+Element-ui后台系统常用js方法

el-dialog弹框关闭清空form表单并清空验证 cancelDialog(diaLog, formRef) {this[diaLog] falseif (formRef) {this.$refs[formRef].resetFields()} }页面使用&#xff1a; <el-dialog :visible.sync"addSubsidyDialog.dialog" close"cancelDialog(addSub…...

Kafka高频面试题整理

文章目录 1、什么是Kafka?2、kafka基本概念3、工作流程4、Kafka的数据模型与消息存储机制1)索引文件2)数据文件 5、ACKS 机制6、生产者重试机制:7、kafka是pull还是push8、kafka高性能高吞吐的原因1&#xff09;磁盘顺序读写&#xff1a;保证了消息的堆积2&#xff09;零拷贝机…...

uniapp地图自定义文字和图标

这是我的结构&#xff1a; <map classmap id"map" :latitude"latitude" :longitude"longitude" markertap"handleMarkerClick" :show-location"true" :markers"covers" /> 记住别忘了在data中定义变量…...

k8s_探针专题

关于探针 生产环境中一定要给pod设置探针&#xff0c;不然pod内的应用发生异常时&#xff0c;K8s将不会重启pod。 需要遵循以下几个原则&#xff08;本人自己总结&#xff0c;仅供参考&#xff09;&#xff1a; 探针尽量简单&#xff0c;不要消耗过多资源。因为探针较为频繁的…...

MySQL触发器基本结构

1、修改分隔符符号 delimiter $$ 可以修改成$$ //都行 2、创建触发器函数名称 create trigger 函数名 3、什么样的操作出发&#xff0c;操作那个表 after&#xff1a;......之后触发 befor&#xff1a;......之前触发 insert&#xff1a;插入被触发 update&#xff1a;修改被触…...

前缀和(一维前缀和+二维前缀和)

前缀和 定义&#xff1a; 前缀和是指某序列的前n项和&#xff0c;可以把它理解为数学上的数列的前n项和&#xff0c;而差分可以看成前缀和的逆运算。合理的使用前缀和与差分&#xff0c;可以将某些复杂的问题简单化。 用途&#xff1a; 前缀和一般用于统计一个区间的和&…...

web前端五行属性:深入探索与实战解析

web前端五行属性&#xff1a;深入探索与实战解析 在Web前端开发中&#xff0c;五行属性这一概念或许听起来有些陌生。然而&#xff0c;如果我们将其与前端开发的核心理念相结合&#xff0c;就能发现其中蕴含的深刻内涵。本文将从四个方面、五个方面、六个方面和七个方面&#…...

白酒:茅台镇白酒的酒厂社会责任与可持续发展

云仓酒庄豪迈白酒&#xff0c;作为茅台镇的品牌&#xff0c;不仅在产品品质和口感方面有着卓着的表现&#xff0c;在酒厂社会责任和可持续发展方面也做出了积极的探索和实践。 首先&#xff0c;云仓酒庄豪迈白酒注重环境保护和资源利用。酒厂在生产过程中严格控制能源消耗和排放…...

音视频开发_SDL音频播放器的实现

今天向大家介绍一下如何通过 SDL 实现一个PCM音频播放器。这是一个最简单的播放器&#xff0c;它不涉及到音频的解复用&#xff0c;解码等工作。我们只需要将音频原始数据喂给 SDL 音频接口就可以听到悦耳的声音了。在下面的列子中我将向你演示&#xff0c;使用 SDL 做这样一个…...

C语言学习系列:初识C语言

前言&#xff0c;C语言是什么 语言&#xff0c;比如中文、英语、法语、德语等&#xff0c;是人与人交流的工具。 C语言也是语言&#xff0c;不过是一种特殊的语言&#xff0c;是人与计算机交流的工具。 为什么叫C语言呢&#xff1f; 这就要从C语言的历史说起了。 一&#…...

利用反向代理编写HTTP抓包工具——可视化界面

手写HTTP抓包工具——可视化界面 项目描述语言golang可视化fynev2功能代理抓包、重发、记录 目录 1. 示例1.1 主界面1.2 开启反向代理1.3 抓包1.4 历史记录1.5 重发 2. 核心代码2.1 GUI2.1 抓包 3. 结语3.1 传送门 1. 示例 1.1 主界面 1.2 开启反向代理 1.3 抓包 1.4 历史记录…...

下拉框数据被遮挡 且 后续数据无法下拉的 解决方法

目录 前言1. 问题所示2. 原理分析3. 解决方法3.1 添加空白版2.2 调整z-index2.3 父容器的溢出属性2.4 调整样式属性4. 效果图前言 小程序使用的是Uniapp,原理都差不多,索性标题就不标注Uniapp(小程序) 对于该问题调试了一个晚上,最终解决,对此记录下来 1. 问题所示 执…...

课设--学生成绩管理系统(二)

欢迎来到 Papicatch的博客 目录 &#x1f40b;引言 &#x1f988;编写目的 &#x1f988;项目说明 &#x1f40b;产品介绍 &#x1f988;产品概要说明 &#x1f988;产品用户定位 &#x1f988;产品中的角色 &#x1f40b; 产品总体业务流程图 &#x1f40b; 产品功…...

STM32CubeMX配置-外部中断配置

一、简介 MCU为STM32G070&#xff0c;配置为上升沿触发外部中断&#xff0c;在上升沿外部中断回调函数中进行相关操作。 二、外部中断配置 查看规格书中管教描述&#xff0c;找到I/O对应的外部中断线&#xff0c;然后进行如下上升沿触发外部中断配置。 三、生成代码 调用上升沿…...

基于Vue的日程排班表 - common-schedule

原文&#xff1a;基于Vue的日程排班表 - common-schedule-CSDN博客...

SmartEDA、Multisim、Proteus大比拼:电路设计王者之争?

在电路设计领域&#xff0c;SmartEDA、Multisim和Proteus无疑是三款备受瞩目的软件工具。它们各自拥有独特的功能和优势&#xff0c;但在这场电路设计王者的竞争中&#xff0c;谁才是真正的领跑者&#xff1f;让我们深入探究这三款软件的异同&#xff0c;揭示它们各自的魅力所在…...

【教资科一传统文化】文化素养传统文化之神话传说、天文历法、古代称谓、中国传统节日、成语典故

目录 ​编辑 传统文化之天文历法 (一)四时(四季)从农历、名称上掌握 (二)二十四节气&#xff08;1、名称2、季节-节气3、特殊&#xff09; (三)十二时辰&#xff08;1.先后顺序2.时间段3.别称&#xff09; (四)五更(五夜) (五)天干地支(1.名称2.纪年) ​文化素养传统文化…...

Apache Pulsar 从入门到精通

一、快速入门 Pulsar 是一个分布式发布-订阅消息平台&#xff0c;具有非常灵活的消息模型和直观的客户端 API。 最初由 Yahoo 开发&#xff0c;在 2016 年开源&#xff0c;并于2018年9月毕业成为 Apache 基金会的顶级项目。Pulsar 已经在 Yahoo 的生产环境使用了三年多&#…...

[Bug]使用duckduckgo的duckduckgo_search API搜索图片出现了错误

现在在kaggle上学习一个课程&#xff0c;第一课主要是识别图片里面是不是鸟&#x1f426;。其中一步是使用duckduckgo 搜索图片&#xff0c;源码&#xff1a; from duckduckgo_search import ddg_images from fastcore.all import * from fastbook import search_images_ddgde…...

超短脉冲激光自聚焦效应

前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应&#xff0c;这是一种非线性光学现象&#xff0c;主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场&#xff0c;对材料产生非线性响应&#xff0c;可能…...

macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用

文章目录 问题现象问题原因解决办法 问题现象 macOS启动台&#xff08;Launchpad&#xff09;多出来了&#xff1a;Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显&#xff0c;都是Google家的办公全家桶。这些应用并不是通过独立安装的…...

2021-03-15 iview一些问题

1.iview 在使用tree组件时&#xff0c;发现没有set类的方法&#xff0c;只有get&#xff0c;那么要改变tree值&#xff0c;只能遍历treeData&#xff0c;递归修改treeData的checked&#xff0c;发现无法更改&#xff0c;原因在于check模式下&#xff0c;子元素的勾选状态跟父节…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

【HTML-16】深入理解HTML中的块元素与行内元素

HTML元素根据其显示特性可以分为两大类&#xff1a;块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...

【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)

升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点&#xff0c;但无自动故障转移能力&#xff0c;Master宕机后需人工切换&#xff0c;期间消息可能无法读取。Slave仅存储数据&#xff0c;无法主动升级为Master响应请求&#xff…...

打手机检测算法AI智能分析网关V4守护公共/工业/医疗等多场景安全应用

一、方案背景​ 在现代生产与生活场景中&#xff0c;如工厂高危作业区、医院手术室、公共场景等&#xff0c;人员违规打手机的行为潜藏着巨大风险。传统依靠人工巡查的监管方式&#xff0c;存在效率低、覆盖面不足、判断主观性强等问题&#xff0c;难以满足对人员打手机行为精…...

如何应对敏捷转型中的团队阻力

应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中&#xff0c;明确沟通敏捷转型目的尤为关键&#xff0c;团队成员只有清晰理解转型背后的原因和利益&#xff0c;才能降低对变化的…...

Vue ③-生命周期 || 脚手架

生命周期 思考&#xff1a;什么时候可以发送初始化渲染请求&#xff1f;&#xff08;越早越好&#xff09; 什么时候可以开始操作dom&#xff1f;&#xff08;至少dom得渲染出来&#xff09; Vue生命周期&#xff1a; 一个Vue实例从 创建 到 销毁 的整个过程。 生命周期四个…...

CVPR2025重磅突破:AnomalyAny框架实现单样本生成逼真异常数据,破解视觉检测瓶颈!

本文介绍了一种名为AnomalyAny的创新框架&#xff0c;该方法利用Stable Diffusion的强大生成能力&#xff0c;仅需单个正常样本和文本描述&#xff0c;即可生成逼真且多样化的异常样本&#xff0c;有效解决了视觉异常检测中异常样本稀缺的难题&#xff0c;为工业质检、医疗影像…...