NTP 是如何进行时间同步的?时钟偏移和网络延迟怎么计算?
简化版
NTP 是网络时间同步协议,通常基于 UDP 123 端口,通过客户端和服务器交换 4 个时间戳来估算网络往返延迟和本地时钟偏移。它不会直接粗暴把时间跳过去,而是尽量用渐进调整避免业务时间倒退;在分布式系统里,NTP 对日志排序、证书校验、Token 过期、数据库复制都很关键。
详细版
NTP 一次同步会记录 4 个时间:
| 时间戳 | 含义 |
|---|---|
| T1 | 客户端发送请求的本地时间 |
| T2 | 服务端收到请求的服务端时间 |
| T3 | 服务端发出响应的服务端时间 |
| T4 | 客户端收到响应的本地时间 |
常见公式是:
往返延迟 delay = (T4 - T1) - (T3 - T2)
时钟偏移 offset = ((T2 - T1) + (T3 - T4)) / 2
它假设请求路径和响应路径延迟大致对称。实际网络不完全对称,所以 NTP 会多次采样、过滤异常值、选择更可信的时间源。面试重点还包括:NTP 分层 Stratum、为什么时间回拨危险、和闰秒/单调时钟的关系。
完整版教学
一、为什么分布式系统离不开时间同步
单机程序里,时间错一点可能只是日志不准;分布式系统里,时间错会变成真实故障。证书依赖有效期,JWT 和 Cookie 依赖过期时间,数据库主从复制和审计日志依赖时间排序,限流窗口和定时任务也依赖本地时钟。
例如 A 机器时间比真实时间快 5 分钟,用户刚签发的 10 分钟 Token 到 B 机器还正常,到 A 机器可能只剩 5 分钟;如果 A 快 15 分钟,Token 可能被误判过期。时间不同步会让“同一请求在不同机器上得到不同结论”。
NTP 在分布式系统里的角色不是让钟表好看,而是让过期、排序、审计和协调有共同基准。
二、NTP 的四时间戳模型
NTP 同步不是服务端告诉客户端“现在几点”这么简单,因为网络传输有延迟。客户端看到响应时,服务端时间已经是过去的时间了。为估算这段延迟,NTP 记录请求和响应两端的 4 个时间戳。
Client Server
| -- T1 请求发送 ------------> |
| | T2 请求到达
| | T3 响应发出
| <------------ 响应到达 T4 -- |
通过 T1、T2、T3、T4,客户端可以估算网络往返延迟和自己相对服务端的偏移。这个模型的关键假设是来回路径延迟近似相等,虽然不完美,但多次采样后足够实用。
三、delay 和 offset 怎么算
假设客户端本地时间慢了 100 ms,网络来回各 20 ms,服务端处理耗时 5 ms。客户端 T1=1000,服务端收到时真实时间是 1020,但服务端钟是准确的,所以 T2=1120;服务端 T3=1125;客户端收到时真实时间是 1045,但客户端慢 100 ms,所以 T4=945。
代入公式:
delay = (T4 - T1) - (T3 - T2)
= (945 - 1000) - (1125 - 1120)
= -55 - 5
这个例子里直接混用偏移后的本地时间会让直觉混乱。更容易记的是公式意义:T4 - T1 是客户端看到的总耗时,T3 - T2 是服务端处理耗时,二者相减得到网络往返延迟;offset 用两个方向的时间差取平均,抵消一半网络延迟。
delay = (T4 - T1) - (T3 - T2)
offset = ((T2 - T1) + (T3 - T4)) / 2
四、为什么 NTP 要多次采样
网络延迟会抖动,单次测量不可靠。一次请求可能刚好遇到排队,得到 200 ms 延迟;下一次可能只有 20 ms。如果用异常样本调时,时钟会被网络抖动带偏。NTP 客户端会周期性采样,过滤离群值,倾向选择延迟更低、更稳定的样本。
| 样本 | delay | offset | 可信度 |
|---|---|---|---|
| A | 20 ms | +3 ms | 高 |
| B | 25 ms | +4 ms | 高 |
| C | 220 ms | +90 ms | 低,可能排队 |
低 delay 样本通常意味着排队更少,更接近真实路径传播时间。因此 NTP 不是一次公式算完,而是一套持续估计和校准过程。
五、时间调整为什么不能随便回拨
如果本地时间比标准时间快 2 秒,最粗暴的做法是立刻把系统时间拨回 2 秒。但时间回拨会伤害很多程序:定时任务可能重复执行,日志时间倒序,缓存过期判断异常,数据库事务时间戳混乱。
更稳的做法是 slewing,也就是让时钟走慢一点或快一点,逐渐追平。例如每秒调整 500 ppm,修正 1 秒偏差大约需要 2000 秒。偏差特别大时,系统才可能在启动阶段 step 直接跳变。
小偏差: 慢慢调速追平,避免时间倒退
大偏差: 启动早期可直接校正,运行中要谨慎
六、Stratum 表示时间源层级
NTP 使用 Stratum 表示离权威时间源的距离。Stratum 0 是原子钟、GPS 等参考源;直接连接它们的服务器是 Stratum 1;再往下是 Stratum 2、3。层级越低通常越接近权威源,但实际质量还要看网络延迟、稳定性和服务器负载。
GPS/原子钟 (Stratum 0)
|
NTP Server (Stratum 1)
|
企业时间服务器 (Stratum 2)
|
业务机器 (Stratum 3)
企业内部常见做法是部署内部 NTP 源,业务机器统一向内部源同步,避免每台机器都访问公网时间服务器,也便于安全审计和统一管控。
七、NTP 和单调时钟要区分
系统里常见两类时间:墙上时间和单调时间。墙上时间表示日期时刻,可能被 NTP 调整;单调时间只保证递增,适合计算耗时。测接口耗时、超时控制、重试间隔时,应该使用单调时钟,而不是可能被调整的系统时间。
| 用途 | 推荐时间 |
|---|---|
| 日志时间、证书有效期 | 墙上时间 |
| 计算函数耗时 | 单调时间 |
| 定时任务触发点 | 墙上时间加防重复 |
| 超时和重试间隔 | 单调时间 |
这也是为什么有些代码在 NTP 回拨时出现负耗时:它用墙上时间做了耗时计算。
八、常见误区与追问
- 误区:NTP 就是服务器返回当前时间。 它通过四时间戳估算延迟和偏移,并进行持续校准。
- 误区:同步时间可以直接回拨。 运行中回拨可能导致定时任务、日志和事务异常,通常要渐进调整。
- 误区:Stratum 数字越小一定越准。 层级重要,但网络质量、服务器负载和稳定性也会影响精度。
- 误区:有了 NTP 就能严格全局排序。 NTP 只能减少时钟偏差,不能提供严格分布式全序。
- 追问:为什么用 UDP? NTP 交互短小,UDP 开销低;可靠性靠周期采样和过滤,而不是单次连接保证。
- 追问:时间不同步会影响 HTTPS 吗? 会,证书有效期校验依赖本地时间,时间偏差大可能误判证书未生效或已过期。
- 追问:计算耗时为什么不用系统当前时间? 系统时间可能被 NTP 调整,耗时应使用单调时钟。
九、加强记忆
NTP 的核心是四个时间戳:T1 客户端发、T2 服务端收、T3 服务端发、T4 客户端收。用它们估算 delay 和 offset,再通过多次采样和渐进调时保持稳定。分布式系统里要把“墙上时间用于业务时刻”和“单调时间用于耗时”分清,避免时间同步带来的隐藏故障。