1-redis分布式锁简答我们通常使用 Redis 实现分布式锁通过 SETNX EXPIRE 保证原子获取锁同时设置唯一UUID避免误删其他线程锁释放锁时使用 Lua 脚本保证删除操作的原子性。生产项目一般使用 Redisson它封装了锁续期、可重入锁、公平锁等能力。1-1.set nxSET key_name client_id NX PX 30000NX只有 Key 不存在时才设置成功保证互斥。PX 30000设置过期时间为 30 秒防止节点宕机导致死锁。client_id每个客户端生成唯一的随机 ID如 UUID用来标识“谁加的锁”。1-2.Lua脚本-释放锁lua脚本写法取出值然后作比较确定是自己创建自己删ifredis.call(get,KEYS[1])ARGV[1]thenreturnredis.call(del,KEYS[1])elsereturn0end用这个脚本去读取然后判断是不是现在这个方法生成的uuid保证原子性大致代码如下publicvoiddoBusiness(){StringlockKeylock:order:123;StringuuidUUID.randomUUID().toString();// set nx内部的值为uuidBooleansuccessredisTemplate.opsForValue().setIfAbsent(lockKey,uuid,30,TimeUnit.SECONDS);if(Boolean.TRUE.equals(success)){try{// // 业务代码// createOrder();}finally{// 释放锁用lua脚本releaseLock(lockKey,uuid);}}else{thrownewRuntimeException(系统繁忙请稍后重试);}}1-3.Redisson现在有下列情况T0: 业务A执行 SETNX lock key_A EX 10锁10秒过期 T1-T8: 业务A执行中... T10: 锁到期Redis自动删除 key T11: 业务B执行 SETNX lock key_B EX 10 → 成功拿到锁 T12: 业务A终于执行完了执行Lua脚本删除锁也就是业务A时间过长导致锁自动过期删除后续业务B看到没锁了就创建key正好业务A运行完了去释放锁导致业务B的key被删除了我们用lua脚本加上uuid的判断可以规避释放锁// 业务A的代码if(setnx(lock,uuidA,10)){// 业务A以为有锁开始执行// 假设这里执行了15秒...doSomeLongWork();// ← 第10秒时锁已经没了但代码还在跑// 第15秒执行完尝试解锁delScript(lock,uuidA);// 失败因为uuid不匹配}但是A自己的业务在锁过期后还在运行这会影响到数据一致性此时我们需要续期这个时候使用Redisson1-3-2.续期正常情况下我们可以手动续期但是一般企业会规范化使用RedissonpublicvoiddoBusiness(){// 1. 获取锁对象Redisson 的锁RLocklockredissonClient.getLock(lock:order:123);try{// 2. 加锁阻塞等待直到获取到锁lock.lock(30,TimeUnit.SECONDS);// 或者直接 lock()使用默认30秒看门狗// 3. 执行业务createOrder();}catch(Exceptione){// 业务异常处理thrownewRuntimeException(业务执行失败,e);}finally{// 4. 释放锁lock.unlock();}}PS服务器宕机因为redisson内部是隔一段时间就续个期如果服务器宕机了那么这个锁到期了也会释放锁不会永久存在业务超时卡死业务代码卡死导致锁一直没释放此时可以通过设置锁的最大时间规避或者设置接口时间等等