Yihui’s Blog

如何为Redis分布式锁设置合理的超时时间?

日期:2026-09-27
标签:#面试 #场景设计 #Redis
难度:中等
来源:牛面场景题
答案说明:独立整理(站内题目标记为 VIP,未读取会员答案)

一句话答案

租约应覆盖可预期的执行、暂停与网络抖动,同时限制故障后的等待;没有可靠耗时上界时用有身份校验的受控续期,并在业务资源侧防止旧执行者写入。

面试口语版(约 60 秒)

我不会套固定秒数。先采集从获锁到最后一次受保护写入的耗时分布,拆出数据库、外部调用、重试、进程暂停和网络抖动,再结合故障恢复能等待多久设初始 TTL。TTL 太短,A 还未完成就过期,B 会进入;太长,A 宕机后 B 等待较久。长任务若需续期,必须在 Redis 中原子比对本次令牌并延长过期时间,且设置业务总超时和停止条件。即使有续期,长时间暂停、网络分区或切主仍可能让旧执行者失去锁;严格顺序的关键写入还要让权威资源校验单调栅栏令牌,普通版本检查不一定足够。

如何确定与验证

  1. 测量:统计完整持锁时长,不只测函数本体;包含依赖调用、重试及异常清理。演练尾部延迟和暂停。
  2. 取舍:在业务可接受的故障等待上限内覆盖正常耗时及合理余量。若两者无法兼顾,拆小工作段、缩短依赖超时,或受控续期。不存在通用的最佳 TTL。
  3. 续期:任务仍在运行且令牌匹配时,用原子脚本执行 PEXPIRE;失败、超时或结果不确定时停止新增工作,重新确认所有权。不能盲目或无限续期。
  4. 验证:模拟进程崩溃、Redis 不可达、外部调用卡住与进程暂停,检查重复执行及下游拒绝旧写入的效果。
on_acquired(key, token, lease, business_deadline, business_task):
    start business_task and renewal_watchdog concurrently
    renewal_watchdog:
        while business_task is running and before_business_deadline:
            wait_until(next_renewal_time)  # 定时等待,不忙循环
            if business_task is finished: break
            result = atomic_if_token_matches_then_pexpire(key, token, lease)
            if result != success:
                mark_lock_lost()
                cancel_remaining_work()
                break
    try:
        wait for business_task to finish or be cancelled
    finally:
        stop and join renewal_watchdog
        atomic_if_token_matches_then_delete(key, token)

伪代码中的提前量、总时长及续期次数需按实际延迟决定。条件删除只避免误删新锁,不能撤销已经写出的副作用。

失败分支与取舍

A 获锁后调用第三方接口,进程暂停超过租约;B 获锁并完成更新;A 恢复继续写库。即使 A 此时续期失败,旧写仍可能落地。严格按获锁顺序保护的关键状态应由权威资源比较单调栅栏令牌;普通行版本条件可以防丢失更新,却不保证在 B 尚未写入时拒绝 A。栅栏生成源本身也必须保证单调。

  • 短租约恢复快,但更易误过期;长租约相反。
  • 续期减少正常长任务误过期,却增加定时器、网络与停止逻辑的复杂度,不能证明无限期持有锁。
  • 观察持锁时长分布、剩余 TTL、续期失败、任务超租约、获取等待和业务版本冲突。

面试官递进追问

  1. 为什么不能把 TTL 直接设为接口平均耗时?
  2. 续期请求超时但 Redis 实际执行成功,如何处理结果不确定?
  3. 旧执行者丢锁后仍写数据库,数据库如何识别并拒绝?

自测

  • 不看笔记,60 秒讲清短租约、长租约、续期的代价。
  • 为含外部 RPC 的任务列出要采集的时间数据和要演练的故障。

参考资料

资料核对日期:2026-09-27。

Maintained by · YihuiEdit on GitHub

Keep reading

View all posts

怎么用Redis实现可重入的分布式锁?

日期:2026-09-27 标签:#面试 #场景设计 #Redis 难度:中等 来源:牛面场景题 答案说明:独立整理(站内题目标记为 VIP,未读取会员答案) 一句话答案 为同一把锁保存“本次最外层获锁的唯一令牌 + 重入次数 + 租约”;嵌套调用共享该令牌并原子递增,释放时递减,次数归零才删除。新一轮独立获锁必…

Read article

基于 Redis 实现分布式锁有什么优缺点?

日期:2026-09-27 标签:#面试 #场景设计 #Redis 难度:简单 来源:牛面场景题 答案说明:独立整理(站内题目标记为 VIP,未读取会员答案) 一句话答案 Redis 锁接入简单、响应快,适合容忍少量故障窗口内重复执行的任务;租约过期与主从切换可能破坏互斥,关键写入还须在资源侧拒绝旧持有者。 面试…

Read article

MySQL主从复制有哪些延迟问题?如何解决数据延迟?

日期:2026-09-27 标签:#面试 #场景设计 #MySQL 难度:中等 来源:牛面场景题 答案说明:独立整理(站内题目标记为 VIP,未读取会员答案) 一句话答案 复制延迟要区分源库产生 binlog、从库接收 relay log 和从库回放提交三个阶段;先找到积压位置,再分别治理写入峰值、网络或回放瓶颈…

Read article