跳转到内容

时间、时钟与事件顺序

分布式系统的核心困难之一:没有全局时钟——每台机器的时钟各走各的。本章讲物理时钟的漂移、Lamport 逻辑时钟、向量时钟与混合逻辑时钟,以及"先后"为什么需要重新定义(→ 复制与一致性模型)。

机器时钟是石英振荡器,漂移(每秒几十微秒到毫秒)让各机器的时钟逐渐偏离;NTP 对时修正,但精度是毫秒级(网络延迟不可忽略),且对时的跳变本身会破坏"时间只增"的假设。

结论:分布式系统不能把物理时钟当作"先后"的依据——两台机器各自记的时间戳无法可靠排序事件。Google TrueTime 是例外(见下)。

Lamport (1978) 的解法:不问几点,只问谁先。每个进程维护计数器:

  • 本地事件:计数器 +1;
  • 发消息:带上计数器;
  • 收消息:计数器 = max(本地, 收到的) + 1。

a→ba \to b(a 因果先于 b)蕴含 C(a)<C(b)C(a) < C(b)——时钟与因果一致。

Lamport 时钟给出与因果一致的全序,但不能检测并发:C(a)<C(b)C(a) < C(b) 不能推出 a→ba \to b(可能只是两个无关进程各自计数)——Lamport 时钟回答"全序"但不回答"是否真的因果相关"。

每个进程维护全系统的计数向量:本地事件加自己的分量,收消息做逐分量 max 再加自己的。

  • a→ba \to b 当且仅当 V(a)≤V(b)V(a) \le V(b)(逐分量);
  • 两个向量不可比 = 并发——向量时钟能检测并发,这是 Lamport 时钟做不到的;
  • 代价是 O(n) 空间(nn 为进程数,每个事件带全向量)——向量时钟能检测并发,代价是 O(n) 空间。

应用:冲突检测(Dynamo 的多版本读写)、分布式调试(事件图)。

  • 混合逻辑时钟(HLC):物理时间戳为主、逻辑计数为辅——时钟既接近物理时间(对人类与外部系统友好)又保持因果一致(CockroachDB、YugabyteDB 的选择);
  • Google TrueTime:硬件(GPS + 原子钟)把时钟误差变成显式区间——API 返回 [earliest,latest][\text{earliest}, \text{latest}] 的保证区间。Spanner 用它实现外部一致性:提交前等待区间上界过去(commit wait),保证"提交时间戳"真实序——误差显式化后,物理时间也能参与一致性。代价是专用硬件。

单机的"先后"由时间戳定义;分布式系统重新定义为因果(happens-before):

  • 同进程的程序序;
  • 消息的发送先于接收。

"先后"在分布式系统中需要重新定义——不是物理时间,而是因果链。一致性的谱系(线性一致、因果一致)本质上都是"对先后顺序承诺多少"的不同回答(→ 复制与一致性模型)。

  • 物理时钟漂移 + NTP 毫秒级精度:不能作为"先后"的依据
  • Lamport 时钟给出与因果一致的全序,但不能检测并发
  • 向量时钟能检测并发,代价是 O(n) 空间
  • HLC 融合物理与逻辑;TrueTime 用硬件把误差变成显式区间(Spanner 的基础)
  • "先后"的分布式定义是因果(happens-before),不是时间戳