引言
分布式系统里,时间不一致比时间不准更致命:日志时间戳错位会让排查无从下手,Token 与证书校验失败会导致服务大面积 401,数据库主从延迟判断失真、分布式锁与共识算法直接崩溃。Linux 的时钟由硬件晶振驱动,天然存在漂移(drift),必须靠 NTP 之类的协议持续校正。
本文从时间漂移的成因讲起,厘清墙钟(CLOCK_REALTIME)与单调钟(CLOCK_MONOTONIC)的区别,介绍 NTP 的分层(stratum)与选源原理,对比 ntpd 与 chrony 并给出 chrony 的完整配置,再简介 PTP 高精度同步、systemd-timesyncd 与时区管理,最后落到监控验证与虚拟机、容器场景的排错实践。
前置:systemd 服务与单元管理。日志时间线一致性见 systemd-journald 与结构化日志,审计取证对时间的依赖见 Linux 安全加固与基线。
目录
- 1. 时间为什么重要:漂移、单调钟与墙钟
- 2. 时间同步原理:NTP 与 stratum
- 3. ntpd 与 chrony:选型对比
- 4. chrony 配置实战
- 5. 选源策略与时间层级
- 6. PTP:高精度时间同步简介
- 7. systemd-timesyncd 与时区
- 8. 监控、验证与排错
- 9. 生产实践:虚拟机与容器
- 10. 速查表
- 延伸阅读
1. 时间为什么重要:漂移、单调钟与墙钟
硬件晶振的频率随温度与老化漂移,普通服务器每天偏差几十到几百毫秒很正常——不校正就会累积成灾难。
漂移的来源分两类:
| 来源 | 表现 | 影响 |
|---|---|---|
| 晶振频率误差 | 每天数十至数百 ms | 长期累积,需持续校正 |
| 温度与电压变化 | 短期抖动 | 影响同步精度 |
| 虚拟化时钟偏移 | 跳变或变慢 | VM 中尤为明显 |
| NTP 网络抖动 | 毫秒级波动 | 决定同步上限 |
Linux 有两套时钟,用途完全不同:
| 时钟 | 系统调用 | 特性 | 用途 |
|---|---|---|---|
| 墙钟 | CLOCK_REALTIME | 可被 NTP 调整、可跳变 | 日志时间戳、证书、Token |
| 单调钟 | CLOCK_MONOTONIC | 只增不减、不受 NTP 影响 | 超时、耗时测量、调度 |
| 启动钟 | CLOCK_BOOTTIME | 含休眠时间 | 休眠感知的计时 |
# 查看墙钟与单调钟
date
cat /proc/uptime
# 查看当前时间源与同步状态
timedatectl
timedatectl timesync-status
关键原则:测量耗时永远用单调钟,记录时刻才用墙钟。用墙钟算耗时,一旦 NTP 回拨就会得到负数或巨大值。
一句话:墙钟管「几点」,单调钟管「多久」——混用二者是分布式系统里最隐蔽的一类 bug。
2. 时间同步原理:NTP 与 stratum
NTP 通过「客户端与服务器交换四个时间戳」估算网络往返延迟与时钟偏差,再渐进地调整本地时钟,而不是一次性跳变。
NTP 报文的四个时间戳:
T1 客户端发送时刻
T2 服务器接收时刻
T3 服务器发送时刻
T4 客户端接收时刻
偏差 offset = ((T2 - T1) + (T3 - T4)) / 2
延迟 delay = (T4 - T1) - (T3 - T2)
时钟按「层级(stratum)」组织:stratum 0 是原子钟/GPS 等基准源,stratum 1 是直连基准源的服务器,stratum 2 从 stratum 1 同步,依此类推,层级越大精度越差。
| stratum | 含义 | 典型设备 |
|---|---|---|
| 0 | 基准时钟 | 原子钟、GPS 接收机 |
| 1 | 直连基准 | 公共 NTP 池中的一级服务器 |
| 2 | 从 stratum 1 同步 | 企业内网 NTP 服务器 |
| 3+ | 逐级下传 | 终端主机 |
| 16 | 未同步 | 不可用状态 |
时钟调整有两种方式:
# 一次性跳变(slew vs step)
# step:立即跳到正确时间(差异大时)
# slew:缓慢调整,避免时间倒退(差异小时)
chronyc makestep # 手动触发一次步进
一句话:NTP 追求「不倒退的平滑校正」——正常运行靠 slew 微调,只有启动时偏差过大才 step 一次,避免时间倒退破坏依赖顺序的逻辑。
3. ntpd 与 chrony:选型对比
chrony 是为「不稳定的网络与虚拟化环境」设计的 NTP 实现,收敛更快、对间歇性联网更友好,已成为现代发行版默认。
| 维度 | ntpd | chrony |
|---|---|---|
| 收敛速度 | 慢(数小时) | 快(数分钟) |
| 时钟调整 | 传统 PLL/FLL | 更精细的算法 |
| 间歇联网 | 差 | 好(适合笔记本/VM) |
| 频率校正 | 需持续运行 | 支持保存 drift 文件 |
| 监控接口 | ntpq | chronyc |
| 默认发行版 | 老系统 | RHEL 7+/Ubuntu 16.04+ |
| 资源占用 | 略高 | 更低 |
# 安装
apt install chrony # Debian/Ubuntu
yum install chrony # RHEL/CentOS
# 服务管理
systemctl enable --now chronyd
systemctl status chronyd
# 常用监控
chronyc tracking # 同步状态
chronyc sources -v # 时间源
chronyc sourcestats -v # 源统计
一句话:新部署一律用 chrony——ntpd 已基本退出历史舞台,chrony 在虚拟机、容器、间歇联网场景下的表现全面胜出。
4. chrony 配置实战
chrony.conf 的核心是「指定时间源 + 允许谁同步 + 是否本地兜底」,其余都是精度调优。
# /etc/chrony.conf(RHEL 风格)
server ntp1.internal.example.com iburst # 内网源优先
server ntp2.internal.example.com iburst
pool 2.pool.ntp.org iburst # 公网兜底
driftfile /var/lib/chrony/drift # 记录漂移率,加速收敛
makestep 1.0 3 # 前 3 次偏差>1s 则步进
allow 10.0.0.0/24 # 允许内网客户端
local stratum 10 # 上游不可达时本地兜底
rtcsync # 同步系统时间到 RTC
logdir /var/log/chrony
log measurements statistics tracking
关键指令说明:
| 指令 | 作用 |
|---|---|
server | 指定单个时间源 |
pool | 指定一组源(自动解析多个 IP) |
iburst | 启动时快速发送一组包,加快收敛 |
makestep 1.0 3 | 前 3 次同步中偏差 >1s 则步进 |
driftfile | 保存频率偏差,加速重启收敛 |
allow | 允许哪些网段作为客户端 |
local stratum N | 上游不可用时以指定层级对外服务 |
rtcsync | 定期把系统时间同步到 RTC |
# 修改配置后重载
systemctl restart chronyd
# 验证配置
chronyd -Q 'server ntp1.internal.example.com iburst'
chronyc sources -v
chronyc tracking
一句话:内网一定要有自己的 NTP 服务器 +
allow内网网段——所有主机直连公网 NTP 既不安全也不稳定,还会因出网抖动放大误差。
5. 选源策略与时间层级
时间源要「多点、就近、分层」:至少 3 个源做多数表决,内网分层减轻上游压力,避免所有主机打同一个源。
chronyc sources 输出解读:
chronyc sources -v
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
^* ntp1.internal.example 2 6 377 33 -12us[ -8us] +/- 89us
^+ ntp2.internal.example 2 6 377 35 +15us[ +20us] +/- 95us
^- 203.0.113.10 2 6 377 40 -120us[-115us] +/- 12ms
| 列 | 含义 |
|---|---|
M | 模式(^ 服务器、= 对等、# 本地) |
S | 状态(* 当前最优、+ 参与组合、- 未参与) |
Stratum | 源所在层级 |
Poll | 轮询间隔(2 的幂秒) |
Reach | 最近 8 次请求的成功位图(377 为全成功) |
LastRx | 距上次收到响应秒数 |
Last sample | 上次测量的偏差 |
选源与分层策略:
# 企业内网分层示例
# 核心 NTP 服务器(stratum 2):同步公网池
server 0.pool.ntp.org iburst
server 1.pool.ntp.org iburst
server 2.pool.ntp.org iburst
allow 10.0.0.0/8
local stratum 10
# 终端主机:只同步内网 NTP
server ntp1.internal.example.com iburst
server ntp2.internal.example.com iburst
一句话:
Reach不是 377 就说明源在丢包——先看 Reach 和 Stratum 判断源是否健康,再看 Last sample 判断精度,最后才谈调优。
6. PTP:高精度时间同步简介
NTP 的精度上限在毫秒级,金融交易、电信、工业控制等场景需要微秒甚至纳秒级,于是有了 PTP(IEEE 1588)。
| 维度 | NTP | PTP |
|---|---|---|
| 精度 | 毫秒级 | 亚微秒至纳秒级 |
| 传输 | UDP/IP(通常) | 二层以太网或 UDP |
| 硬件 | 软件时间戳 | 硬件时间戳(PHC) |
| 拓扑 | 任意 | 主从(需交换机支持) |
| 典型场景 | 通用服务器 | 金融、电信、工业 |
PTP 依赖网卡的硬件时间戳(PTP Hardware Clock)来消除软件栈抖动:
# 查看网卡是否支持硬件时间戳
ethtool -T eth0
# 查看 PHC 设备
ls /dev/ptp*
# 安装 linuxptp
apt install linuxptp
# 启动 ptp4l(主时钟同步)
ptp4l -i eth0 -m
# 启动 phc2sys(把 PHC 时间同步到系统时钟)
phc2sys -s eth0 -w -m
# /etc/linuxptp/ptp4l.conf(关键项)
[global]
clockClass 248
domainNumber 0
slaveOnly 1 # 本机作为从时钟
一句话:PTP 的精度来自硬件时间戳,不是协议本身——没有支持 PTP 的网卡和交换机,配再多参数也达不到微秒级。
7. systemd-timesyncd 与时区
systemd-timesyncd 是一个轻量 SNTP 客户端,够用但不精确,适合桌面与简单服务器;它只管墙钟,不提供 NTP 服务端能力。
# /etc/systemd/timesyncd.conf
[Time]
NTP=ntp1.internal.example.com ntp2.internal.example.com
FallbackNTP=0.pool.ntp.org 1.pool.ntp.org
RootDistanceMaxSec=5
# 启用与查看
timedatectl set-ntp true
timedatectl status
timedatectl timesync-status
systemctl restart systemd-timesyncd
注意:chrony 与 systemd-timesyncd 会争抢时钟,装了 chrony 就要关掉 timesyncd:
systemctl disable --now systemd-timesyncd
时区管理:
# 查看当前时区
timedatectl
# 列出可用时区
timedatectl list-timezones | grep Asia
# 设置时区
timedatectl set-timezone Asia/Shanghai
# 手动设置时间(不推荐,有 NTP 就别用)
timedatectl set-time "2026-10-04 12:00:00"
# 查看 RTC 与系统时钟
hwclock --show
hwclock --systohc # 系统时钟写入 RTC
| 组件 | 角色 | 精度 | 适用 |
|---|---|---|---|
| chronyd | 完整 NTP 客户端+服务端 | 毫秒 | 服务器、内网时间源 |
| ntpd | 传统 NTP | 毫秒 | 老系统 |
| systemd-timesyncd | 轻量 SNTP 客户端 | 十毫秒级 | 桌面、简单场景 |
| ptp4l | PTP | 微秒/纳秒 | 金融、电信 |
一句话:chrony 与 timesyncd 二选一,绝不能同时开——两个客户端同时调整时钟会互相打架,导致时钟反复抖动。
8. 监控、验证与排错
时间问题的排查顺序:先确认服务在跑,再看有没有源,再看偏差多少,最后看为什么偏差大。
# 1. 服务状态
systemctl status chronyd
chronyc activity
# 2. 同步状态(关键指标)
chronyc tracking
# 3. 源是否可达
chronyc sources -v
chronyc sourcestats -v
# 4. 手动强制同步
chronyc makestep
# 5. 查看最近同步事件
journalctl -u chronyd -n 50
chronyc tracking 关键字段:
| 字段 | 含义 | 健康值 |
|---|---|---|
| Reference ID | 当前时间源标识 | 非 0 |
| Stratum | 层级 | 1~15 |
| System time | 与源的时间偏差 | 微秒~毫秒 |
| Last offset | 上次调整量 | 接近 0 |
| RMS offset | 偏差均方根 | 小 |
| Frequency | 本机时钟频率偏差(ppm) | 稳定 |
| Leap status | 闰秒状态 | Normal |
常见故障与处理:
# 源不可达(Reach 全 0):查 DNS、UDP 123 防火墙、上游
dig ntp1.internal.example.com
nc -uz ntp1.internal.example.com 123
# 时间差过大拒绝同步:先手动步进一次
chronyc makestep
# Frequency 剧烈波动:多为虚拟机时钟源问题(见下节)
一句话:
Reach全 0 是「够不着」,Stratum 16是「没同步」——先分清是网络问题还是配置问题,再决定是查防火墙还是改配置。
9. 生产实践:虚拟机与容器
虚拟化环境的时间同步要特别处理:VM 的时钟可能被 hypervisor 干预,容器则共享宿主机时钟——两者策略完全不同。
虚拟机场景:
# KVM/QEMU:使用 kvm-clock 时钟源
cat /sys/devices/system/clocksource/clocksource0/available_clocksource
cat /sys/devices/system/clocksource/clocksource0/current_clocksource
# 应优先使用 kvm-clock / tsc
# VMware:安装 open-vm-tools 并启用时间同步
systemctl status vmtoolsd
vmware-toolbox-cmd timesync status
关键原则:不要在 VM 内同时用 NTP 和宿主机时间同步,二者会互相拉扯:
# VMware 场景:二选一
vmware-toolbox-cmd timesync disable # 若 VM 内跑 chrony
# 或
systemctl disable --now chronyd # 若依赖宿主机同步
容器场景:
# 容器默认共享宿主机的时钟命名空间
docker run --rm alpine date
# 因此容器内通常不需要、也不应该跑 NTP
# 若要独立时间命名空间(少见):
docker run --rm --cap-add SYS_TIME --privileged alpine \
sh -c 'date -s "2026-10-04 12:00:00"'
| 场景 | 时钟来源 | 建议 |
|---|---|---|
| 物理机 | RTC + NTP | chrony 同步公网/内网 |
| KVM 虚拟机 | kvm-clock + NTP | 用 kvm-clock,chrony 微调 |
| VMware | 宿主 + 可选 NTP | 二选一,勿双管齐下 |
| 容器 | 宿主机 | 不跑 NTP,靠宿主机 |
| K8s 节点 | 宿主机 | 节点同步即可,Pod 无需 |
# 检查容器与宿主机时间是否一致
docker run --rm --pid=host alpine date
date
一句话:容器不管理时间,虚拟机避免双源——时间同步的职责边界要清晰,越权管理时钟比不同步更危险。
10. 速查表
| 需求 | 命令 |
|---|---|
| 查看同步状态 | timedatectl / chronyc tracking |
| 查看时间源 | chronyc sources -v |
| 查看源统计 | chronyc sourcestats -v |
| 强制步进 | chronyc makestep |
| 手动指定源测试 | chronyd -Q 'server ntp.x iburst' |
| 重启服务 | systemctl restart chronyd |
| 设置时区 | timedatectl set-timezone Asia/Shanghai |
| 启用 NTP | timedatectl set-ntp true |
| 关闭 timesyncd | systemctl disable --now systemd-timesyncd |
| 查看 RTC | hwclock --show |
| 系统时间写 RTC | hwclock --systohc |
| 检查时钟源 | cat /sys/devices/system/clocksource/clocksource0/current_clocksource |
| 网卡硬件时间戳 | ethtool -T eth0 |
| PTP 主同步 | ptp4l -i eth0 -m |
一句话记忆:服务器一律 chrony,内网自建时间源并 allow 网段;Reach 看连通、Stratum 看层级、System time 看精度;VM 用 kvm-clock、容器靠宿主机;chrony 与 timesyncd 绝不共存。
延伸阅读
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。