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

[WenJi项目实战]拒绝死锁与误删:从手写 Redis 锁到 Redisson 看门狗的演进之路

[WenJi项目实战]拒绝死锁与误删:从手写 Redis 锁到 Redisson 看门狗的演进之路

前言

在文迹项目的用户发布博客的场景中,为了防止同一用户频繁刷接口赚取积分,我们通常会使用 Redis 分布式锁进行限流。本文将结合实际业务,拆解手写 Redis 锁的核心原理,分析其在极端场景下的隐患,并探讨如何通过 Lua 脚本和 Redisson 进行架构升级。

🔍 当前分布式锁的实现原理

核心代码

// ① 加锁:SETNX + TTL 原子操作StringlockKey="lock:blog:"+userId;// 按用户粒度加锁StringlockValue=UUID.randomUUID().toString();// 唯一标识Booleanacquired=stringRedisTemplate.opsForValue().setIfAbsent(lockKey,lockValue,10,TimeUnit.SECONDS);if(Boolean.FALSE.equals(acquired)){thrownewBusinessException(429,"操作太频繁");}// ② 释放锁:GET 比较 + DELETE(防误删)StringcurrentValue=stringRedisTemplate.opsForValue().get(lockKey);if(lockValue.equals(currentValue)){stringRedisTemplate.delete(lockKey);}

原理拆解(三个关键设计点)

设计点实现方式解决什么问题
原子加锁setIfAbsent(key, value, ttl, unit)对应 RedisSET key value NX EX 10,NX 保证互斥,EX 防止死锁
唯一标识UUID 作为 value防止误删其他线程持有的锁
安全解锁GET → 比较 UUID → DELETE解决"锁过期后误删新锁"的经典问题

💡 为什么需要 UUID?
假设线程 A 获取锁后,业务执行超时导致锁自动过期。此时线程 B 获取了锁,如果线程 A 随后直接执行delete,就会把线程 B 的锁删掉。通过 UUID 校验,可以确保线程 A 只能删除属于自己的锁。

锁粒度设计

目前按用户粒度加锁(lock:blog:{userId}):

  • 用户 A(id=1):lock:blog:1← 只锁用户 A 自己
  • 用户 B(id=2):lock:blog:2← 不影响用户 B
    同一用户并发 100 次请求,仅 1 次成功,其余返回 429;不同用户之间完全隔离。

现存隐患分析

虽然手写锁能解决大部分并发问题,但在架构层面仍存在以下缺陷:

  1. 锁过期时间写死:业务执行时间如果超过 10s,锁会自动释放,后续请求进入,导致并发安全问题。
  2. 缺乏续期机制:没有类似 Redisson 的“看门狗”机制,锁一旦过期只能自动释放。
  3. 解锁非原子性:释放锁分为GETDELETE两步。在极端时序下(GET 之后、DELETE 之前锁恰好过期),依然有极小概率发生误删。

🚀 架构升级方案

方案 1:引入 Lua 脚本,保证解锁绝对原子性(当前最快捷的修改方式,项目也修改成这个方法)

GETDELETE合并为 Redis 端的原子操作,彻底消除误删风险。

1. 编写lua/unlock.lua

ifredis.call("GET",KEYS[1])==ARGV[1]thenreturnredis.call("DEL",KEYS[1])elsereturn0end

2. 配置 Spring Bean(启动时加载一次)

@ConfigurationpublicclassRedisLuaConfig{@BeanpublicDefaultRedisScript<Long>unlockScript(){DefaultRedisScript<Long>script=newDefaultRedisScript<>();script.setLocation(newClassPathResource("lua/unlock.lua"));script.setResultType(Long.class);returnscript;}}

3. 业务层调用

Longresult=stringRedisTemplate.execute(unlockScript,Collections.singletonList(lockKey),lockValue);

方案 2:引入 Redisson + 看门狗(终极方案)

如果希望彻底解决锁过期和续期问题,引入 Redisson 是最佳选择。

1. 添加依赖

<dependency><groupId>org.redisson</groupId><artifactId>redisson-spring-boot-starter</artifactId><version>3.27.0</version></dependency>

2. 业务代码重构

@AutowiredprivateRedissonClientredissonClient;publicvoidpublishBlog(TravelBlogblog){RLocklock=redissonClient.getLock("lock:blog:"+blog.getUserId());// tryLock(等待时间, 锁持有时间, 时间单位)// 锁持有时间传 -1 则启用看门狗(自动续期)if(!lock.tryLock(0,-1,TimeUnit.SECONDS)){thrownewBusinessException(429,"操作太频繁");}try{// 业务逻辑... 锁会自动续期(默认每 10 秒续一次)}finally{// 必须在 finally 中释放,且 Redisson 内部已实现原子化释放lock.unlock();}}

📝 总结

  • 轻量级场景:如果业务执行极快(毫秒级),手写SETNX+Lua 脚本解锁已经足够,无需引入额外依赖。
  • 复杂/耗时场景:如果业务逻辑复杂、执行时间不可控,强烈建议直接上Redisson,利用看门狗机制保障分布式锁的绝对安全。
http://www.jsqmd.com/news/1048501/

相关文章:

  • 积石山宴席必吃菜品推荐|本地人私藏清真家常菜,办宴不踩雷清单 - 速递信息
  • 潍坊营业性演出许可证代办公司推荐那家专业靠谱 - 速递信息
  • 帆软报表前台任意文件上传漏洞深度剖析与武器化实践
  • 2026年6月最新百达翡丽中国官方售后网点服务电话及客户热线地址 - 百达翡丽服务中心
  • 2026北京黄金回收行情解读|顶尖翘楚执牛耳,全城黄金回收商家实力段位测评 - 奢侈品交易观察员
  • 2026北京黄金回收行业翘楚测评|龙头领衔执牛耳,正规黄金回收标杆甄选指南 - 奢侈品交易观察员
  • 2026青岛门窗选购权威推荐:五大本地实力派源头工厂年度榜单与深度实测 - GrowthUME
  • VEO 3多模态私有化部署实战:从模型验证到推理流水线
  • 2026年6月最新天梭中国官方售后网点客户服务电话及地址 - 天梭服务中心
  • 2026惠州黄金变现避坑全指南:6家正规机构实测推荐,惠奢汇领衔不踩坑 - 生活测评小能手
  • 2026河源黄金奢侈品回收靠谱门店排名实测:避坑攻略看这篇 - 生活测评小能手
  • 2026黄金回收避坑指南:称重、鉴定、报价全流程干货 - 奢侈品交易观察员
  • 2026北京名表回收选购指南|领航全域+行业翘楚,全城奢表回收商家星级权威测评 - 奢侈品交易观察员
  • SAP UI5项目实战:用Gherkin与BDD实现业务语言驱动自动化测试
  • 沈阳刑事律师机构排行:基于专业维度的客观参考 - 互联网科技品牌测评
  • 2026年6月最新浪琴中国官方售后客户电话热线地址服务网点 - 浪琴服务中心
  • 北京播音主持艺考考前冲刺班盘点 适配不同备考需求 - 互联网科技品牌测评
  • 第一个量化实验
  • 南通办理营业性演出许可证代办服务商推荐 - 速递信息
  • 2026年现阶段西安企业甄选AI推广服务商:口碑、实力与落地能力缺一不可 - 速递信息
  • 数据说话!2026沈阳黄金回收高价、正规、速度综合排名 - 奢侈品交易观察员
  • 2026年国内活性炭吸附设备厂家排行 解决选型痛点适配全场景 - 速递信息
  • 2026年6月最新江诗丹顿中国官方售后电话网点服务热线地址客服 - 江诗丹顿服务中心
  • 沈阳刑事律师排行盘点:专业实力与本地经验对比 - 互联网科技品牌测评
  • 微信里能投票吗?微信里面怎么做投票,云帆投票+西瓜评选+腾讯投票,平台深度测评报告 - 投票小程序
  • 惠州黄金回收靠谱机构推荐:2026最新排名与避坑全指南 - 生活测评小能手
  • 2026年上海机械革命官方售后服务最新地址核验报告 - GrowthUME
  • 3080Ti显存仅12GB,如何用QLoRA微调Qwen2.5-7B-Instruct
  • 北京播音主持艺考考前冲刺班 合规机构盘点参考 - 互联网科技品牌测评
  • 新手必看!2026黄金回收正确变现方式,杜绝低价套路 - 奢侈品交易观察员