Redis 分布式锁过期了,还没处理完怎么办?
为了防止死锁,我们会给分布式锁加一个过期时间,但是万一这个时间到了,我们业务逻辑还没处理完,怎么办?
这是一个分布式应用里很常见到的需求,关于这个问题,有经验的程序员会怎么处理呢,今天的文章,V 哥来详细说一说,把这个问题彻底讲清楚。开干!
首先,我们在设置过期时间时要结合业务场景去考虑,尽量设置一个比较合理的值,就是理论上正常处理的话,在这个过期时间内是一定能处理完毕的。
之后,我们再来考虑对这个问题进行兜底设计。
关于这个问题,目前常见的解决方法有两种:
-
守护线程“续命”:额外起一个线程,定期检查线程是否还持有锁,如果有则延长过期时间。Redisson 里面就实现了这个方案,使用“看门狗”定期检查(每1/3的锁时间检查1次),如果线程还持有锁,则刷新过期时间。
-
超时回滚:当我们解锁时发现锁已经被其他线程获取了,说明此时我们执行的操作已经是“不安全”的了,此时需要进行回滚,并返回失败。
同时,需要进行告警,人为介入验证数据的正确性,然后找出超时原因,是否需要对超时时间进行优化等等。下面V哥分别用案例来介绍以上两种解决方法。对于进一步理解比较有帮助,请继续往下看。
守护线程“续命”
Redisson 是一个基于 Java 的 Redis 客户端库,它提供了多种分布式数据结构和服务,包括实现为 Redisson 对象的分布式锁。使用 Redisson 可以简化分布式锁的实现和管理,特别是它的自动续期功能,可以避免锁在业务执行期间过期。
以下是使用 Redisson 库实现自动续期的 Java 案例代码,以及详细流程步骤的解释:
- 添加 Redisson 依赖
首先,需要在项目的 pom.xml 文件中添加 Redisson 的依赖:
<dependencies><!-- 其他依赖... --><dependency><groupId>org.redisson</groupId><artifactId>redisson-spring-boot-starter</artifactId><version>3.15.3</version> <!-- 请使用最新版本 --></dependency>
</dependencies>
- 配置 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;}
}
- 使用 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(); // 释放锁}}
}
- 自动续期机制
Redisson 的 RLock 对象会自动处理锁的续期。当一个线程获取了锁,Redisson 会在后台启动一个定时任务(看门狗),用于在锁即将过期时自动续期。
详细流程步骤:
-
获取锁
:当调用 lock.lock() 时,Redisson 会尝试在 Redis 中创建一个具有过期时间的锁。 -
锁的自动续期
:Redisson 会启动一个后台线程(看门狗),它会在锁的过期时间的一半时检查锁是否仍然被当前线程持有。 -
续期锁
:如果锁仍然被持有,看门狗会延长锁的过期时间。这确保了即使业务逻辑执行时间较长,锁也不会过期。 -
执行业务逻辑
:在锁的保护下,执行业务逻辑。 -
释放锁
:当业务逻辑执行完毕后,调用 lock.unlock() 释放锁。如果当前线程是最后一个持有锁的线程,Redisson 会从 Redis 中删除锁。 -
异常处理
:如果在执行业务逻辑时发生异常,finally 块中的 unlock() 调用确保了锁能够被释放,防止死锁。 -
看门狗线程终止
:一旦锁被释放,看门狗线程会停止续期操作,并结束。
通过这种方式,Redisson 提供了一个简单而强大的机制来处理分布式锁的自动续期,从而减少了锁过期导致的问题。
超时回滚
使用超时回滚机制处理 Redis 分布式锁过期的情况,是指当一个线程因为执行时间过长导致持有的分布式锁过期,而其他线程又获取了同一把锁时,原线程需要能够检测到这一情况并执行业务逻辑的回滚操作。以下是使用 Java 实现的一个业务场景案例,以及详细流程步骤的解释:
- 业务场景设定
假设我们有一个电商网站,需要处理订单支付的业务。为了保证在支付过程中数据的一致性,我们需要使用分布式锁来避免并发问题。
- 定义分布式锁
我们首先定义一个分布式锁的接口 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 方法的实现...
}
- 业务逻辑实现
接下来,我们实现订单支付的业务逻辑:
@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);}}
}
- 超时回滚流程步骤:
-
尝试获取锁:在执行业务逻辑之前,首先尝试获取分布式锁。
-
执行业务逻辑:如果成功获取锁,则执行支付逻辑,包括检查订单状态、扣款、更新订单状态等。
-
异常处理:如果在执行过程中发生异常,执行回滚逻辑,撤销已经进行的操作,以保证数据的一致性。
-
释放锁:无论业务逻辑是否成功执行,都需要在 finally 块中释放锁,以避免死锁。
-
超时回滚检测:如果业务逻辑执行时间过长导致锁过期,其他线程可能会获取到同一把锁并执行业务逻辑。在这种情况下,原线程在执行回滚逻辑时需要检测锁的状态,如果发现锁已经被其他线程持有,则需要根据业务需求进行相应的处理。
-
锁释放后的处理:在释放锁之后,如果业务逻辑执行失败,可能需要通知用户或者记录日志,以便进一步处理。
通过这种方式,我们可以确保即使在分布式锁过期的情况下,业务逻辑也能够通过超时回滚机制来保证数据的一致性和完整性。
搞定。关注“威哥爱编程”,一起消灭项目中一个一个问题,成长路上,我们搀扶前行。
相关文章:
Redis 分布式锁过期了,还没处理完怎么办?
为了防止死锁,我们会给分布式锁加一个过期时间,但是万一这个时间到了,我们业务逻辑还没处理完,怎么办? 这是一个分布式应用里很常见到的需求,关于这个问题,有经验的程序员会怎么处理呢ÿ…...

Vue2+Element-ui后台系统常用js方法
el-dialog弹框关闭清空form表单并清空验证 cancelDialog(diaLog, formRef) {this[diaLog] falseif (formRef) {this.$refs[formRef].resetFields()} }页面使用: <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)磁盘顺序读写:保证了消息的堆积2)零拷贝机…...

uniapp地图自定义文字和图标
这是我的结构: <map classmap id"map" :latitude"latitude" :longitude"longitude" markertap"handleMarkerClick" :show-location"true" :markers"covers" /> 记住别忘了在data中定义变量…...
k8s_探针专题
关于探针 生产环境中一定要给pod设置探针,不然pod内的应用发生异常时,K8s将不会重启pod。 需要遵循以下几个原则(本人自己总结,仅供参考): 探针尽量简单,不要消耗过多资源。因为探针较为频繁的…...
MySQL触发器基本结构
1、修改分隔符符号 delimiter $$ 可以修改成$$ //都行 2、创建触发器函数名称 create trigger 函数名 3、什么样的操作出发,操作那个表 after:......之后触发 befor:......之前触发 insert:插入被触发 update:修改被触…...

前缀和(一维前缀和+二维前缀和)
前缀和 定义: 前缀和是指某序列的前n项和,可以把它理解为数学上的数列的前n项和,而差分可以看成前缀和的逆运算。合理的使用前缀和与差分,可以将某些复杂的问题简单化。 用途: 前缀和一般用于统计一个区间的和&…...
web前端五行属性:深入探索与实战解析
web前端五行属性:深入探索与实战解析 在Web前端开发中,五行属性这一概念或许听起来有些陌生。然而,如果我们将其与前端开发的核心理念相结合,就能发现其中蕴含的深刻内涵。本文将从四个方面、五个方面、六个方面和七个方面&#…...

白酒:茅台镇白酒的酒厂社会责任与可持续发展
云仓酒庄豪迈白酒,作为茅台镇的品牌,不仅在产品品质和口感方面有着卓着的表现,在酒厂社会责任和可持续发展方面也做出了积极的探索和实践。 首先,云仓酒庄豪迈白酒注重环境保护和资源利用。酒厂在生产过程中严格控制能源消耗和排放…...
音视频开发_SDL音频播放器的实现
今天向大家介绍一下如何通过 SDL 实现一个PCM音频播放器。这是一个最简单的播放器,它不涉及到音频的解复用,解码等工作。我们只需要将音频原始数据喂给 SDL 音频接口就可以听到悦耳的声音了。在下面的列子中我将向你演示,使用 SDL 做这样一个…...

C语言学习系列:初识C语言
前言,C语言是什么 语言,比如中文、英语、法语、德语等,是人与人交流的工具。 C语言也是语言,不过是一种特殊的语言,是人与计算机交流的工具。 为什么叫C语言呢? 这就要从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的博客 目录 🐋引言 🦈编写目的 🦈项目说明 🐋产品介绍 🦈产品概要说明 🦈产品用户定位 🦈产品中的角色 🐋 产品总体业务流程图 🐋 产品功…...

STM32CubeMX配置-外部中断配置
一、简介 MCU为STM32G070,配置为上升沿触发外部中断,在上升沿外部中断回调函数中进行相关操作。 二、外部中断配置 查看规格书中管教描述,找到I/O对应的外部中断线,然后进行如下上升沿触发外部中断配置。 三、生成代码 调用上升沿…...
基于Vue的日程排班表 - common-schedule
原文:基于Vue的日程排班表 - common-schedule-CSDN博客...

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

【教资科一传统文化】文化素养传统文化之神话传说、天文历法、古代称谓、中国传统节日、成语典故
目录 编辑 传统文化之天文历法 (一)四时(四季)从农历、名称上掌握 (二)二十四节气(1、名称2、季节-节气3、特殊) (三)十二时辰(1.先后顺序2.时间段3.别称) (四)五更(五夜) (五)天干地支(1.名称2.纪年) 文化素养传统文化…...

Apache Pulsar 从入门到精通
一、快速入门 Pulsar 是一个分布式发布-订阅消息平台,具有非常灵活的消息模型和直观的客户端 API。 最初由 Yahoo 开发,在 2016 年开源,并于2018年9月毕业成为 Apache 基金会的顶级项目。Pulsar 已经在 Yahoo 的生产环境使用了三年多&#…...
[Bug]使用duckduckgo的duckduckgo_search API搜索图片出现了错误
现在在kaggle上学习一个课程,第一课主要是识别图片里面是不是鸟🐦。其中一步是使用duckduckgo 搜索图片,源码: from duckduckgo_search import ddg_images from fastcore.all import * from fastbook import search_images_ddgde…...

超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...
macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用
文章目录 问题现象问题原因解决办法 问题现象 macOS启动台(Launchpad)多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显,都是Google家的办公全家桶。这些应用并不是通过独立安装的…...

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

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
【HTML-16】深入理解HTML中的块元素与行内元素
HTML元素根据其显示特性可以分为两大类:块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...
【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)
升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点,但无自动故障转移能力,Master宕机后需人工切换,期间消息可能无法读取。Slave仅存储数据,无法主动升级为Master响应请求ÿ…...

打手机检测算法AI智能分析网关V4守护公共/工业/医疗等多场景安全应用
一、方案背景 在现代生产与生活场景中,如工厂高危作业区、医院手术室、公共场景等,人员违规打手机的行为潜藏着巨大风险。传统依靠人工巡查的监管方式,存在效率低、覆盖面不足、判断主观性强等问题,难以满足对人员打手机行为精…...

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

Vue ③-生命周期 || 脚手架
生命周期 思考:什么时候可以发送初始化渲染请求?(越早越好) 什么时候可以开始操作dom?(至少dom得渲染出来) Vue生命周期: 一个Vue实例从 创建 到 销毁 的整个过程。 生命周期四个…...

CVPR2025重磅突破:AnomalyAny框架实现单样本生成逼真异常数据,破解视觉检测瓶颈!
本文介绍了一种名为AnomalyAny的创新框架,该方法利用Stable Diffusion的强大生成能力,仅需单个正常样本和文本描述,即可生成逼真且多样化的异常样本,有效解决了视觉异常检测中异常样本稀缺的难题,为工业质检、医疗影像…...