分布式锁实战:Redisson vs. Redis 原生指令的性能对比

news2025/6/9 7:27:10

分布式锁实战:Redisson vs. Redis 原生指令的性能对比

引言

在DIY主题模板系统中,用户可自定义聊天室的背景、图标、动画等元素。当多个运营人员或用户同时修改同一模板时,若没有锁机制,可能出现“甲修改了背景色,乙覆盖了甲的修改”的脏写问题。此时,分布式锁成为解决资源互斥访问的核心工具。

市场上常见的分布式锁方案有两种:

  • Redis原生指令(如SET key value NX PX):轻量、性能高,但需手动处理超时、可重入等边界问题;
  • Redisson:基于Redis的Java客户端,封装了RedLock算法,提供可重入锁、公平锁等高级特性,但实现复杂度更高。

本文将结合DIY主题模板系统的实际场景,从应用场景底层原理常见坑点压测对比选型建议五大维度,深入解析两种方案的差异,并给出实战指导。

一、分布式锁的应用场景:DIY主题模板系统的互斥需求

1.1 业务背景

DIY主题模板系统的核心功能是模板配置的增删改查,典型操作流程如下:

  1. 运营人员通过后台选择模板ID(如template-123);
  2. 系统从数据库读取模板当前配置(背景色、图标路径等);
  3. 运营人员修改配置(如将背景色从#FFFFFF改为#FF0000);
  4. 系统将新配置写回数据库。

1.2 并发问题与锁需求

当两个运营人员同时修改同一模板时,可能出现以下问题:

  • 丢失更新:甲读取旧配置→乙读取旧配置→甲写入新配置→乙写入新配置(覆盖甲的修改);
  • 脏数据:甲修改图标路径但未提交→乙基于旧路径修改其他字段→甲回滚导致乙的数据依赖失效。

1.3 分布式锁的价值

通过为模板ID(如template-123)加锁,确保同一时刻仅一个请求能修改该模板,流程如图1所示:

请添加图片描述

二、Redisson的底层原理:基于RedLock算法的增强实现

2.1 为什么需要RedLock?

传统的单节点Redis锁(如SET key value NX PX)存在单点故障风险:若Redis主节点宕机且未同步到从节点,锁可能被重复获取。为解决此问题,Redis作者提出了RedLock算法(Redisson默认实现),通过多个独立Redis实例(通常5个)提升可靠性。

2.2 RedLock的获取与释放流程

RedLock的核心逻辑是:向N个独立Redis节点依次申请锁,若在多数节点(N/2+1)成功获取锁,则认为加锁成功。具体流程如图2所示:
请添加图片描述

2.3 Redisson的封装与扩展

Redisson基于RedLock算法,提供了以下增强功能:

  • 可重入锁:同一线程可多次获取同一锁(通过lockCount计数器实现);
  • 公平锁:按请求顺序分配锁(通过Semaphore队列实现);
  • 锁续期:若业务执行时间超过锁过期时间,自动延长锁的有效期(“看门狗”机制);
  • 异步锁:支持lockAsync()/unlockAsync()异步操作,避免阻塞线程。

三、原生Redis指令的坑:从“可用”到“可靠”的距离

3.1 原生Redis锁的基础实现

通过SET key value NX PX指令可实现基础的分布式锁(NX表示仅当key不存在时设置,PX设置过期时间):

public boolean tryLock(String lockKey, String requestId, int expireTime) {
    String result = jedis.set(lockKey, requestId, "NX", "PX", expireTime);
    return "OK".equals(result);
}

public void unlock(String lockKey, String requestId) {
    String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
    jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
}

3.2 原生实现的三大致命问题

(1)问题一:超时导致的锁误删

场景:业务执行时间超过锁的过期时间(如锁设置为30秒,业务执行了40秒),锁自动释放后,其他线程获取锁。此时原线程完成业务后,会删除新线程的锁,导致互斥失效。

原因:锁的过期时间与业务执行时间不匹配,且原生实现未提供自动续期机制。

(2)问题二:不可重入导致的死锁

场景:同一线程在未释放锁的情况下,再次尝试获取同一锁(如递归调用),由于锁已存在(NX条件不满足),加锁失败,导致死锁。

原因:原生Redis锁仅记录“锁是否存在”,未记录“持有锁的线程ID”,无法判断是否是同一线程重复获取。

(3)问题三:单点故障导致的锁失效

场景:Redis主节点宕机,未同步到从节点,新主节点未感知旧锁存在,其他线程可重新获取锁,导致同一资源被多个线程同时修改。

原因:单节点Redis无法保证高可用,锁的可靠性依赖单点。

四、压测对比:Redisson vs. 原生Redis的性能差异

为量化两种方案的性能差异,我们基于DIY主题模板系统的实际场景,设计了以下压测实验:

4.1 压测环境与参数

维度配置/值
服务器8核16G Linux(CentOS 7)
Redis集群5节点(3主2从,主节点内存8G)
压测工具JMeter(500线程,循环100次)
业务场景高并发修改同一模板(锁竞争激烈)

4.2 压测指标说明

  • TPS(每秒事务数):单位时间内成功获取并释放锁的次数;
  • 平均延迟(ms):从请求加锁到释放锁的总耗时;
  • 锁冲突率(%):加锁失败的请求占比(原生Redis无自动重试,Redisson默认重试3次);
  • 锁误删率(%):释放非自己持有的锁的概率。

4.3 压测结果与分析

(1)场景1:短耗时业务(业务执行时间<锁过期时间)
  • 原生Redis锁

    • TPS:12000
    • 平均延迟:8ms
    • 锁冲突率:5%(无重试)
    • 锁误删率:0%(业务执行时间<过期时间,无超时)
  • Redisson(RedLock)

    • TPS:8000
    • 平均延迟:15ms
    • 锁冲突率:2%(自动重试3次)
    • 锁误删率:0%(看门狗自动续期)
(2)场景2:长耗时业务(业务执行时间>锁过期时间)
  • 原生Redis锁

    • TPS:11000
    • 平均延迟:9ms
    • 锁冲突率:8%(部分请求因锁过期被拒绝)
    • 锁误删率:12%(原线程释放已过期的锁)
  • Redisson(RedLock)

    • TPS:7500
    • 平均延迟:18ms
    • 锁冲突率:3%(自动重试+续期)
    • 锁误删率:0%(看门狗续期至业务完成)
(3)场景3:Redis主节点宕机(模拟故障)
  • 原生Redis锁

    • 锁失效时间:30秒(主从切换耗时)
    • 锁冲突率:40%(主节点宕机期间,从节点未同步锁信息)
  • Redisson(RedLock)

    • 锁失效时间:5秒(多数节点存活,仍可保证锁有效)
    • 锁冲突率:5%(仅需多数节点存活即可维持锁)

4.4 数据结论

维度原生Redis锁Redisson(RedLock)
性能(TPS)高(轻量无额外开销)低(需与多个节点交互)
可靠性低(单点故障/超时误删)高(多节点+自动续期)
开发成本高(需手动处理边界问题)低(封装完善,开箱即用)

五、最佳实践:如何选择分布式锁方案?

5.1 按业务场景选择

(1)选择原生Redis锁的场景:
  • 性能敏感:如高频交易系统(每秒上万次锁操作),轻量指令更适合;
  • 短耗时业务:业务执行时间明确<锁过期时间(如5秒内),无需续期;
  • 弱一致性:允许偶发锁冲突(如用户评论点赞,重复点赞可通过幂等处理)。
(2)选择Redisson的场景:
  • 强一致性:如财务系统、配置修改(必须保证互斥);
  • 长耗时业务:业务执行时间不确定(如文件上传、复杂计算),需自动续期;
  • 高可用要求:系统依赖Redis集群(如电商大促、直播活动),需避免单点故障。

5.2 分布式锁的通用设计原则

  1. 锁粒度最小化:仅对核心资源加锁(如模板ID),避免锁整个服务;
  2. 过期时间合理:根据业务执行时间设置(建议为业务耗时的2~3倍),或启用Redisson的看门狗续期;
  3. 唯一标识防误删:锁值设置为请求唯一ID(如UUID),释放时校验(原生Redis通过Lua脚本实现);
  4. 监控与报警:记录锁获取失败率、锁持有时间,及时发现异常(如锁未释放导致的死锁)。

六、实战:在DIY主题模板系统中落地

6.1 原生Redis锁的实现(短耗时场景)

// 短耗时业务(如修改模板背景色,耗时约2秒)
public void updateTemplate(String templateId, String newConfig) {
    String lockKey = "lock:template:" + templateId;
    String requestId = UUID.randomUUID().toString();
    int expireTime = 5000; // 过期时间5秒(业务耗时2秒×2.5)

    // 加锁
    boolean locked = tryLock(lockKey, requestId, expireTime);
    if (!locked) {
        throw new RuntimeException("模板正在被修改,请稍后再试");
    }

    try {
        // 业务逻辑:读取旧配置→修改→写入
        String oldConfig = templateDao.get(templateId);
        String mergedConfig = mergeConfig(oldConfig, newConfig);
        templateDao.update(templateId, mergedConfig);
    } finally {
        // 释放锁(通过Lua脚本防误删)
        unlock(lockKey, requestId);
    }
}

6.2 Redisson的实现(长耗时场景)

// 长耗时业务(如模板批量上传,耗时约30秒)
public void batchUploadTemplate(String templateId, List<Resource> resources) {
    RLock lock = redissonClient.getLock("lock:template:" + templateId);
    try {
        // 加锁(自动续期,过期时间默认30秒)
        boolean locked = lock.tryLock(10, TimeUnit.SECONDS); // 最多等待10秒
        if (!locked) {
            throw new RuntimeException("模板正在被修改,请稍后再试");
        }

        // 业务逻辑:上传资源→生成配置→写入数据库(耗时30秒)
        for (Resource resource : resources) {
            ossClient.upload(resource.getPath(), resource.getContent());
        }
        String newConfig = generateConfig(resources);
        templateDao.update(templateId, newConfig);
    } finally {
        lock.unlock();
    }
}

总结

分布式锁的选择没有“最优解”,需结合业务场景(性能要求、一致性等级)、技术成本(开发维护难度)、系统架构(Redis集群规模)综合判断:

  • 原生Redis锁适合性能敏感、短耗时、弱一致性的场景,但需手动处理边界问题;
  • Redisson适合强一致性、长耗时、高可用的场景,通过封装降低开发成本。

在DIY主题模板系统中,我们对短耗时的“单个配置修改”使用原生Redis锁(TPS高,满足业务需求),对长耗时的“批量资源上传”使用Redisson(避免锁超时误删,保障数据一致性)。

希望本文的实践经验能帮助你在实际项目中做出更合理的选择!

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

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

相关文章

react+taro 开发第五个小程序,解决拼音的学习

1.找一个文件夹 cmd 2.taro init 3.vscode 找开该文件夹cd help-letters 如&#xff1a;我的是(base) PS D:\react\help-letters> pnpm install 4.先编译一下吧。看下开发者工具什么反应。 pnpm dev:weapp 5.开始规则。我用cursor就是不成功。是不是要在这边差不多了&…

kafka(windows)

目录 介绍 下载 配置 测试 介绍 Kafka是一个分布式流媒体平台&#xff0c;类似于消息队列或企业信息传递系统。 下载 Kafka对于Zookeeper是强依赖&#xff0c;所以安装Kafka之前必须先安装zookeeper 官网&#xff1a;Apache Kafka 下载此安装包并解压 配置 新建log…

基于安卓的文件管理器程序开发研究源码数据库文档

摘 要 伴随着现代科技的发展潮流&#xff0c;移动互联网技术快速发展&#xff0c;各种基于通信技术的移动终端设备做的也越来越好了&#xff0c;现代智能手机大量的进入到了我们的生活中。电子产品的各种软硬技术技术的发展&#xff0c;操作系统的不断更新换代&#xff0c;谷歌…

EMC VNXe 存储系统日志收集方法

写在前面 有朋友找来看看VNXe的故障&#xff0c;这种问题总是要收集日志&#xff0c;顺便这里也分享给大家。 注意&#xff0c;VNXe和VNX 属于完全不同的产品&#xff0c;不要看名字很类似&#xff0c;操作系统已经完全重构了&#xff0c;如果说是否有联系&#xff0c;大概就…

从“人找政策”到“政策找人”:智能退税ERP数字化重构外贸生态

离境退税新政核心内容与外贸企业影响 &#xff08;一&#xff09;政策核心变化解析 退税商店网络扩容 新政明确鼓励在大型商圈、旅游景区、交通枢纽等境外旅客聚集地增设退税商店&#xff0c;并放宽备案条件至纳税信用M级企业。以上海为例&#xff0c;静安区计划新增1000家退…

以人类演示视频为提示,学习可泛化的机器人策略

25年5月来自清华大学、上海姚期智研究院和星动纪元&#xff08;RoboEra&#xff09;公司的论文“Learning Generalizable Robot Policy with Human Demonstration Video as a Prompt”。 最近的机器人学习方法通​​常依赖于从通过遥操作收集的大量机器人数据集中进行模仿学习…

SOC-ESP32S3部分:36-适配自己的板卡

飞书文档https://x509p6c8to.feishu.cn/wiki/RP4UwPrsKi4xuQkKLAAcKxD3n1b 如果你自己画了PCB板&#xff0c;需要把自己绘制的板卡配置小智AI工程&#xff0c;可以参考此文档。 下载源码 克隆或下载源码到本地&#xff0c;这里以1.5.5为例&#xff0c;大家可以自行修改其它版…

LLMs 系列科普文(8)

八、模型的自我认知 接下来我们聊聊另一种问题&#xff0c;即模型的自我认知。 网上经常经常可以看到人们会问大语言模型一些关于认知方面的问题&#xff0c;比如“你是什么模型&#xff1f;谁创造了你&#xff1f;” 说实话&#xff0c;其实这个问题有点无厘头。 之所以这么…

机器学习基础相关问题

机器学习相关的基础问题 K-means是否一定会收敛 K-means是否一定会收敛 K-means算法在有限步数内一定会收敛&#xff0c;但收敛到的可能是局部最优解而非全局最优解。以下是详细分析&#xff1a; K-means 的优化目标是最小化 样本到其所归属簇中心的距离平方和&#xff08;SSE…

验证负载均衡与弹性伸缩

什么是弹性伸缩&#xff08;Auto Scaling&#xff09;&#xff1f; 弹性伸缩是指 云计算平台根据实时负载自动调整计算资源&#xff08;如服务器实例、容器Pod&#xff09;数量&#xff0c;以确保系统在高峰时保持稳定&#xff0c;在低谷时节省成本。 什么时候会触发弹性伸缩&…

Three.js中AR实现详解并详细介绍基于图像标记模式AR生成的详细步骤

文档地址 Three.js中AR实现详解 以下是Three.js中实现AR功能的详细解析&#xff0c;涵盖技术原理、实现步骤、核心组件及优化策略&#xff1a; &#x1f9e9; 一、技术基础 AR.js框架的核心作用 AR.js是Three.js实现AR的基石&#xff0c;提供以下核心能力&#xff1a; 多模…

GeoBoundaries下载行政区划边界数据(提供中国资源shapefile)

要下载山东省济南市各个区的行政区划边界数据&#xff0c;你可以通过 geoBoundaries 提供的数据来实现。下面是详细步骤&#xff0c;包括网页操作和可选的 Python 自动化方式。 目录 ✅ 一、通过 geoBoundaries 官网手动下载1. 打开官网&#xff1a;2. 查找中国数据&#xff1a…

大模型如何选型?嵌入模型如何选型?

欢迎来到啾啾的博客&#x1f431;。 记录学习点滴。分享工作思考和实用技巧&#xff0c;偶尔也分享一些杂谈&#x1f4ac;。 有很多很多不足的地方&#xff0c;欢迎评论交流&#xff0c;感谢您的阅读和评论&#x1f604;。 目录 引言模型优劣认知与模型选择大模型&#xff08;L…

开源大模型网关:One API实现主流AI模型API的统一管理与分发

以下是对One API的简单介绍&#xff1a; One API是一个使用go语言开发的大语言模型 API 管理与分发系统支持Docker一键快速部署&#xff0c;且资源占用小&#xff0c;高性能开箱支持多平台大模型快速接入&#xff0c;包括OpenAI、Gemini、xAI、Grop、Anthropic Claude、Ollama…

智慧充电:新能源汽车智慧充电桩的发展前景受哪些因素影响?

全球能源结构转型与碳中和目标的推进&#xff0c;新能源汽车产业迎来爆发式增长&#xff0c;而智慧充电桩作为其核心基础设施&#xff0c;发展前景备受关注。智慧充电不仅关乎用户充电体验的优化&#xff0c;更是电网平衡、能源效率提升的关键环节。 然而&#xff0c;其发展并…

【网站建设】不同类型网站如何选择服务器?建站项目实战总结

做了几个建站项目后,深刻体会到一件事:不同类型的网站,所采用的服务器策略是完全不同的。 如果选错了服务器方案,可能带来过高的成本、过低的性能,甚至上线失败。 这篇文章分享一下我在实战中的经验,供正在做建站项目的朋友参考。 🚩 1️⃣ 纯展示型网站 —— 静态服务…

iptables实验

实验一&#xff1a;搭建web服务&#xff0c;设置任何人能够通过80端口访问。 1.下载并启用httpd服务器 dnf -y install httpd 开启httpd服务器 systemctl start httpd 查看是否启用 下载并启用iptables&#xff0c;并关闭firewalld yum install iptable…

前后端分离开发 和 前端工程化

来源&#xff1a;黑马程序员JavaWeb开发教程&#xff0c;实现javaweb企业开发全流程&#xff08;涵盖SpringMyBatisSpringMVCSpringBoot等&#xff09;_哔哩哔哩_bilibili 前后端混合开发&#xff1a; 需要使用前端的技术栈开发前端的功能&#xff0c;又需要使用Java的技术栈…

web端rtmp推拉流测试、抽帧识别计数,一键式生成巡检报告

本文旨在实现无人机城市交通智慧巡检中的一个模块——无人机视频实时推拉流以及识别流并在前端展示&#xff0c;同时&#xff0c;统计目标数量以及违停数量&#xff0c;生成结果评估&#xff0c;一并发送到前端展示。对于本文任何技术上的空缺&#xff0c;可在博主主页前面博客…

Excel 表格内批量添加前缀与后缀的实用方法

我们经常需要为 Excel 表格中的内容统一添加前缀或后缀&#xff0c;例如给编号加“NO.”、给姓名加“会员_”等。手动操作效率低&#xff0c;本文将介绍几种实用的方法&#xff0c;帮助你快速完成批量添加前缀和后缀的操作。 使用“&”运算符添加前缀或后缀&#xff08;推…