Yihui’s Blog

实现分布式单例对象

日期:2026-07-11
标签:#面试 #八股 #后端 #系统设计 #场景题

一句话答案

分布式环境无法靠 JVM 单例保证全局唯一,通常用选主或带租约的分布式锁确保同一时刻只有一个活动实例,并用 fencing token 防止旧实例继续写入。

面试口语版

我会先确认真正需求通常是“只有一个实例执行任务”,而不是“内存里只有一个对象”。可以用 ZooKeeper/etcd 临时节点选主,或使用带 TTL 的分布式锁。实例获得领导权后定期续租,失去会话或续租失败就立即停止对外执行。仅靠锁仍有 GC 暂停导致锁过期的问题,所以每次获得领导权都生成单调递增 fencing token,下游只接受更大 token 的写入,从而拒绝旧 Leader。

关键细节

  • 单例对象本身无法跨进程共享,应该共享状态或保证单活执行。
  • CP 协调系统更适合选主;Redis 锁需正确处理过期、续租和故障模型。
  • 业务必须能容忍短暂双主,或由存储层基于 token 拒绝旧主写入。
  • 读请求可多活,只有写或调度职责需要单活,避免无谓牺牲可用性。

面试官追问

  1. GC 停顿超过租约会怎样?
  2. 什么是 fencing token?
  3. 网络分区时如何避免双主?

面试官追问参考答案

1. GC 停顿超过租约会怎样?

实例暂停期间无法续租,协调系统会让租约过期并选出新 Leader;旧实例恢复后可能误以为自己仍是主,形成短暂双主。因此恢复后必须重新确认租约,并让下游用 fencing token 拒绝旧实例写入。

2. 什么是 fencing token?

每次成功获得领导权或锁时,由协调系统返回单调递增的令牌。写请求携带 token,下游只接受大于已见最大值的请求;即使旧持有者因暂停后恢复,它的较小 token 也会被拒绝。

3. 网络分区时如何避免双主?

使用基于多数派的 CP 协调系统,只有能联系多数节点的一侧可以续租或当选,少数派停止写。业务下游还应验证 Epoch/fencing token;如果系统选择 AP,就无法同时严格避免双主,必须接受冲突并设计合并。

Maintained by · YihuiEdit on GitHub

Keep reading

View all posts