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 块中释放锁,以避免死锁。

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

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

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

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

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

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

相关文章

c++ 笔记二

1.可变参数和限制输入&#xff1a; 代码&#xff1a;不限制输入&#xff0c;返回的总和 #include <iostream> #include <filesystem> #include <string> #include <vector>template<class Type> concept AddAble requires(Type T1, Type T2) …

adb常用命令详解--提升开发效率利器

文章目录 文件管理截屏与录屏logcat 使用dumpsys 相关ps 相关am 相关pm 相关wm 相关setprop 设置属性input 相关adb connect 远程无线调试其它 本文首发地址 https://h89.cn/archives/281.html 最新更新地址 https://gitee.com/chenjim/chenjimblog 博主 Linux 使用较多&#x…

04 翼型和机翼、尾翼几何选择

04 翼型和机翼、尾翼几何选择 4 -1 引言4-2 翼型的选择4-2-1 翼型的几何4-2-2 翼型的升力和阻力4-2-3 翼型选择与设计4-2-4 设计升力系数4-2-5 失速4-2-6 翼型厚度比4-2-7 关于翼型其他方面的考虑 4-3 机翼几何外形4-3-1 展弦比4-2-3 机翼后掠角4-3-3 机翼稍根比4-3-4 机翼扭转…

团结的力量:友情、互助与感恩

时间如白驹过隙&#xff0c;半载光阴转瞬即逝。回首过去的六个月&#xff0c;在CSDN平台上&#xff0c;我经历了无数的挑战和成长。在大厂和阿豪的帮助下&#xff0c;我的粉丝数终于突破了万大关。这不仅是我个人的成就&#xff0c;更是我们团结、互助和感恩精神的见证。 初识…

aardio实战篇) 下载微信公众号文章为pdf和html

首发地址&#xff1a; https://mp.weixin.qq.com/s/w6v3RhqN0hJlWYlqTzGCxA 前言 之前在PC微信逆向) 定位微信浏览器打开链接的call提过要写一个保存公众号历史文章的工具。这篇文章先写一个将文章保存成pdf和html的工具&#xff0c;后面再补充一个采集历史的工具&#xff0c…

HTTP协议版本历程

HTTP协议的发展历程 版本推出年份当前状态HTTP/0.91991年已过时HTTP/1.01996年已过时HTTP/1.11997年标准HTTP/2.02015年标准HTTP/3.02022年标准 HTTP/0.9 HTTP/0.9非常简单&#xff0c;并不涉及数据包传输&#xff0c;通过请求和响应的交换达成通信&#xff0c;请求由单行指…

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

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

小抄 20240611

1 不要总是问“什么项目靠谱”“什么行业有前途”&#xff0c;这些东西对普通人没有太大参考意义&#xff0c;每个看上去靠谱的行业&#xff0c;都有可能变得不靠谱&#xff0c;重要的是&#xff0c;让自己变得靠谱&#xff0c;人靠谱&#xff0c;干什么事都能靠谱。 2 普通人…

图像处理与视觉感知复习--图像特征描述图像生成

文章目录 角点&#xff08;关键点&#xff09;的特点图像分类的流程梯度方向直方图&#xff08;HOG&#xff09;流程平移、旋转和尺度特征&#xff08;SIFT&#xff09;流程常用的图像生成模型GAN的原理Diffusion Model的原理mAP计算方法 角点&#xff08;关键点&#xff09;的…

QY-22 低功耗墒情监测站 厂家直营 无线传输

产品概述 低功耗墒情监测站基于传感、无线通信、处理与控制等物联网技术的开发&#xff0c;利用传感技术&#xff0c;通过传感器测量土壤墒情&#xff0c;并使用物联网进行传输。无需专门的通信线路&#xff0c;在联网的状态下&#xff0c;数据可快速、主动的上报到云平台&…

Vue48-ref属性

一、需求&#xff1a;操作DOM元素 1-1、使用原生的id属性 不太好&#xff01; 1-2、使用 ref属性 原生HTML中&#xff0c;用id属性给元素打标识&#xff0c;vue里面用ref属性。 给哪个元素加了ref属性&#xff0c;vc实例对象就收集哪个元素&#xff01;&#xff01;&#xff0…

光流法大全

H-S光流法 https://blog.csdn.net/Jianwen_Jiang/article/details/79094864 https://blog.csdn.net/jpc20144055069/article/details/96475084 金字塔迭代&#xff08;Iterative Pyramidal&#xff09;LK光流算法 https://github.com/MichaelBeechan/orbslam2-with-…

HTML初体验

可参考jd.com官网&#xff0c;ctrlu查看当前页面源代码 找到你的项目&#xff0c;在项目中创建html类型的网页文件 标准的HTML正确书写格式 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title&…

仅靠独立网站也能赚到100万,真的太牛了

你听说过 Photopea 吗&#xff1f;这是一个免费的类似 Photoshop 的图像编辑器。 这个项目&#xff1a; 每月1300万访问量每月150万用户使用小时每月10万美元的广告收入 Photopea 项目的天才创造者是 Ivan Kutskir。 令人惊讶的是&#xff0c;他独自处理了每日50万用户&…

Tomcat配置详解

文章目录 一、配置文件介绍配置文件日志文件 二、组件组件分层和分类核心组件Tomcat处理请求过程URL对应关系 三、部署java程序手动部署搭建博客状态页 四、常见配置详解tomcat端口号安全配置管理虚拟主机配置Context配置 四、Tomcat Nginx动静分离 一、配置文件介绍 配置好环…

区间DP——AcWing 282. 石子合并

区间DP 定义 区间 DP 是动态规划的一种特殊形式&#xff0c;主要是在一段区间上进行动态规划计算。 运用情况 通常用于解决涉及在一段区间内进行操作、计算最优值等问题。比如计算一个区间内的最大子段和、最小分割代价等。一些常见的场景包括合并操作、划分操作等在区间上…

夏季河湖防溺水新举措:青犀AI视频智能监控系统保障水域安全

近日一则新闻引起大众关注&#xff0c;有网友发布视频称&#xff0c;假期在逛西湖时&#xff0c;发现水面上“平躺”漂浮着一名游客在等待救援。在事发3分钟内&#xff0c;沿湖救生员成功将落水游客救到了岸边。 随着夏季的到来&#xff0c;雨水增多&#xff0c;各危险水域水位…

【镜像制作】制作k8s的yaml配置的备份镜像

文章目录 简介一.备份代码二.dockerfile代码三.cronjob配置 简介 通过shell脚本写一个定期备份k8syaml配置的镜像&#xff0c;然后通过cronjob来实现定期执行&#xff0c;将备份文件上传到ceph存储或者是存放到NAS存储上。 一.备份代码 通过kubectl导出yaml配置文件&#xff0c…

什么是服务器系统端口隐患?

对于服务器来说&#xff0c;首要保障稳定性和安全性。因此&#xff0c;我们仅需保证服务器最基本的功能即可&#xff0c;就像声卡都是默认禁止的。我们并不需要太多的功能&#xff0c;也不需要太多的端口支持。像一些不必要&#xff0c;而且风险较高的端口大可封掉。而一些必要…

如何下载GoldWave 6.80软件及详细安装步骤

GoldWave功能介绍&#xff1a; GoldWave是一款很强大多功能数字音频编辑软件&#xff0c;可以用来消除某些音乐里边的噪音&#xff0c;可以用来声音编缉、播放、录制和转换还是多功能。它的音频特效有很多种可供选择。 GoldWave音频编辑软件与Windows其它应用软件一样&#x…