面试级「分布式 ID 设计方案」

目标 → 主流方案 → 对比 → 实战选型 → 源码级思想,适合 P6~P7 / 架构岗,可以直接背,也可以当系统设计题来答。


一、分布式 ID 的设计目标(面试开场)

分布式 ID 是跨服务、跨库、跨机器的唯一标识,设计时要满足:

全局唯一(最基本)

趋势递增(MySQL B+Tree 友好)

高性能(高并发下不成为瓶颈)

高可用(不能依赖单点)

易接入(业务无感)

可解析(排查问题方便)


二、常见分布式 ID 方案总览

方案

唯一性

递增

性能

复杂度

推荐指数

UUID

⭐⭐

数据库自增

⭐⭐

数据库号段

⭐⭐

⭐⭐⭐⭐

Redis 自增

⭐⭐

⭐⭐⭐

Snowflake

✅✅

⭐⭐⭐

⭐⭐⭐⭐⭐

Leaf / TinyID

✅✅

⭐⭐⭐⭐

⭐⭐⭐⭐⭐


三、主流方案详解(重点)


1️⃣ UUID(不推荐)

UUID.randomUUID().toString();

优点

✅ 简单

✅ 无网络开销

✅ 本地生成

缺点(致命)

无序​ → MySQL 页分裂

❌ 太长(36 位字符串)

❌ 无业务含义

❌ 不易排查问题

👉 结论:只适合临时标识,不适合业务 ID


2️⃣ 数据库自增 ID(单机 OK)

CREATE TABLE order (
  id BIGINT AUTO_INCREMENT PRIMARY KEY
);

优点

✅ 简单

✅ 严格递增

缺点

❌ 单点

❌ 性能瓶颈

❌ 分库分表困难

👉 结论:单体系统可用,分布式不行


3️⃣ 数据库号段模式(推荐)

本质是:批量取号,内存发号

原理

DB 只存最大值
每次取 1000 个号
缓存在内存中
用完再取

表结构

CREATE TABLE id_segment (
  biz_tag VARCHAR(32) PRIMARY KEY,
  max_id BIGINT,
  step INT
);

发号逻辑

update id_segment
set max_id = max_id + step
where biz_tag = 'order';

优点

✅ 高性能

✅ 趋势递增

✅ 弱依赖 DB

缺点

❌ 依赖 DB

❌ 重启可能浪费 ID

中小规模系统非常合适


4️⃣ Redis 自增(简单但有限)

INCR order:id

优点

✅ 快

✅ 简单

✅ 原子性

缺点

❌ Redis 宕机风险

❌ 重启可能重复(需持久化)

❌ 无时间戳信息

👉 适合非核心业务


5️⃣ Snowflake(最主流 ⭐⭐⭐⭐⭐)

Twitter 开源,工业级方案

ID 结构(64 bit)

| 1 bit | 41 bit 时间戳 | 10 bit 机器ID | 12 bit 序列号 |
0 | 0000000000000000000000000000000000000 | 0000000000 | 000000000000

各部分含义

位段

长度

说明

符号位

1

固定 0

时间戳

41

毫秒级

机器 ID

10

数据中心 + 工作节点

序列号

12

同一毫秒内自增

特点

趋势递增

本地生成

高性能

无依赖

问题点(面试必问)

问题

解决方案

时钟回拨

等待 / 抛异常 / 用上次时间

机器 ID 分配

Zookeeper / 配置中心

序列号耗尽

等到下一毫秒


Snowflake 代码示例(精简版)

public class SnowflakeIdGenerator {

    private final long workerId;
    private final long epoch = 1700000000000L;
    private long sequence = 0L;
    private long lastTimestamp = -1L;

    public SnowflakeIdGenerator(long workerId) {
        this.workerId = workerId;
    }

    public synchronized long nextId() {
        long timestamp = System.currentTimeMillis();

        if (timestamp < lastTimestamp) {
            throw new RuntimeException("时钟回拨");
        }

        if (timestamp == lastTimestamp) {
            sequence = (sequence + 1) & 4095;
            if (sequence == 0) {
                timestamp = waitNextMillis(timestamp);
            }
        } else {
            sequence = 0;
        }

        lastTimestamp = timestamp;

        return ((timestamp - epoch) << 22)
                | (workerId << 12)
                | sequence;
    }

    private long waitNextMillis(long timestamp) {
        while (timestamp <= lastTimestamp) {
            timestamp = System.currentTimeMillis();
        }
        return timestamp;
    }
}

6️⃣ 号段模式增强版:Leaf / TinyID(大厂方案)

核心思想

DB + 缓存 + 双 Buffer

  • 一个号段快用完时
  • 异步加载下一个号段
  • 无阻塞切换

美团 Leaf、滴滴 TinyID 都是这个思路

👉 适合高并发、核心业务


四、方案选型建议(面试总结用)

场景

推荐方案

单体系统

数据库自增

中小规模

数据库号段

高并发核心

Snowflake

大厂级

Leaf / TinyID

非核心业务

Redis / UUID


五、面试 5 分钟口述版(直接背)

面试官:如何设计分布式 ID?

参考回答:

分布式 ID 的核心目标是全局唯一、趋势递增、高性能和高可用。常见方案有 UUID、数据库自增、数据库号段、Redis 自增和 Snowflake。

UUID 虽然简单,但无序且太长,不适合作为数据库主键;数据库自增在分库分表场景下会成为瓶颈;数据库号段模式通过批量取号、内存发号,性能和可用性都不错,适合中小规模系统;Redis 自增依赖 Redis 的可用性,适合非核心业务。

目前最主流的是 Snowflake 算法,它利用时间戳、机器 ID 和序列号生成 64 位 Long 型 ID,趋势递增、本地生成、性能非常高,是 Twitter 开源的工业级方案。实际使用时会遇到时钟回拨问题,可以通过等待或异常方式处理,机器 ID 可以通过 Zookeeper 或配置中心分配。

在大规模场景下,像美团 Leaf、滴滴 TinyID 这样的号段增强方案,通过双 Buffer 预加载,进一步提升了稳定性和性能。

实际选型时,我会根据业务规模和一致性要求来决定,核心业务优先 Snowflake 或 Leaf,非核心业务可以考虑 Redis 或号段模式。


六、一句话总结(收尾金句)

“分布式 ID 没有万能方案,核心是在唯一性、性能和可维护性之间做权衡,Snowflake 是目前最成熟、最通用的选择。”


七、面试官常追问 & 标准答法

追问

回答

Snowflake 时钟回拨怎么办?

等待 / 抛异常 / 使用上次时间

机器 ID 怎么分配?

Zookeeper / 配置中心 / 启动时分配

为什么 ID 要趋势递增?

减少 MySQL 页分裂

号段模式浪费 ID 怎么办?

可接受,用可维护性换性能

分布式 ID 能包含业务信息吗?

可以,但不建议,ID 应解耦业务

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值