跳转到内容

NTP 1991 — 用四个时间戳和一棵服务器树,让全互联网的钟差几毫秒

是什么

NTP(Network Time Protocol)是让一台普通电脑通过不可靠的互联网,去和原子钟保持毫秒级一致的协议。Mills 1991 这篇论文是它的奠基设计。

日常类比:一个班里几百号人都戴着便宜电子表,每块表每天会快慢几十秒。班主任只有一块标准表。要让全班的表都对得上,不可能让大家排队让班主任挨个调;得搞一套”组长把时间传给小组、小组再传下去”的层级,再加上每次对表都要”扣掉传话花的时间”。

NTP 把这件事工程化:

  • 服务器树:根是接 GPS / 原子钟的少数权威机器(stratum 1),它们把时间传给 stratum 2,再到 stratum 3……
  • 四时间戳:每次客户端问服务器要时间,记下 4 个时刻,从中算出”我比你慢多少(offset)“和”路上花了多久(delay)”
  • 算法链:滤波 → 选择 → 组合 → 纪律环(PLL),把多个上游服务器的噪声测量收敛成一个稳定的本地时钟修正

公网上能稳定做到 10ms 级,局域网内亚毫秒级。

为什么重要

不理解 NTP,下面这些事都讲不清:

  • 你电脑右下角那个时间凭什么和北京天文台一致 —— 它每隔几分钟在偷偷和某台 NTP 服务器对表
  • 数据库的”时间戳排序”为什么不能直接用 wall-clock —— NTP 只能保证毫秒级,事务序需要纳秒
  • Spanner 为什么要造 TrueTime(GPS+原子钟+API 返回区间)—— 因为 NTP 给不出”误差上界”
  • 为什么 2014 年 NTP 反射型 DDoS 能打出几百 Gbps —— 协议早期的 monlist 查询设计有放大漏洞

NTP 同时是互联网计时基础设施早期分布式系统教科书案例:它示范了在不可靠网络上,如何用统计 + 控制论的组合扛住延迟抖动、对称性破坏、单点故障。

核心要点

NTP 工作流程拆 四步

  1. 测量(四时间戳):客户端发包记 t0,服务器收到记 t1、回包记 t2,客户端收到记 t3。

    • 偏移 θ = ((t1 − t0) + (t2 − t3)) / 2
    • 时延 δ = (t3 − t0) − (t2 − t1)
    • 这套算法默认前向后向路径耗时一样——不对称就会有系统误差。
  2. 滤波(clock filter):保留最近 8 次测量,挑 dispersion 最小的那一个。类比:抽 8 次秒表读数,扔掉抖得最厉害的,留最稳的。

  3. 选择 + 组合(selection / combine):从多台上游里去掉falseticker(说谎或离群的),剩下的truechimer按 1/dispersion² 加权平均。类比:让 5 个朋友报时间,先剔掉明显瞎说的两个,剩下三个的平均更可信。

  4. 纪律环(discipline loop):用 PLL/FLL(锁相/锁频环)持续微调本地晶振的频率和相位,让它慢慢追上目标,不是猛地跳过去(跳过去会让 make 这种依赖时间戳的工具炸)。

整套加起来:多个上游 + 多次测量 + 控制论,把不可靠 UDP 网络的抖动磨成一条平滑曲线。

实践案例

案例 1:手算一次 NTP 同步

假设你发了一个 NTP 请求:

t0 = 100.000 (客户端发出,本地时钟)
t1 = 150.020 (服务器收到,服务器时钟)
t2 = 150.030 (服务器回包, 服务器时钟)
t3 = 100.030 (客户端收到,本地时钟)

代入:

  • offset θ = ((150.020 − 100.000) + (150.030 − 100.030)) / 2 = 50.010
  • delay δ = (100.030 − 100.000) − (150.030 − 150.020) = 0.020

结论:客户端比服务器慢 50.010 秒,单程时延约 10ms。客户端会慢慢加快本地时钟,几分钟内追上服务器。

案例 2:为什么 stratum 数字不直接代表精度

新人常以为”stratum 越小越准”。错。stratum 只是到根的图距离。一台 stratum 3 服务器如果接的是稳定光纤 + 多个良配上游,可能比一台跨大陆链路的 stratum 2 更准。真正看精度要看 dispersion 和 jitter 两个指标

案例 3:NTP 在内网部署该怎么搭

100 节点的小集群,常见错误是只配一台上游。Mills 论文反复强调要至少 4 台——前 3 台是为了 Byzantine 容错(投票剔除一台说谎的还能多数决),第 4 台是冗余。生产环境一般本地部 2-3 台 stratum 2,对外指向 4 台不同 ISP / pool.ntp.org 的 stratum 1/2。

案例 4:把 NTP 和 Spanner TrueTime 放一起对比

维度NTPTrueTime
时间源多级服务器树每数据中心一组 GPS + 原子钟
输出单点估计(now)区间 [earliest, latest]
精度公网毫秒,LAN 亚毫秒数据中心约 7ms 区间宽度
用途通用计时跨大陆事务序,用 commit-wait 等区间

理解 TrueTime 的设计动机,最快的路径就是先理解 NTP 给不出”误差上界”——它没有把 dispersion 作为一个数值返回给应用层,应用只能拿到”现在大概是 X”。

踩过的坑

  1. 对称路径假设是脆弱前提:家庭宽带 100M 下行 / 10M 上行,路径不对称,offset 估计会系统性偏移;多上游互投票能抵消大部分。
  2. stratum 不等于精度:监控要看 dispersion / jitter,别只盯 stratum 数字。
  3. NTP 不能给强一致数据库做事务序:毫秒级误差对秒级业务足够,但纳秒级事务要 HLC 或 TrueTime;2010 年代很多团队在这上面栽过跟头。
  4. DDoS 反射放大:早期 NTP 有 monlist 等查询,请求几十字节回应几千字节,2014 年被滥用打出 400Gbps 级攻击;公网部署必须关掉这些查询、加速率限制、上 NTS(RFC 8915,给 NTP 套 TLS)。

适用 vs 不适用场景

适用

  • 通用服务器/桌面/手机的时间同步(毫秒级够用)
  • 日志系统的时间排序(容忍亚秒级偏差)
  • 大多数对时间精度要求”差不多就行”的业务

不适用

  • 强一致分布式数据库的事务序 → 用 TrueTime / HLC
  • 金融交易、5G 基站、PTP 网络 → 用 PTP(IEEE 1588,硬件时间戳,亚微秒)
  • 需要”误差上界”的场景 → NTP 只给点估计,不给区间

历史小故事(可跳过)

  • 1985 年:Mills 在 Univ of Delaware 部署 NTPv0,从 ARPA 时代就在做。
  • 1991 年:这篇 IEEE Trans on Communications 论文把多年工程经验形式化,是 NTP 进入主流学界的标志性文献。
  • 1992 年:NTPv3 RFC 1305 发布,是这篇论文的标准化版本。
  • 2010 年:Mills 出 Computer Network Time Synchronization 专著,被誉为”互联网计时之父”。
  • 2010 年代:Spanner TrueTime / HLC / NTS / PTP 等后续方案,都在不同维度补 NTP 的短板。

学到什么

  1. 测量 + 滤波 + 控制环 是任何”在不可靠通道上估一个连续量”的通用模板(GPS、传感器融合、分布式追踪都用)
  2. 多上游冗余 + 投票 是分布式系统对抗 Byzantine 故障的最基本手段
  3. 不对称是真实世界默认状态——任何依赖”前向后向相等”的协议都要想清楚不对称时的退化
  4. 同一个抽象层不要让”工程足够”的方案去解”理论需要更强保证”的问题:NTP 不是为强一致设计的,强行用就会栽

延伸阅读

  • 论文 PDF:Mills 1991 — Internet Time Synchronization
  • RFC 5905:NTPv4 标准(2010)
  • RFC 8915:NTS(NTP 的 TLS 安全层,2020)
  • 工具:chrony(现代 NTP 客户端,比传统 ntpd 收敛更快)
  • lamport-1978 —— 逻辑时钟:物理时钟之外的另一条思路
  • byzantine-generals-1982 —— 为什么至少要 3f+1 个上游才能容 f 个说谎者
  • spanner —— TrueTime 用 GPS+原子钟把”误差区间”显式暴露给上层

关联

  • lamport-1978 —— Lamport 逻辑时钟,与 NTP 的物理时钟互补
  • fidge-1988 —— 向量时钟,捕捉因果序而非真实时刻
  • mattern-1989 —— 分布式快照中的时间一致问题
  • chandy-lamport-1985 —— 全局快照算法,假设有近似同步时钟
  • byzantine-generals-1982 —— NTP selection 阶段去 falseticker 的理论依据
  • spanner —— 后 NTP 时代如何获得”误差上界”
  • hlc-2014 —— Hybrid Logical Clock,把物理与逻辑时钟揉到一起
  • tcp —— NTP 不用 TCP 而用 UDP 的设计取舍
  • dns —— 同样靠层级 + 缓存解决全球分发的协议

反向链接

  • byzantine-generals-1982 —— 拜占庭将军问题 — 节点能撒谎时怎么达成一致
  • chandy-lamport-1985 —— Chandy-Lamport 1985 — 分布式系统不停机也能拍一张全家福
  • dns —— DNS — 把全球域名解析切成一棵可分布维护的树
  • fidge-1988 —— Fidge 1988 — 给每个进程一份”账本向量”,让因果关系变成可判定
  • hlc-2014 —— HLC 2014 — 把逻辑时钟和物理时钟合一,让普通服务器也能拍一致快照
  • lamport-1978 —— Lamport 1978 — 分布式系统里没有”绝对的同时”
  • mattern-1989 —— Mattern 1989 — 虚拟时间与全局状态:把分布式时钟变成 N 维笛卡尔积
  • spanner —— Spanner — 全球分布式 SQL 数据库
  • tcp —— TCP — 在不可靠的 IP 上凿出一条 reliable 字节流