[TOC] #### 1. 前言 --- 你有 10 台服务器,每台都能处理订单,用户下单的时候要扣库存 如果两台服务器同时读到库存是 1,同时扣减,都写回 0,结果卖了两件,但库存只减了一个,超卖了 怎么办 ?需要一把锁,同一时间只让一台服务器操作库存 单机环境下用 Java 的 synchronized 就行,但分布式环境下,多台机器需要一把 “大家都能看到的锁” Redis 就是干这个的 #### 2. 基础用法 --- NX = key 不存在才设置(抢锁成功),EX 30 = 30 秒自动过期(防止死锁) ```plaintext set lock:order:1001 1 NX EX 30 ``` 用完删除: ```bash del lock:order:1001 ``` 但有问题 A 拿到锁,执行超过 30 秒,锁自动过期了 B 拿到锁,A 执行完了,把 B 的锁删了 你的锁被别人删了,这就不安全了 #### 3. 加唯一标识 --- 每个请求生成一个 UUID,存到锁的 value 里: ```plaintext set lock:order:1001 uuid_001 NX EX 30 ``` 释放的时候先检查是不是自己的锁: ```lua if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("del", KEYS[1]) else return 0 end ``` 用 Lua 脚本保证 “判断 + 删除” 是原子操作 为什么不能分两步 ? 因为 get 和 del 之间有时间差,可能锁已经过期被别人拿走了 #### 4. 锁续期 --- 30 秒过期但任务执行了 40 秒怎么办 ? 看门狗机制:后台线程每隔 10 秒检查锁还在不在,在就续期 30 秒。 Java 项目直接用 Redisson,这些都帮你搞定了: ```java RLock lock = redissonClient.getLock("order:1001"); try { lock.lock(30, TimeUnit.SECONDS); // 业务逻辑 } finally { lock.unlock(); } ``` 原理要知道,但实际项目别自己手撸 #### 5. 本文小结 --- 小总结: + 基础版:set NX EX + del + 必须加唯一标识,Lua 脚本释放 + 锁续期用看门狗,Java 用 Redisson + 原理要懂,面试会问