Files
examination/topics/thumbup/distributed-lock/short_answer.json
T

77 lines
8.1 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"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 错乱问题。"
}
]
}