{ "topic": "distributed-lock", "type": "short_answer", "schema_version": "1.0.0", "generated": "2026-09-09T21:42:00+08:00", "questions": [ { "id": "sa-001", "type": "short_answer", "difficulty": 3, "tags": [ "distributed-lock", "lock-design" ], "question": "请解释 RedisLockUtil 中 DEFAULT_LOCK_TIMEOUT(10秒)和 DEFAULT_ACQUIRE_TIMEOUT(3秒)两个参数的区别,以及它们分别在什么场景下需要调整。", "answer": "DEFAULT_LOCK_TIMEOUT(10秒)是锁的持有时间上限,即 Redis key 的 TTL。业务必须在此时间内完成操作,否则锁自动释放,可能导致并发问题。如果业务逻辑执行时间较长(如涉及远程调用、大量数据处理),需要适当增大该值。DEFAULT_ACQUIRE_TIMEOUT(3秒)是等待获取锁的最长时间,即客户端自旋等待的上限。在高并发场景下,如果多个客户端竞争同一把锁,超过此时间未获取到就返回失败。如果希望提高请求成功率而非快速失败,可以增大该值,但会增加线程阻塞时间。", "keywords": [ "锁持有时间", "TTL", "锁等待时间", "acquireTimeout", "业务执行时间", "高并发", "自旋等待" ], "scoring_rubric": "满分(5分):准确区分两个超时的含义(1分),说明 lockTimeout 是锁 TTL 自动释放(1分),说明 acquireTimeout 是自旋等待上限(1分),各给出一个调整场景(1分),区分概念清晰无混淆(1分)。混淆两者含义扣3分,只回答一个扣2分。", "explanation": "DEFAULT_LOCK_TIMEOUT(10秒)是锁的持有时间上限,即 Redis key 的 TTL。业务必须在此时间内完成操作,否则锁自动释放,可能导致并发问题。如果业务逻辑执行时间较长(如涉及远程调用、大量数据处理),需要适当增大该值。DEFAULT_ACQUIRE_TIMEOUT(3秒)是等待获取锁的最长时间,即客户端自旋等待的上限。在高并发场景下,如果多个客户端竞争同一把锁,超过此时间未获取到就返回失败。如果希望提高请求成功率而非快速失败,可以增大该值,但会增加线程阻塞时间。" }, { "id": "sa-002", "type": "short_answer", "difficulty": 4, "tags": [ "distributed-lock", "redis-lock" ], "question": "RedisLockUtil 使用 setIfAbsent(SET NX)实现锁的获取。请解释该方案的\"安全性\"(Safety)和\"活性\"(Liveness)分别由什么保证,以及各自的局限是什么。", "answer": "安全性(Safety)——互斥性保证:由 Redis 的 SET NX 原子操作保证。NX 参数确保只有当 key 不存在时才能设置成功,从而保证同一时刻最多只有一个客户端持有锁。局限:在 Redis 主从架构下,主节点写入锁后未同步到从节点就宕机,从节点提升为主后锁丢失,安全性被破坏。活性(Liveness)——最终可获取性保证:由锁的 TTL(lockTimeout)自动过期保证。即使持有锁的客户端崩溃或网络分区,锁最终会过期释放,其他客户端可以获取。局限:如果业务执行时间超过 TTL,锁提前释放,安全性又被打破(活性的保证反而威胁了安全性)。这是一个经典的两难困境,也是 Redisson 引入看门狗(watchdog)自动续期机制的原因。", "keywords": [ "SET NX原子操作", "互斥性", "主从同步", "TTL自动过期", "锁续期", "watchdog", "活性与安全性的权衡" ], "scoring_rubric": "满分(5分):准确解释安全性由 SET NX 保证(1分),说明主从架构下的局限(1分),准确解释活性由 TTL 保证(1分),说明业务超时与安全性的矛盾(1分),提及看门狗/续期机制作为解决方案(1分)。仅回答一半内容扣2分,概念错误扣3分。", "explanation": "安全性(Safety)——互斥性保证:由 Redis 的 SET NX 原子操作保证。NX 参数确保只有当 key 不存在时才能设置成功,从而保证同一时刻最多只有一个客户端持有锁。局限:在 Redis 主从架构下,主节点写入锁后未同步到从节点就宕机,从节点提升为主后锁丢失,安全性被破坏。活性(Liveness)——最终可获取性保证:由锁的 TTL(lockTimeout)自动过期保证。即使持有锁的客户端崩溃或网络分区,锁最终会过期释放,其他客户端可以获取。局限:如果业务执行时间超过 TTL,锁提前释放,安全性又被打破(活性的保证反而威胁了安全性)。这是一个经典的两难困境,也是 Redisson 引入看门狗(watchdog)自动续期机制的原因。" }, { "id": "sa-003", "type": "short_answer", "difficulty": 5, "tags": [ "distributed-lock", "lock-design" ], "question": "如果要将 RedisLockUtil 升级为支持看门狗自动续期和可重入的生产级分布式锁,需要做哪些改造?请从架构设计角度列出至少三项关键改造点并简述实现思路。", "answer": "1. 看门狗自动续期(Watchdog):在后台启动一个定时任务(如每 lockTimeout/3 时间),检查当前线程是否仍持有锁,如果持有则续期(重新 SET EX)。Redisson 的做法是在获取锁成功后启动一个 Netty 时间轮,定时续期,锁释放时取消定时器。2. 可重入锁支持:当前实现不支持可重入。改造思路是用 Hash 结构存储锁信息(field=锁持有者标识,value=重入次数),获取锁时如果已是持有者则 incr 重入计数,解锁时 decr,计数归零才真正删除 key。Lua 脚本需要相应改造以支持重入逻辑。3. 看门狗参数可配置化:当前的 lockTimeout 硬编码为 10 秒,应支持自定义续期间隔、最大续期时间等参数,以适配不同业务场景。4. 公平锁支持:当前实现是非公平锁(先到不一定先得),可引入 Redis 有序集合(Sorted Set)实现 FIFO 队列,按请求时间戳排序获取锁。5. 线程安全优化:移除 ThreadLocal 存储 lockValue 的设计,改为将 lockValue 作为 tryLock 的返回值传递给 unlock,避免线程池复用导致的 lockValue 错乱问题。", "keywords": [ "看门狗watchdog", "自动续期", "可重入锁", "Hash结构", "重入计数", "Lua脚本改造", "公平锁", "Sorted Set", "参数可配置", "ThreadLocal替代" ], "scoring_rubric": "满分(5分):列出至少三项改造点(1分),每项有实现思路描述(每项1分,共3分),至少一项提到 Redisson 作为参考实现(0.5分),回答逻辑清晰、无概念错误(0.5分)。只列改造点无实现思路扣2分,概念错误(如说可重入用 List 实现)扣2分。", "explanation": "1. 看门狗自动续期(Watchdog):在后台启动一个定时任务(如每 lockTimeout/3 时间),检查当前线程是否仍持有锁,如果持有则续期(重新 SET EX)。Redisson 的做法是在获取锁成功后启动一个 Netty 时间轮,定时续期,锁释放时取消定时器。2. 可重入锁支持:当前实现不支持可重入。改造思路是用 Hash 结构存储锁信息(field=锁持有者标识,value=重入次数),获取锁时如果已是持有者则 incr 重入计数,解锁时 decr,计数归零才真正删除 key。Lua 脚本需要相应改造以支持重入逻辑。3. 看门狗参数可配置化:当前的 lockTimeout 硬编码为 10 秒,应支持自定义续期间隔、最大续期时间等参数,以适配不同业务场景。4. 公平锁支持:当前实现是非公平锁(先到不一定先得),可引入 Redis 有序集合(Sorted Set)实现 FIFO 队列,按请求时间戳排序获取锁。5. 线程安全优化:移除 ThreadLocal 存储 lockValue 的设计,改为将 lockValue 作为 tryLock 的返回值传递给 unlock,避免线程池复用导致的 lockValue 错乱问题。" } ] }