做一个私人网站需要多少钱,pycharm网站开发,app网站开发流程图,百度指数是搜索量吗Redis 分布式锁实现详解#xff1a;基于 SET NX Lua 脚本的互斥性保证 在分布式系统中#xff0c;多个服务实例同时操作同一资源时#xff0c;必须保证同一时刻只有一个实例能执行关键逻辑。这就是分布式锁的核心作用。本文基于一个生产环境中常用的 Redis Spring Boot 实…Redis 分布式锁实现详解基于 SET NX Lua 脚本的互斥性保证在分布式系统中多个服务实例同时操作同一资源时必须保证同一时刻只有一个实例能执行关键逻辑。这就是分布式锁的核心作用。本文基于一个生产环境中常用的 Redis Spring Boot 实现方案详细讲解为什么其他客户端无法重复获取同一把锁并结合具体代码进行原理分析。一、分布式锁的核心要求一个合格的分布式锁必须满足互斥性任意时刻全局只有一个客户端持有锁。防死锁持有锁的客户端崩溃后锁能自动释放。解锁安全只有加锁的客户端才能释放锁防止误删他人锁。高性能加锁/解锁操作应为原子级。二、Redis 实现方案核心原理本文方案使用Redis 的 SET NX EX 原子命令实现加锁配合Lua 脚本实现安全解锁。核心依赖 Redis 的单线程模型和原子操作确保互斥性。1. 加锁原理tryLock 方法BooleanresultredisTemplate.opsForValue().setIfAbsent(fullLockKey,lockValue,expireTime,TimeUnit.SECONDS);底层等价于 Redis 命令SET lock_prefix:xxx 客户端唯一value NX EX 30NXNot eXists只有 key 不存在时才设置成功。EX同时设置过期时间防止死锁。为什么其他客户端无法重复获取锁Redis 是单线程的所有命令串行执行。当客户端 A 执行 SET NX 时如果 key 不存在 → 设置成功A 获得锁。客户端 B、C 几乎同时到达 → Redis 已经处理完 A 的命令此时 key 已存在B 和 C 的 NX 操作直接失败。关键点Redis 单线程 NX 原子性保证“先到先得”后到的客户端必然看到 key 已存在无法重复设置。因此全局互斥性得到严格保证。2. 解锁原理releaseLock 方法LongresultredisTemplate.execute(redisScript,Collections.singletonList(fullLockKey),lockValue);Lua 脚本原代码版本ifredis.call(get,KEYSp[1]ARGV[1]thenreturnredis.call(del,KEYS[1])elsereturn0endLua 脚本的作用先判断当前 key 的 value 是否等于加锁时设置的 lockValue。只有匹配才执行 DEL。整个脚本在 Redis 服务器端原子执行中间不会被其他命令插入。为什么这能防止后续重复假设 A 持有锁但业务超时锁过期后 B 抢到锁。此时 A 执行解锁Lua 校验 value 不匹配 → 不删除 B 的锁。B 的锁继续有效后续客户端 C 依然无法抢到。如果没有 Lua 直接 DEL就会出现“A 删了 B 的锁 → C 立刻抢到”的连锁反应导致互斥性失效。三、完整代码实现生产可用版建议packagecom.anmory.common.service.impl;importcom.anmory.common.service.DistributeLockService;importlombok.extern.slf4j.Slf4j;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.data.redis.core.StringRedisTemplate;importorg.springframework.data.redis.core.script.DefaultRedisScript;importorg.springframework.stereotype.Service;importjava.util.Collections;importjava.util.concurrent.TimeUnit;/** * 分布式锁服务实现类 */ServiceSlf4jpublicclassDistributeLockServiceImplimplementsDistributeLockService{AutowiredprivateStringRedisTemplateredisTemplate;privatestaticfinalStringLOCK_PREFIXlock_prefix:;privatefinalDefaultRedisScriptLongredisScript;privatestaticfinalStringSCRIPT_TEXTif redis.call(get, KEYSp[1] ARGV[1] then return redis.call(del, KEYS[1]) else return 0 end;publicDistributeLockServiceImpl(){redisScriptnewDefaultRedisScript();redisScript.setScriptText(SCRIPT_TEXT);redisScript.setResultType(Long.class);}OverridepublicbooleantryLock(StringlockKey,StringlockValue,longexpireTime){// 1. 补全完整的keyStringfullLockKeyLOCK_PREFIXlockKey;// 2. 把value写进redisBooleanresultredisTemplate.opsForValue().setIfAbsent(fullLockKey,lockValue,expireTime,TimeUnit.SECONDS);if(result){log.info([redis分布式锁], 获取锁成功, key:{}, value:{},fullLockKey,lockValue);}else{log.error([redis分布式锁], 获取锁失败, key:{}, value:{},fullLockKey,lockValue);}returnresult;}OverridepublicbooleanreleaseLock(StringlockKey,StringlockValue){// 1. 补全完整的keyStringfullLockKeyLOCK_PREFIXlockKey;LongresultredisTemplate.execute(redisScript,Collections.singletonList(fullLockKey),lockValue);booleanreleasedresult!nullresult0;if(released){log.info([redis分布式锁], 释放锁成功, key:{}, value:{},fullLockKey,lockValue);}else{log.error([redis分布式锁], 释放锁失败, key:{}, value:{},fullLockKey,lockValue);}returnreleased;}}注意Lua 脚本中的KEYSp[1]为笔误应修正为KEYS[1]否则脚本执行会报语法错误。生产环境建议修正后重新测试。四、使用示例StringlockKeyorder:12345;StringlockValueUUID.randomUUID().toString();booleanlockedlockService.tryLock(lockKey,lockValue,30);if(locked){try{// 业务逻辑}finally{lockService.releaseLock(lockKey,lockValue);// 必须在 finally 中释放}}五、总结本文实现的 Redis 分布式锁通过以下两点严格保证其他客户端无法重复获取锁加锁阶段Redis 单线程 SET NX EX 原子操作确保全局只有一个客户端能成功设置 key。解锁阶段Lua 脚本原子校验 value防止误删他人锁从而维持后续抢锁的互斥性。该方案轻量、高性能适合大多数中型分布式系统使用。相比 Redisson它更透明、更易理解和调试。欢迎关注、收藏、点赞你的支持是我持续输出的动力