物理时钟:时钟漂移、NTP 与不可信的时间

01-基础与模型 入门 约 15 分钟 #时间#NTP#时钟漂移#单调时钟 更新 2026-10-02
当前状态:未学
本文基于模型知识整理(生成时未联网核对),关键结论建议对照经典文献复核。

一句话定义

分布式系统中每台机器的物理时钟(石英晶体振荡器)都会漂移且可被外部校时服务突然调整,因此跨机器的墙钟时间既不精确也不单调,不能作为事件排序与超时判定的依据。

为什么重要

大量"看似正确"的系统设计暗含了"时间戳可跨机器比较"的假设,而这是分布式系统最经典的 bug 来源之一:备份覆盖新数据、过期判定失效、事件顺序颠倒。理解时钟的不可信性,才能理解为什么需要逻辑时钟(kp-004)与共识(kp-017)。

前置知识

kp-001;操作系统时钟的基本概念。

核心概念

  • 墙钟(wall-clock time):gettimeofday/Date.now() 一类返回"日历时间"的时钟,受 NTP 校正影响,可能回拨或跳变。
  • 单调时钟(monotonic clock):只增不减、用于测量时间间隔的时钟(如 Java System.nanoTime()、Go time.Since()),但其读数只在单机内有意义,跨机器不可比较。
  • 时钟漂移(drift):石英钟每秒误差约百万分之几十,一天可漂移数十毫秒到数秒(与温度、机器年龄有关)。
  • NTP:网络时间协议,向权威时钟源校准;校正方式为阶跃(突然跳变)或缓慢调整(slewing),两者都会破坏"时间平滑流逝"的假设。
  • 闰秒:UTC 与地球自转对齐引入的整秒调整,曾多次造成真实系统大面积故障。

原理与机制

墙钟的两大不可信来源:

  1. 不精确:漂移 + NTP 校准误差,意味着两台机器对"同一时刻"的读数可以差开毫秒到秒级,且差距随时间波动。
  2. 不单调:NTP 阶跃校正或管理员改时间会让墙钟回拨;"先发生的事件却带更早时间戳"随时可能发生。

由此推出两条工程铁律:测时长用单调时钟;跨机器排序事件绝不能只用墙钟。跨机器唯一可靠的排序依据是消息传递关系(happens-before,见 kp-004),或者在协议内显式地把时间变成需要共识的对象(kp-017)。

让时间变可信的代价:Google Spanner 选择把时钟的不确定性显式建模——TrueTime API 返回区间 [earliest, latest],提交事务时等待到足够确保"提交时间戳已过"才返回(commit wait)。这是用延迟换时间正确性的著名工程折衷(见 kp-032)。

图示

机器A墙钟: ──────────╲______╱──────►  NTP阶跃导致回拨
机器B墙钟: ─────╱──────╲───────────►  NTP阶跃导致跳前
  同一真实时刻 t0,A 显示 10:00:03.100,B 显示 10:00:03.250
  → 用两者时间戳比较事件先后不可靠

直观类比

每块手表都走得不太准,还经常被人手动拨快拨慢。你可以用一块表计时(单调钟),但不能拿两块表的时间直接判定"谁先谁后",除非两人先对表——而对表这个动作本身,就是分布式系统要解决的协调问题。

实例或案例

  • 某系统用"备份节点时钟读数"决定覆盖关系,NTP 跳变后备份带着旧数据覆盖了主库,造成数据回退——典型的墙钟信任事故。
  • 2012 年与 2015 年的闰秒导致多个大型站点(如部分 Linux 内核上的 Java 服务)hang 死,促成 Google 提出 smear(把 1 秒摊到 24 小时内平滑加)。
  • Spanner(2012 论文)证明:给时钟配硬件与 GPS/原子钟授时,并对不确定性显式建模,墙钟也能支撑外部一致性——但前提是接受 commit wait 延迟与专用基础设施。

常见误区

  • 误区一:"NTP 校准后时间就准了"。校准是周期性且带误差的,两次校准之间持续漂移,校正瞬间还会跳变。
  • 误区二:"单调时钟可以跨机器比较"。单调钟读数只是本机起点任意的计数,跨机比较毫无意义。
  • 误区三:"用数据库服务器时间给事件排序就安全了"。若多个应用节点各自取本地时间写库,依旧错序;必须由单一权威点(单库、TSO、TrueTime)发时间。

与其他知识点的关系

  • kp-004:放弃物理时间、改用逻辑时序(happens-before)排序事件。
  • kp-017:共识协议只用逻辑任期/日志位置,不依赖墙钟;超时只是活性手段。
  • kp-032:Spanner 的 TrueTime 是"驯服"物理时间的完整案例。

自测题

  1. 为什么测量代码执行耗时必须用单调时钟?

答:墙钟可能因 NTP 校正回拨,导致测出负数或失真;单调时钟保证只增不减。

  1. "跨机器比较墙钟时间戳来排序事件"错在哪?

答:各机时钟漂移不同且会跳变,同一真实时刻读数不同,先发生的事件可能带更晚的时间戳。

  1. Spanner 如何在承认时钟不完美的前提下获得外部一致性?

答:TrueTime 返回时间区间并显式暴露不确定性,提交时 commit wait 至"确定已过提交时间戳",用等待延迟换取正确性。

延伸阅读

  • Martin Kleppmann《DDIA》第 8 章"Unreliable Clocks"。
  • James C. Corbett 等, "Spanner: Google's Globally-Distributed Database"(OSDI 2012)。
  • David F. 体系下的 NTP/时钟同步综述:Mills, "Internet Time Synchronization: The Network Time Protocol"。