假设你是一座大型演唱会票务中心的总负责人。开票瞬间,全城几十个售票窗口同时开售,每张票都要一个全球唯一的票号——不能两张票重号,票号还要好记、好找,方便观众按座位区快速入场。更麻烦的是,高峰期每秒涌入百万级请求,任何一个窗口都不能成为瓶颈。这就是分布式系统的“取号难题”。 解决思路有两条路。一条路是给每张票随机生成超长字符串,比如“F7A2-9C4B-8D01-3E56“,几乎不可能重复,但票号毫无顺序,观众进场得全场乱找;另一条路是把票号拆成”开票时刻 + 售票窗口号 + 每秒流水号”三段拼接,既保证唯一,又天然按时间递增,观众按号找座又快又顺。前一条路就是 UUID,后一条路就是 Snowflake。 本文用“售票大厅”这个比喻贯穿始终,把两者的生成原理、存储开销、索引友好度和适用场景讲透,帮你为业务挑选合适的那张“票”。

岗位关联

分布式ID是后端与基础设施工程师绕不开的经典选型题。理解 Snowflake 与 UUID 的底层差异,能帮你避开主键性能灾难,属于“面试高频、上线必备”的核心知识。

目录
  1. 可视化演示
  2. ID生成挑战:为什么自增主键不够用
  3. UUID原理:掷骰子出票的利与弊
  4. Snowflake原理:时间+窗口+流水三段拼票号
  5. 存储与索引:票号长短的代价
  6. 选型决策:该发哪一种票
  7. 生产实践:时钟回拨等翻车现场
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

展示Snowflake位结构生成流程、UUID 128位生成机制及两种方案多维度性能对比的三模态交互动画。

本节配有交互动效(进入视口后自动加载,约 3KB)。

Snowflake位结构 时间戳 机器ID ID=TS|WID|SEQ Snowflake由时间戳机器ID和序列号组成64位趋势递增全局唯一ID

ID生成挑战:为什么自增主键不够用

假设演唱会票务中心只有一台取号机,所有售票窗口都去那里取号。排队的人越聚越多,取号机成了全场最大瓶颈;更麻烦的是,一旦票务中心扩建、增设第二台取号机,两台机器各自从 1 开始出号,就会同时出现两张"000001"号票,观众拿着它根本不知道坐哪儿。

数据库自增主键就是那台“唯一的取号机”。单机数据库里它简单可靠,但一旦分库分表、水平扩展,每个库各自维护自增计数器,必然产生重复 ID。分布式系统需要一套“让所有节点各自取号、又不重号”的方案,这就引出了全局唯一 ID 的三个核心诉求:全局唯一、高性能、趋势递增。全局唯一是底线;高性能指生成操作要在毫秒级完成,能扛住开票瞬间的百万级峰值;趋势递增则让 ID 大小随创建时间单调增长,方便排序、分页与数据库索引。

这三个诉求可以用一个简单公式理解:系统在一段时间里需要生成多少 ID,取决于请求速率乘以持续时间。

把“取号机”拆到每个售票窗口,让各窗口用一个约定好的规则自己算号,就同时解决了“唯一”和“性能”两个问题。这正是 Snowflake 与 UUID 的共同起点,只是两家“算号规则”完全不同。

N=R×TN = R \times T
这个公式说明,分布式 ID 方案必须先估算“要发多少张票”,才能决定 ID 空间够不够大。
  1. 符号定义$N$ 表示一段时间内需要生成的 ID 总量,$R$ 是平均每秒请求数,$T$ 是持续运行的秒数。
    N=R×TN = R \times T
  2. 数量级推算以每秒 1 万次请求、持续运行一年为例,可以算出需要支持约 3150 亿个 ID。
    104×86400×365≈3.15×101110^4 \times 86400 \times 365 \approx 3.15 \times 10^{11}

UUID原理:掷骰子出票的利与弊

有些演出不要求连号,售票系统干脆给每张票掷一遍 128 个“骰子”,掷出一串随机票号,比如 "F7A2-9C4B-8D01-3E56"。只要骰子数量足够多,全世界所有售票系统同时开票,也几乎不可能掷出两张完全相同的号码。

这就是 UUID 的核心思路——用足够大的随机空间换取“无需协调的唯一”。UUID 标准共 128 位,v4 版本将其中 122 位交给随机数,剩下 6 位标记版本与变体。任何一台机器只要按格式拼好随机位,就能独立生成 ID,不需要请求任何中心节点,本地生成速度极快。

UUID 最大的优点是零协调成本、实现极其简单;最大的缺点则是完全不关心顺序。它在时间轴上随机跳动,没有递增关系,以字符串形式存储需要 36 个字符(含连接符),对应二进制 16 字节。在“只需唯一、不需排序”的场景下,它是非常优秀的选择。

那么它到底有多不容易重复?可以用生日悖论的碰撞概率公式来感受。

掷骰子票虽然不会重号,但观众入场时想按“连号座位区”快速找座就会抓狂——这正是随机主键在数据库索引上遇到的困境:唯一性解决了,有序性却彻底丢了。

P≈n22×2122P \approx \frac{n^2}{2 \times 2^{122}}
当已生成的 UUID 数量为 $n$ 时,发生一次碰撞的概率约等于上式。$n$ 不到万亿量级时,概率几乎可以忽略。
  1. 随机空间大小UUID v4 使用 122 位随机数,$2 \times 2^{122} = 2^{123}$ 是碰撞概率公式中的近似分母。
    2×2122=21232 \times 2^{122} = 2^{123}
  2. 碰撞概率$n$ 是已经生成的 UUID 数量,$n$ 越大、概率越高,但常规业务量下 $n$ 远不足以引发碰撞。
    P≈n22123P \approx \frac{n^2}{2^{123}}

Snowflake原理:时间+窗口+流水三段拼票号

如果票务中心规定票号由三部分组成:开票时刻、售票窗口编号、该窗口这一秒内的流水号,那么同一时刻不同窗口、同一窗口不同时刻、同一时刻同一窗口不同流水,三管齐下就能保证全场唯一,而且票号天然连号、整体随时间递增。

Snowflake 正是这个思路,由 Twitter 提出,用一个 64 位整数承载信息:第 1 位符号位固定为 0,接下来 41 位存毫秒时间戳(相对自定义纪元),10 位存机器码,最后 12 位存序列号。它表达的语义是“哪个时刻、哪台窗口、第几个号”。因为时间戳占 41 位,整体可用约 69.7 年;机器码 10 位支持 1024 台机器同时发号;每台机器每毫秒内序列号从 0 到 4095,共 4096 个。若某毫秒请求超过 4096,就阻塞到下一毫秒。

生成的 ID 整体随现实时间推进而变大,因此对数据库主键索引极其友好——新 ID 总是落在索引“末尾”。三段如何拼成一个整数,可以用一个位运算公式表示。

三段式票号让“售票窗口”只需知道自己是谁、当前几点、发到第几张,就能独立算出全局唯一的连号票。相比掷骰子,它把“唯一”从概率事件变成了构造事件。

id=(t−t0)×222+m×212+sid = (t - t_0) \times 2^{22} + m \times 2^{12} + s
$t$ 是当前毫秒时间,$t_0$ 是自定义纪元起点,$m$ 是 10 位机器码,$s$ 是 12 位序列号。乘上 $2^{22}$ 和 $2^{12}$ 等价于把各段“左移”到互不重叠的位上。
  1. 符号说明$t$ 和 $t_0$ 的差值代表从纪元起经过的毫秒数,$m$ 是机器码,$s$ 是序列号。
    t,  t0,  m,  st,\; t_0,\; m,\; s
  2. 移位含义$(t - t_0) \times 2^{22}$ 等价于把时间戳左移 22 位,为机器码和序列号腾出空间。
    (t−t0)×222(t - t_0) \times 2^{22}
  3. 拼装结果三部分在二进制位上互不重叠,按位相加就得到最终的 64 位 ID。
    +m×212+s+ m \times 2^{12} + s

存储与索引:票号长短的代价

短票号“07-000123“写在登记簿上很省纸,查询时一页能多看几行;超长随机票号”F7A2-9C4B-8D01-3E56“不仅占格子,还让登记簿被写得很”碎”。数据库主键也是同样的道理。

落到 B+ 树索引里,主键长度直接影响每个叶子页能容纳多少索引项。Snowflake 是 64 位整数,占 8 字节;UUID 是 128 位,占 16 字节。同样的 16KB 叶子页,前者大约能比后者多装近一倍的记录,磁盘 IO 和缓存命中率都更优。更关键的差异在写入模式:Snowflake 的 ID 连续追加,B+ 树只需在“最右侧”插入,页分裂极少;UUID 的值随机分布,新记录散落各页,频繁触发页分裂并留下碎片,写入放大严重。这就是“随机主键拖垮 InnoDB”的经典问题。

每页能装多少行,本质上由主键长度与指针长度共同决定。

连号票让登记簿按顺序写满一页再开下一页,而随机票让每一页都被“零散插空”。对数据库而言,顺序追加和随机散落的性能差异,会在写入量放大后彻底显现。

K行/页=⌊16 KiBLid+L指针⌋K_{\text{行/页}} = \left\lfloor \frac{16 \text{ KiB}}{L_{\text{id}} + L_{\text{指针}}} \right\rfloor
$K_{\text{行/页}}$ 是每个叶子页大约能容纳的记录数,$L_{\text{id}}$ 是主键占用的字节数,$L_{\text{指针}}$ 是页内指针占用的字节数。主键越短,页能装的行越多。
  1. 符号含义$K_{\text{行/页}}$ 表示每个 B+ 树叶子页可容纳的记录行数,$L_{\text{id}}$ 是主键字节数,$L_{\text{指针}}$ 是页内指针字节数。
    K行/页=⌊16 KiBLid+L指针⌋K_{\text{行/页}} = \left\lfloor \frac{16 \text{ KiB}}{L_{\text{id}} + L_{\text{指针}}} \right\rfloor
  2. 代入对比同样 16KiB 页下,8 字节主键与 16 字节主键的行容量相差接近一半。
    Lid=8 BvsLid=16 BL_{\text{id}} = 8 \text{ B} \quad \text{vs} \quad L_{\text{id}} = 16 \text{ B}

选型决策:该发哪一种票

小剧场只有几百个座位,随便编号也无妨;几万人的体育场演唱会,观众必须按号段快速入场,就必须连号。发多少票、观众怎么找座位,决定了用哪种票号方案。

选择 Snowflake 还是 UUID,本质是在“有序性、长度、安全性与协调成本”之间取舍。若业务主键需要按时间范围扫描、趋势递增,选 Snowflake;若客户端需要离线生成 ID、无法接受集中协调,选 UUID。举例来说,订单、流水、消息这类高频写入且经常按时间查询的数据,优先 Snowflake;日志追踪 ID、离线数据打标这类只求唯一不求顺序的场景,UUID 更省事。如果担心 ID 被遍历猜出业务量,随机 UUID 更安全,因为 Snowflake 的 ID 包含时间戳,可被反推生成时刻。

另一个需要关注的硬指标是方案的理论寿命,Snowflake 的时间戳段是 41 位,能用的年限可以精确计算。

发哪一种票,取决于“观众怎么入场”。对在线业务来说,连号票让数据索引、范围查询都受益;对离线、去中心化场景来说,随机票的零协调成本更加宝贵。没有绝对更好的方案,只有更匹配的取舍。

Tmax⁡=2411000×86400×365≈69.7T_{\max} = \frac{2^{41}}{1000 \times 86400 \times 365} \approx 69.7
$T_{\max}$ 表示从自定义纪元起,Snowflake 方案理论上能使用的最大年数。超过这个年限,41 位时间戳就会溢出。
  1. 总毫秒数41 位无符号整数最多表示 $2^{41}$ 毫秒。
    241≈2.2×10122^{41} \approx 2.2 \times 10^{12}
  2. 单位换算除以毫秒换算到秒、天、年的系数,得到可用年限。
    1000×86400×365≈3.15×10101000 \times 86400 \times 365 \approx 3.15 \times 10^{10}
  3. 结果约 69.7 年,因此大多数系统在自定义纪元上预留足够余量即可放心使用。
    Tmax⁡≈69.7T_{\max} \approx 69.7

生产实践:时钟回拨等翻车现场

售票大厅墙上的石英钟如果被调慢了几秒,按“开票时刻”拼出来的票号就可能和先前重复,整个系统会出现两张同号票。聪明的系统会监控时钟变化,发现钟往回走时暂停放票,或启用备用号段救场。

Snowflake 的生产落地,重点要处理三类问题:时钟回拨、机器码分配、序列号溢出与高可用。时钟回拨源于 NTP 校时,会导致同一台机器在“已过去的时间戳”上重新发号,从而产生重复 ID。常见策略包括:检测到回拨后等待本地时钟追平再发号;用扩展序列号段或保留最后一次时间戳强制递增;把发号收敛到独立服务(如美团的 Leaf 等)统一管理。机器码则需要通过注册中心统一下发,避免多台机器使用了相同的 10 位机器码。

判断时钟是否回拨,本质是比较“本次生成时刻”与“上次生成时刻”的差值。

一场成功的演唱会,除了票号规则设计得好,还要预防“钟表坏了”这类意外。生产环境的 Snowflake 正是靠回拨检测、机器码管理和独立发号服务,才把工程风险一点点磨平。

Δt=tnow−tlast,状态={正常发号Δt≥0回拨处理Δt<0\Delta t = t_{\text{now}} - t_{\text{last}}, \quad\text{状态} = \begin{cases} \text{正常发号} & \Delta t \ge 0 \\ \text{回拨处理} & \Delta t < 0 \end{cases}
$\Delta t$ 是本次与上次生成 ID 的时间差。差值为负表示时钟后退,必须进入回拨处理分支,否则会复用历史时间戳,生成重复 ID。
  1. 定义差值$\Delta t$ 为当前时刻减去上一次生成 ID 的时刻。
    Δt=tnow−tlast\Delta t = t_{\text{now}} - t_{\text{last}}
  2. 判断状态当 $\Delta t \ge 0$ 时时间正常,按原逻辑发号;当 $\Delta t < 0$ 时说明时钟回拨,需要触发等待、备用段或拒绝发号等兜底策略。
    {正常发号Δt≥0回拨处理Δt<0\begin{cases} \text{正常发号} & \Delta t \ge 0 \\ \text{回拨处理} & \Delta t < 0 \end{cases}

AI 应用场景

推荐系统样本ID生成

阶段:数据清洗与存储

解决的问题:训练样本表需要全局唯一的 sample_id,同时要按时间回溯最近 N 天的样本。传统自增主键在分库分表后必然重复;使用 Snowflake 后,ID 不仅能全局唯一,还能按 ID 范围快速筛出最新样本,天然支持“时间窗抽样”。

具体案例:某推荐算法平台的样本以“用户 + 物品 + 时间 + 特征向量”为行,每天写入量数亿,读侧重“最近 7 天数据”。平台用 Snowflake 生成 sample_id 后,按 ID 排序等同按时间排序,离线回放和在线增量训练都提速明显。

LLM推理链路追踪

阶段:监控与可观测性

解决的问题:一次大模型推理请求会跨多个微服务,需要 trace_id 串联所有日志。若由网关统一发号,网关成为瓶颈且可能单点故障;改用 UUID 后在每个服务本地生成,零协调成本、全球唯一,非常适合日志聚合与问题排查。

具体案例:一个 RAG 问答系统,从网关到向量检索、LLM 服务、日志平台,每次请求生成一个 UUID 作为 trace_id,各服务把日志写到同一 ID 下,排障时直接检索该 ID 即可看到完整调用链。

特征版本号生成

阶段:特征工程

解决的问题:离线特征任务并行跑在几十台机器上,每个版本需要一个唯一编号。若用 Snowflake,需要解决机器码分配和时钟回拨等额外成本;用 UUID 直接从任务节点本地生成,写入元数据中心即可,简单可靠。

具体案例:某特征平台每天凌晨启动 50 个并行任务,每个任务产出一批特征文件,任务级 ID 用 UUID 生成并登记在元数据中心,后续追溯和回滚只凭 ID 即可定位。

Python 演示

python42 行
import timeimport uuid  class SimpleSnowflake:    """简化版 Snowflake: 41位时间戳 + 10位机器码 + 12位序列号"""     def __init__(self, machine_id, epoch_ms=1700000000000):        if not (0 <= machine_id < 1024):            raise ValueError("machine_id must be in [0, 1024)")        self.machine_id = machine_id        self.epoch_ms = epoch_ms        self._seq = 0        self._last_ms = -1     def next_id(self):        now_ms = int(time.time() * 1000)        if now_ms < self._last_ms:            raise RuntimeError("clock moved backwards, refuse to issue id")        if now_ms == self._last_ms:            self._seq = (self._seq + 1) % 4096            if self._seq == 0:                while now_ms <= self._last_ms:                    now_ms = int(time.time() * 1000)        else:            self._seq = 0            self._last_ms = now_ms        return ((now_ms - self.epoch_ms) << 22) | (self.machine_id << 12) | self._seq  def main():    sf = SimpleSnowflake(machine_id=7)    ids = [sf.next_id() for _ in range(2000)]    print("Snowflake 2000 ids, unique count:", len(set(ids)))    print("strictly increasing:", all(ids[i] < ids[i + 1] for i in range(len(ids) - 1)))    uuids = [uuid.uuid4() for _ in range(2000)]    print("UUID 2000 ids, unique count:", len(set(uuids)))    print("memory: snowflake", len(ids) * 8, "bytes; uuid", len(uuids) * 16, "bytes")  if __name__ == "__main__":    main()
目的:用 Python 实现一个简化版 Snowflake 生成器,并与 UUID 对比唯一性、递增性与内存占用,直观感受两种方案的差异。
  1. if now_ms < self._last_ms:检测时钟回拨,发现时间倒退直接拒绝发号,避免重复。
  2. if now_ms == self._last_ms:同一毫秒内请求到达时,走序列号递增分支。
  3. self._seq = (self._seq + 1) % 4096序列号在 0~4095 之间循环,对应 12 位容量。
  4. return ((now_ms - self.epoch_ms) << 22) | (self.machine_id << 12) | self._seq把时间戳、机器码、序列号按位拼装成 64 位整数。
  5. len(set(ids))用集合去重验证生成 2000 个 ID 是否唯一。
  6. uuid.uuid4()调用标准库生成一个随机 UUID。

常见误区

误区网上都说 UUID 是“全球唯一”,所以写代码时完全放心,觉得它绝对不可能出现两个相同的值。

正解UUID 的“唯一”是概率意义上的唯一。v4 用 122 位随机数,碰撞概率极低,但理论上仍可能重复。可以类比“掷 122 个骰子”:虽然连续两次掷出完全一样序列的概率微乎其微,却不是数学上的不可能。在极端海量数据或恶意攻击场景下,仍需要评估风险。

为何常见:几乎所有资料都在强调“无需协调、全球唯一”,省略了“概率”二字,读者容易把高概率事件理解为必然事件。

误区既然 Snowflake 里有时间戳,那后生成的 ID 一定比先生成的大,就像数据库自增主键一样。

正解Snowflake 只保证趋势递增,不保证严格递增。不同机器的时钟存在偏差,早发生的请求可能生成更大的 ID;同一毫秒内的多个请求则靠序列号排序。它适合“按时间排序友好”,但不要用 ID 大小作为事件因果或严格时间序的判据。

为何常见:人们看到时间戳占主导,就直觉以为 ID 就是时间,忽略了机器码和序列号对顺序的干扰。

误区听说“随机主键会导致页分裂、性能差”,于是所有 UUID 主键都被一票否决。

正解随机 UUID 在“频繁插入、大数据量”场景下确实不友好,但在只读表、离线数仓、日志表或写入量很小的表里完全可用;UUID 的新版本(如 UUIDv7)加入了时间戳前缀,也能获得趋势递增特性。选型要看具体写入模式,不能一刀切。

为何常见:技术文章为了强调 Snowflake 的优势,常把 UUID 描述成“数据库毒药”,忽略了场景边界。

误区12 位序列号不够用了就等下一毫秒,那只要时钟一直在走,永远出得完号,不会有问题。

正解等待下一毫秒的前提是时间戳单调前进。一旦本地时钟回拨,时间戳会退回到已用过的区间,再等也只是“回到过去”,重复风险就来了。所以生产环境必须加回拨检测、保留上次时间戳或用备用序列号段兜底,否则高并发下可能静默产生重复 ID。

为何常见:很多讲解只演示了序列号溢出后的“等待”逻辑,没把时钟回拨作为前提讲清楚,学习者会误以为序列号循环能覆盖所有异常。

面试题

Q1. Snowflake 的 64 位二进制中,不包含下列哪一段?

单选题 · easy

  • A.41 位毫秒时间戳
  • B.10 位机器码标识
  • C.12 位序列号计数
  • D.8 位循环冗余校验码← 正确答案

答案:D。Snowflake 的 64 位由 1 位符号位、41 位时间戳、10 位机器码和 12 位序列号组成,不包含校验码。就像演唱会票号只有“时刻、窗口、流水”三段,没有额外防伪位。

Q2. UUID 标准形式的二进制位数是多少?

单选题 · easy

  • A.32 位二进制
  • B.64 位二进制
  • C.128 位二进制← 正确答案
  • D.256 位二进制

答案:C。UUID 是 128 位标准格式,对应 16 字节。它比 Snowflake 的 64 位长一倍,这也是它在存储和索引上更“重”的根本原因。

Q3. 同一毫秒内、同一台机器上,Snowflake 最多能生成多少个 ID?

单选题 · easy

  • A.1024 个ID
  • B.4096 个ID← 正确答案
  • C.8192 个ID
  • D.不设上限任意多

答案:B。12 位序列号取值范围是 0~4095,所以同一个毫秒内单机最多生成 4096 个 ID。超出后需要阻塞等到下一个毫秒,类似售票窗口一秒钟最多撕 4096 张连号票。

Q4. Snowflake 的“趋势递增”与数据库自增主键的“严格递增”最主要的区别是什么?

单选题 · mid

  • A.要求每个 ID 都比前一个大 1
  • B.只要求随整体时间推移变大← 正确答案
  • C.要求所有节点之间严格有序
  • D.和自增主键的含义完全相同

答案:B。Snowflake 不保证每个 ID 都比前一个大 1,也不保证跨节点的全局严格顺序,只保证整体上随时间推移而变大。好比连号票保证“后出的票号大致更大”,但不保证所有窗口同时出票时严格按自然数排列。

Q5. 为什么用随机 UUID 做数据库主键会导致页分裂增多?

单选题 · mid

  • A.因为 UUID 的存储空间不足
  • B.因为 UUID 的生成速度太慢
  • C.因为 UUID 的值是随机无序的← 正确答案
  • D.因为 UUID 之间会发生冲突

答案:C。B+ 树适合顺序插入,随机无序的主键会散落在各页之间,频繁触发页分裂与碎片。UUID 就像随机散落的票号,观众入场时哪一页都要翻找,数据库写入时哪一页都要拆。

Q6. Snowflake 中机器码占 10 位,理论上最多支持多少台机器同时发号?

单选题 · mid

  • A.512 台机器
  • B.1024 台机器← 正确答案
  • C.2048 台机器
  • D.4096 台机器

答案:B。10 位二进制能表示 2¹⁰=1024 个不同值。这个机器码相当于售票窗口编号,窗口编号不够用会导致两台机器用同一个号,进而可能重复出票。

Q7. 下列哪些属于标准 Snowflake 的组成段?

多选题 · mid

  • A.毫秒级时间戳← 正确答案
  • B.机器码标识← 正确答案
  • C.序列号计数← 正确答案
  • D.密码学哈希值

答案:ABC。标准 Snowflake 由时间戳、机器码、序列号三段构成,本质是一段可解释的结构化数字;密码学哈希值与三段式拼接毫无关系。

Q8. 哪些场景下选择 UUID 比 Snowflake 更合适?

多选题 · mid

  • A.客户端离线生成全局 ID← 正确答案
  • B.需要隐藏真实业务规模← 正确答案
  • C.需要按时间范围扫描数据
  • D.数据库主键需趋势有序

答案:AB。客户端离线生成时无法协调机器码,UUID 零依赖;随机 UUID 不可猜测,能隐藏业务量。但按时间扫描和趋势有序是 Snowflake 的强项,UUID 无序且长度大,不适合这类需求。

Q9. 某服务遇到 Snowflake 时钟回拨,下列哪种做法是最危险的?

单选题 · hard

  • A.短暂停止发号并等待时钟恢复
  • B.使用备用序列号段继续发号
  • C.直接按回拨后的时间继续生成← 正确答案
  • D.以上一次时间戳为基准继续递增

答案:C。直接用回拨后的本地时间生成,等于把时间戳退回到已使用过的区间,必然导致 ID 重复。等待时钟追平、用备用序列号段、以上次时间戳为基准递增都是常见兜底手段。

Q10. 以下哪些是业界应对 Snowflake 时钟回拨问题的常用方案?

多选题 · extreme

  • A.等待本地时钟自动校准恢复← 正确答案
  • B.使用独立发号服务集中分配← 正确答案
  • C.借用扩展序列号段继续发号← 正确答案
  • D.直接回拨时拒绝一切生成

答案:ABC。等待时钟追平是最直接的做法;独立发号服务将时钟依赖收敛到少数节点,便于统一控制;扩展序列号段能借用预留位继续递增。完全拒绝一切生成虽然安全,但会造成服务短暂不可用,通常只作为最后手段而非“常用方案”。