基于Redisson的分布式锁原理深度解析与优化实践

基于Redisson的分布式锁原理深度解析与优化实践

分布式环境下,锁的实现至关重要。本文将从技术背景与应用场景出发,结合核心原理、关键源码、实际示例,深入剖析Redisson分布式锁的实现机制,并给出性能优化建议,帮助后端开发者在高并发场景下稳健落地分布式锁。

一、技术背景与应用场景

随着微服务、云原生架构的普及,多个服务实例常常并发访问同一共享资源,例如:

  • 订单重复提交防重:避免高并发下生成重复订单。
  • 库存并发扣减:保证库存不出现超卖。
  • 分布式定时任务:集群环境中同节点只执行一次任务。

传统的JVM层面synchronizedReentrantLock无法跨进程、跨机器使用,需要依赖外部组件。基于Redis的分布式锁具备高性能、部署简单、可扩展等优势,是业界主流选择之一。Redisson作为一款功能丰富、社区活跃的Redis客户端,为分布式锁提供了完整实现。

二、核心原理深入分析

Redisson的分布式锁主要有以下几种实现:

  • RLock (可重入锁)
  • RSemaphore (信号量)
  • RReadWriteLock (读写锁)

本文重点关注RLock的实现原理,核心流程如下:

  1. 客户端调用lock.lock()时,向Redis发送Lua脚本,该脚本会:
    • 先检查当前客户端持有锁的重入计数,若已持有则直接++并续期。
    • 若无持有,则尝试设置key(SET NX PX),成功即获锁,设置内置看门狗续期机制。
  2. 看门狗机制:Redisson启动了一个内部定时任务,每隔lockWatchdogTimeout/3毫秒,续期锁的TTL,以保证长时间业务执行不超时。
  3. 解锁时,客户端执行解锁Lua脚本:
    • 判断当前clientId是否与锁中存储一致,若一致则--重入计数,若计数为0则删除锁并取消续期任务。

2.1 Lua脚本核心代码

-- lock.lua
local key = KEYS[1]
local clientId = ARGV[1]
local ttl = tonumber(ARGV[2])-- 重入
if (redis.call('HEXISTS', key, clientId) == 1) thenredis.call('HINCRBY', key, clientId, 1)redis.call('PEXPIRE', key, ttl)return nil
end-- 初次获取
if (redis.call('EXISTS', key) == 0) thenredis.call('HSET', key, clientId, 1)redis.call('PEXPIRE', key, ttl)return nil
end-- 其他客户端已占用,返回剩余TTL
return redis.call('PTTL', key)

2.2 看门狗(LockWatchdog)实现

Redisson在org.redisson.lock包下实现了看门狗续期任务:

public class LockWatchdog extends ScheduledService {private final String lockName;public LockWatchdog(...){ }@Overridepublic void run() {try {// 发送续期命令,延长TTLcommandExecutor.evalWriteAsync(..., RScript.Mode.READ_WRITE, unlockScript, RScript.ReturnType.STATUS, Arrays.asList(lockName), clientId, lockWatchdogTimeout);} catch (Exception e) {log.error("Lock watchdog renew error", e);}}
}

默认lockWatchdogTimeout为30秒,业务执行时间小于该值时可不设置自定义TTL。

三、关键源码解读

3.1 锁实例生成

RLock lock = redisson.getLock("order:lock");
public class RedissonLock implements RLock {private final CommandAsyncExecutor commandExecutor;private final String name;private final long lockWatchdogTimeout;public void lock() {lock(DEFAULT_ACQUIRY_RETRY_MILLIS, DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS);}public void lock(long leaseTime, TimeUnit unit) {// leaseTime为-1时,启用看门狗续期internalLock(leaseTime, unit);}
}

3.2 加锁的内部逻辑

private void internalLock(long leaseTime, TimeUnit unit) {long threadId = Thread.currentThread().getId();String clientId = getClientId(threadId);long ttl = unit.toMillis(leaseTime) > 0 ? unit.toMillis(leaseTime) : lockWatchdogTimeout;while (true) {Long result = tryAcquireAsync(leaseTime, unit).get();if (result == null) {// 获得锁,启动Watchdog续期scheduleWatchdog(clientId);return;}Thread.sleep(DEFAULT_ACQUIRY_RETRY_MILLIS);}
}

四、实际应用示例

以下示例展示如何在Spring Boot项目中引入Redisson分布式锁:

  1. 引入依赖:
<dependency><groupId>org.redisson</groupId><artifactId>redisson-spring-boot-starter</artifactId><version>3.17.6</version>
</dependency>
  1. 配置文件(application.yml):
redisson:address: "redis://127.0.0.1:6379"lockWatchdogTimeout: 30000
  1. 业务代码:
@Service
public class OrderService {private final RLock orderLock;private final RedissonClient redissonClient;@Autowiredpublic OrderService(RedissonClient client) {this.redissonClient = client;this.orderLock = redissonClient.getLock("order:lock");}public void createOrder(String userId) {orderLock.lock();try {// 核心业务:检查库存、写入订单表processOrder(userId);} finally {orderLock.unlock();}}
}

五、性能特点与优化建议

  1. watchDog续期带来额外心跳开销,可根据业务情况调小lockWatchdogTimeout或显式指定leaseTime
  2. 高并发场景下热点锁可能成为瓶颈,可结合Redisson的RPermitExpirableSemaphore分布式信号量进行限流降级。
  3. 对比Zookeeper实现的分布式锁,Redisson更轻量,适合高TPS场景,但Redis单点故障需配合哨兵/集群部署。
  4. 对锁竞争激烈的场景,可采用业务层面分段锁(Hash槽分段)或增强键前缀随机化,降低热点。
  5. 监控锁的使用情况:结合Redisson API获取当前线程持有信息,并结合Prometheus采集告警。

总结:本文从原理到实践,全面解析了基于Redisson的分布式锁机制并提供优化建议,旨在帮助开发者在高并发生产环境中稳健落地。

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

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

相关文章

室外 3DVG 基准

室外 3DVG基准&#xff08;按重要性与被引用频率&#xff09; Talk2Car / Talk2Car-3D (2019 / 衍生) — 对象 referral&#xff08;驾驶场景&#xff09; 说明&#xff1a;最早的自然语言 → 驾驶场景对象引用数据集之一&#xff08;原 Talk2Car 是以 nuScenes 为底并提供自然…

Jenkins安装部署(Win11)和常见配置镜像加速

一、安装前准备 本文使用的Jenkins Windows一键安装包&#xff0c;JDK事先配置好环境变量&#xff0c;Jenkins版本&#xff1a; Jenkins下载地址&#xff1a;jenkins一键安装包v2-479-1.msi资源-CSDN下载 二、Jenkins安装部署 1、下载Jenkins &#xff0c;点击下一步下一步…

Windows MCP.Net:革命性的 .NET Windows 桌面自动化 MCP 服务器

&#x1f4cb; 目录 项目概述 核心技术架构 功能特性详解 技术实现亮点 安装与配置 实战应用场景 代码示例与API详解 性能优化与最佳实践 未来发展规划 总结 项目概述 在人工智能快速发展的今天&#xff0c;AI 助手与操作系统的深度集成成为了一个重要趋势。Window…

Java ArrayList的介绍及用法

十分想念顺店杂可。。。ArrayList 是 Java 集合框架中最常用的类之一&#xff0c;实现了 List 接口&#xff0c;底层基于动态数组实现&#xff0c;支持动态扩容&#xff0c;相比普通数组更灵活。以下是其详细介绍及用法&#xff1a;一、核心特性动态大小&#xff1a;无需预先指…

Docker 命令大全及使用场景总结

一、容器生命周期管理1. 创建并运行容器docker run [选项] 镜像名 [命令]常用选项&#xff1a;-d&#xff1a;后台运行&#xff08;detached&#xff09;-it&#xff1a;交互式终端&#xff08;如 -it ubuntu bash&#xff09;--name&#xff1a;指定容器名称-p 主机端口:容器端…

简单的 HTTPS 学习

简单的 HTTPS 学习 1. 需求 现在使用的服务是HTTP调用形式&#xff0c;服务可能会有调用外围https形式的服务&#xff0c;简单了解了一下&#xff0c;然后写了一个简单的例子进行记录。 HTTP&#xff08;超文本传输协议&#xff09; 是一种用于传输超文本的应用层协议&#…

[系统架构设计师]系统质量属性与架构评估(八)

[系统架构设计师]系统质量属性与架构评估&#xff08;八&#xff09; 一.软件系统质量属性 1.基本概念 软件系统质量属性&#xff1a;可测量或可测试的属性 开发期质量属性&#xff0c;运行期质量属性面向架构评估的质量属性&#xff1a;1.可用性&#xff1a; 提升策略 错误检测…

【R语言】R 语言中 gsub 与正则表达式详解(含 POSIX 与 Perl 风格实例)

R 语言中 gsub 与正则表达式详解&#xff08;含 POSIX 与 Perl 风格实例&#xff09; 在 R 语言中&#xff0c;字符串处理是非常常见的需求&#xff0c;R 语言中的 gsub() 函数则具有字符串替换的功能。本文将通过两个实例&#xff0c;帮助你深入理解 R 的 gsub()、POSIX 字符…

EN55035多媒体设备电磁兼容性抗干扰要求标准

EN55035 是一项由欧洲标准化委员会制定的电磁兼容性&#xff08;EMC&#xff09;标准&#xff0c;全称为《多媒体设备的电磁兼容性要求》。该标准主要针对多媒体设备的电磁辐射和抗干扰能力进行规范&#xff0c;确保这类设备在电磁环境中能够正常工作&#xff0c;同时不对其他设…

计算分组内时间列的最大差值

计算分组内时间列的最大差值 在 Pandas 中&#xff0c;要计算每个分组内 time 列的最大值与当前行值的差值&#xff0c;需结合 groupby() 和 transform() 方法。核心步骤如下&#xff1a;分组计算最大值 使用 transform(max) 获取每个分组中 time 列的最大值&#xff0c;结果会…

CUDA 编程笔记:CUDA延迟隐藏

一、核心概念&#xff1a;延迟隐藏&#xff08;Latency Hiding&#xff09;是 GPU 通过多线程机制掩盖指令延迟的关键技术。当某些线程束&#xff08;warp&#xff09;因指令延迟&#xff08;如内存访问或算术计算&#xff09;而等待时&#xff0c;其他就绪线程束会立即被调度执…

MySQL工具包中的其他程序

虽然有很多不同的程序&#xff0c;但有些选项是公共的&#xff0c;比兔用户名和密码&#xff0c;使用方法和MySQL相同&#xff0c;在这里统一列出&#xff0c;后面我们介绍不同的工具时&#xff0c;只讨论个性的选项以及作用以下是常用的MySQL程序&#xff1a;程序名作用mysqld…

C#WPF实战出真汁09--【消费开单】--选择菜品

1、功能介绍当选择一个空桌时&#xff0c;必须先开台才能开单&#xff0c;可以先开台&#xff0c;再开单&#xff0c;也可以开台的同时开单当选择一个用餐中的餐桌时&#xff0c;必须显示该桌前面已经点好的菜品&#xff0c;同时可以继续点餐或结账所以无论哪个功能都涉及选择菜…

大厂语音合成成本深度对比:微软 / 阿里 / 腾讯 / 火山 API 计费拆解与技术选型指南

在 AI 配音、智能客服、教育音频等场景爆发的当下&#xff0c;语音合成 API 已成为企业技术栈中的核心组件。然而&#xff0c;不同云厂商的计费规则差异显著&#xff0c;短文本 / 长文本计费分离、预付费 / 后付费价格梯度悬殊、音色授权费暗藏成本陷阱等问题&#xff0c;常导致…

Flutter开发 网络请求

HttpClient&#xff08;dart自有&#xff09; 1.get 点击请求按钮获取数据&#xff0c;解析数据获取单词展示到屏幕上。class MyState extends State {String info "暂无数据";List<Widget> texts [];overridevoid initState() {super.initState();}override…

vscode中用python调用matlab的函数(环境安装)

本实践适用于WIN11-x64和ubuntu22.04-x64系统&#xff0c;其余系统和架构未验证。 效果展示 1.环境要求 MATLAB Engine API for Python 的系统要求&#xff1a;参阅此官方文档MATLAB 与 Python 的版本兼容性&#xff1a;参阅此官方文档 2.安装步骤 安装Vscode&#xff08;不…

【数据分享】大清河(大庆河)流域上游土地利用

而今天要说明数据就是大清河&#xff08;大庆河&#xff09;流域上游土地利用。数据介绍大清河&#xff0c;又称大庆河&#xff0c;作为海河流域的重要支流&#xff0c;其流域上游地区不仅是区域水资源调控的关键节点&#xff0c;更是生态保护与经济发展的重要载体。以下从地理…

图论——Djikstra最短路

原理解释 首先解释一下它大概的应用场景以及原理&#xff1a;现在有这么一张图&#xff0c;图上各点之间都有一定的边权或者说是距离。给定你一个起点&#xff08;例如点1&#xff09;&#xff0c;让你求这个点到图上所有点的最短距离是多少&#xff1f; 这个问题比较平常&…

kafka初步介绍

Kafka角色介绍TopicTopic主题的意思&#xff0c;消费者必须指定主题用于的消息发送&#xff0c;生产者也必须指定主题用于消息的接收。topic只是逻辑上的划分。partitionpartition是分区的意思&#xff0c;他的主要作用是将发送到一个topic的数据做一个划分。如果有4个partitio…

windows10的vs2019编译openssl静态库备忘

1、下载安装openssl源码2、官网下载安装activeperl或Strawberry Perl。官网下载慢&#xff0c;网盘找找。使用中activeperl有些异常提示、缺模块&#xff0c;最后使用了Strawberry Perl。3、安装nasm。powershell使用choco install nasm -y 即可。powershell使用cd命令打开当前…