NTP 实战与排错 — chrony/ntpd/timedatectl 与时间不同步定位
Wireshark 抓 NTP、chronyc/ntpq/timedatectl/w32tm 命令、配置与时间漂移排错 / 应用层 / UDP 123
Table of Contents
这篇你能学到
- 如何用 Wireshark / tcpdump / tshark 抓并读懂 NTP 报文(Mode、Stratum、refid、四时间戳、KoD),以及怎么确认 monlist 已关闭。
chronyc/ntpq/timedatectl/w32tm全套命令怎么用、输出符号怎么读、chrony.conf/ntp.conf怎么配。- “时间不同步 / offset 抖动 / falseticker / 时间跳变 / Kerberos 偏斜 / 全是 ? / 被当反射源"的排错思路,以及 NTP vs chrony vs PTP 的选型。
1. 抓包观察
1.1 Wireshark 显示过滤式
这组过滤式能干什么:从海量 UDP 里只挑 NTP 流量,按模式(客户端/服务端/危险的 mode 7)、层级、闰秒、参考源、根延迟过滤,快速定位问题包。
| |
命令行:
| |
1.2 典型字段说明(怎么读一个 NTP 响应)
| 字段 | 正常值 | 异常判读 |
|---|---|---|
Flags.Leap Indicator | 0(no warning) | 3 = 对端自己都没同步,别用它 |
Flags.Version | 4 | 3 为老版本,兼容但建议升级 |
Flags.Mode | 请求 3 / 响应 4 | 出现 7(private)= monlist 探测,安全告警 |
Peer Clock Stratum | 1~4 | 16 = 未同步;0 = Kiss-o-Death(看 refid) |
Peer Polling Interval | 6~10(64~1024 s) | 过小可能触发服务端限速(KoD RATE) |
Root Delay | LAN < 1 ms,公网 < 100 ms | 过大说明上游链路差,精度受限 |
Root Dispersion | < 100 ms | 越大越不可信;chrony 用它算 root distance |
Reference ID | GPS/PPS/.GPS. 或上游 IPv4 | RATE/DENY/RSTR = 被限速或拒绝 |
Origin Timestamp | 等于客户端发出的 t1 | 不匹配 → 伪造包或串包,客户端应丢弃 |
Receive/Transmit Timestamp | 单调递增 | t3 < t2 异常;两者差过大说明服务端处理慢 |
快速心算校验:delay = (t4-t1) - (t3-t2)。若 Wireshark 中相邻请求/响应帧的时间差远大于该 delay,说明本地处理或抓包点引入了额外延迟。
1.3 安全检查:确认 monlist 已关闭
这组命令能干什么:验证你的 NTP 服务端有没有暴露 monlist 这个 556 倍反射放大入口,有响应就是风险。
2. 常用命令 / 配置
2.1 通用:查看系统时间状态(systemd)
这组命令能干什么:总览系统时间/时区/NTP 开关,设时区、开关网络同步、读写硬件时钟——排错第一步先看这里。
| |
2.2 chrony(现代 Linux 默认,推荐)
这组命令能干什么:启停服务、看时间源列表(最常用 chronyc sources)、看详细同步状态(chronyc tracking)、紧急校时。chronyc sources 输出符号是判断"谁被选中/谁在说谎/谁不可达"的关键。
| |
读懂 chronyc sources 输出:
| |
| 符号 | 含义 |
|---|---|
^ | 服务器(= 为对等体,# 为本地参考时钟) |
* | 当前选中的同步源 |
+ | 可接受的备选源(参与合并) |
- | 被聚类算法排除的源 |
x | falseticker(与多数源矛盾,被判为说谎) |
? | 不可达(Reach=0) |
~ | 变化过大,时间不稳定 |
| Reach | 8 位八进制可达寄存器。377 = 最近 8 次全部成功(理想值);0 不可达;177/376 表示有丢包 |
| LastRx | 距上次收到响应的秒数 |
| Last sample | 偏移[修正后偏移] +/- 误差范围 |
chronyc tracking 关键行:
| |
/etc/chrony/chrony.conf(Debian)或 /etc/chrony.conf(RHEL):
| |
改完重启并验证:
2.3 ntpd(传统 ntp.org 实现)
这组命令能干什么:启停 ntpd、看时间源(ntpq -p)、读系统变量、单次校时。注意 ntpd 需手工 disable monitor 才安全。
| |
ntpq -p 输出符号(与 chrony 类似):
| |
| 首列符号 | 含义 |
|---|---|
* | system peer,当前同步源 |
+ | 候选源(通过选择算法) |
- | 被聚类剔除 |
x | falseticker |
# | 良好但因源过多未被选中 |
o | PPS 同步的 peer |
| (空格) | 被丢弃(不可达、stratum 过高、环路) |
/etc/ntp.conf 安全基线:
| |
2.4 Windows 时间服务(w32time)
这组命令能干什么:查看/配置 Windows 的 w32time 同步状态与源,强制重同步,查域控 PDC(域内权威时间源),设时区。
| |
Hyper-V/VMware 虚拟机注意:来宾集成服务的"时间同步"会与 NTP 抢控制权,域控/时间服务器上应关闭虚拟化时间同步。
2.5 快速手工校时(应急,不推荐长期使用)
这组命令能干什么:在没配常驻服务时,做一次性的临时对时(会跳变,仅应急)。
3. 常见故障与排错
3.1 时间不同步(timedatectl 显示 System clock synchronized: no)
先记住结论:九成落在这三处——多个时间服务互相打架、UDP 123 出不去/回不来被防火墙挡了、或 NTP 域名解析不了。按"服务冲突 → 端口 → 防火墙 → 源可达 → DNS"顺序查最快。
排查顺序:
| |
| 现象 | 原因 | 解决 |
|---|---|---|
Reach = 0,所有源 ? | UDP 123 被防火墙/云安全组阻断 | 放行出方向 UDP 123(很多云默认放行,但等保加固后常被关掉) |
Cannot talk to daemon | chronyd 未运行 | systemctl start chronyd |
| 端口被占用 | ntpd 与 chronyd 同时启动 | 只保留一个 |
| 容器内不同步 | 容器共享宿主内核时钟,容器内不应跑 NTP | 在宿主机上同步;容器只挂载 /etc/localtime 校正时区 |
| 云主机时间跳变 | 云厂商 hypervisor 时间同步 + NTP 冲突 | 用云内网 NTP(如阿里云 ntp.cloud.aliyuncs.com、169.254.169.123) |
3.2 offset 抖动大 / jitter 高
先记住结论:offset 忽大忽小,根因多半是网络抖、路径不对称、源太少或抹平/非抹平源混用——不是 NTP 算错了,而是"输入的样本本身就脏”。
| 原因 | 判断 | 处理 |
|---|---|---|
| 网络拥塞或链路抖动 | chronyc sourcestats 中 Std Dev 大;ping RTT 波动大 | 换就近服务器;用内网时间服务器分发 |
| 路径不对称 | offset 存在稳定的固定偏差 | 换对称路径;或本地部署 GPS 时钟源 |
| 服务器负载高 | 服务端 t3-t2 大 | 换服务器 |
| 虚拟机 CPU steal | vmstat 中 st 高 | 减少超卖;启用 kvm-clock / hyperv-tsc |
| 源太少 | 只配 1~2 个源 | 配 4 个以上不同机构的源 |
| 混用抹平与非抹平源 | 一部分源被标记 x(falseticker) | 抹平源(Google/AWS)与标准源不可混用 |
3.3 出现 falseticker(x 标记)
先记住结论:x 标记=该源被算法判定"和大多数源矛盾、在说谎"。先确认它是不是 leap smear 源混用、或路径严重不对称,再决定移除。
原因:该源确实时间不对;或它是 leap smear 源而其他不是;或路径严重不对称。处理:移除该源,或统一全部源的抹平策略。
3.4 时间跳变导致应用异常
先记住结论:数据库报"时间倒退"、定时任务重复/漏跑、Java currentTimeMillis() 回退——这些几乎都是一次性大幅 step 跳变惹的祸;治本是"运行时只 slew,启动才允许一次 step",应用侧改用单调时钟。
症状:数据库报"时间倒退"、定时任务重复或漏跑、日志时间乱序、Java 应用 System.currentTimeMillis() 回退。
根因:一次性大幅 step 调整。
处理:
3.5 Kerberos / AD 认证失败(KRB_AP_ERR_SKEW)
先记住结论:域登录、RDP、kinit 报"clock skew",根因就是客户端与 KDC 时间偏差 > 5 分钟——先 chronyc tracking 看 System time 偏多少,再对齐到 DC/PDC 的时间。
症状:域账号登录失败、RDP 报认证错误、kinit 提示 “Clock skew too great”。
原因:客户端与 KDC 时间偏差 > 5 分钟(默认 clockskew)。
正确的 AD 时间架构:PDC 模拟器 → 外部 Stratum 1/2 → 其他 DC 同步 PDC → 成员服务器与客户端同步各自 DC。虚拟化的 DC 必须关闭 hypervisor 时间同步。
3.6 chronyc sources 全是 ? 但 tcpdump 有响应包
先记住结论:能抓到包却显示 ?,说明响应包"内容不合格"——服务端自己没同步(stratum 16 / LI=3)、被限速(KoD)、或 Origin 不匹配被当成伪造包丢弃。
- 检查响应包的
Stratum:若为 16 或 LI=3,说明服务端自己没同步,chrony 会拒绝使用。 - 检查是否为 KoD:
ntp.stratum == 0且 refid 为RATE/DENY→ 被限速或拒绝,换服务器或调大 poll。 - 检查
Origin Timestamp是否匹配:不匹配说明响应被 NAT/中间设备改写或是伪造包。
3.7 服务器被当作 NTP 反射放大源
先记住结论:出方向 UDP 123 突然暴涨打向陌生 IP,基本就是你的 ntpd 暴露了 monlist 被当成放大跳板——立刻 disable monitor + restrict ... noquery,或换 chrony。
发现:出方向 UDP 123 流量暴涨,目标为陌生 IP。
修复:
云安全组:仅放行必要来源的 UDP 123 入方向。
3.8 排错思路总览
先记住结论:时间不对的排查是一条"由粗到细"的链——先看服务在不在、是不是多个服务打架,再看源是否可达(Reach 377),最后看偏差/抖动/时区。时刻记住"时区错 ≠ 时间错"。
| |
重要区分:时区错(显示差 8 小时)与时间错(UTC 本身不准)是两个完全不同的问题。前者用
timedatectl set-timezone,与 NTP 无关。
4. 与其他协议对比
| 维度 | NTP | SNTP | chrony | PTP (IEEE 1588) | systemd-timesyncd |
|---|---|---|---|---|---|
| 性质 | 协议 + 参考实现 ntpd | NTP 的简化子集 | NTP 的另一实现 | 独立协议 | SNTP 客户端实现 |
| 规范 | RFC 5905 | RFC 4330(已归并) | 实现 RFC 5905 | IEEE 1588-2019 | 实现 SNTP |
| 端口 | UDP 123 | UDP 123 | UDP 123 | UDP 319(事件)/ 320(通用) | UDP 123 |
| 精度 | LAN 0.1 | 较低(无滤波) | 同 NTP,收敛更快 | 亚微秒~纳秒 | 毫秒级 |
| 时间戳位置 | 软件(用户态/内核) | 软件 | 软件(支持硬件时戳) | 硬件(网卡 PHY) | 软件 |
| 多源统计 | 有(选择/聚类/合并) | 无 | 有,算法更优 | 有(BMCA 最佳主时钟算法) | 无(单源) |
| 网络要求 | 普通 IP 网 | 普通 IP 网 | 普通 IP 网 | 需支持边界/透明时钟的交换机 | 普通 IP 网 |
| 断网/间歇连接 | 一般 | 差 | 优秀(专为笔记本/虚机设计) | 一般 | 一般 |
| 可作服务端 | 是 | 否 | 是 | 是(Master) | 否 |
| 资源占用 | 中 | 极低 | 低 | 中 | 极低 |
| 典型场景 | 传统服务器、大规模授时 | 嵌入式、IoT | 现代 Linux 默认 | 金融交易、5G、工业控制、电力 | 桌面/轻量容器宿主 |
选型建议:
- 普通服务器 / 云主机 → chrony(RHEL 8+、Ubuntu 20.04+ 默认,收敛快、断网友好、无 mode 7 风险)。
- 需要作为大规模内网授时服务器且已有成熟 ntpd 运维体系 → ntpd(注意
disable monitor)。 - 桌面/极简容器宿主 → systemd-timesyncd 足够。
- 微秒级以下需求(高频交易、5G 前传、变电站) → PTP(
linuxptp的ptp4l+phc2sys),并配 GPS/北斗 grandmaster。 - 混合方案:PTP 做机房内高精度分发,NTP 做跨机房/公网兜底。
5. 速查表 / 常见面试题
5.1 命令速查
| 目标 | chrony | ntpd | systemd | Windows |
|---|---|---|---|---|
| 查看源 | chronyc sources -v | ntpq -p | timedatectl show-timesync | w32tm /query /peers |
| 同步状态 | chronyc tracking | ntpstat / ntpq -c rv | timedatectl status | w32tm /query /status |
| 立即校时 | chronyc makestep | ntpd -gq | systemctl restart systemd-timesyncd | w32tm /resync /force |
| 只查询不改 | chronyd -Q 'server X' | ntpdate -q X | — | w32tm /stripchart /computer:X |
| 统计 | chronyc sourcestats | ntpq -c rv | — | w32tm /monitor |
| 配置文件 | /etc/chrony.conf | /etc/ntp.conf | /etc/systemd/timesyncd.conf | 注册表 / w32tm /config |
| drift 文件 | /var/lib/chrony/drift | /var/lib/ntp/ntp.drift | — | — |
5.2 关键数值速查
| 项目 | 值 |
|---|---|
| 端口 | UDP 123(NTS-KE 为 TCP 4460) |
| 报文长度 | 48 字节(不含扩展与 MAC) |
| 时间戳纪元 | 1900-01-01 00:00:00 UTC |
| Unix 换算 | Unix = NTP - 2208988800 |
| 时间戳分辨率 | 2⁻³² s ≈ 233 皮秒 |
| Era 溢出 | 2036-02-07 06:28:16 UTC |
| Stratum 范围 | 0(参考钟)~ 15,16 = 未同步 |
| 默认 poll | 64 ~ 1024 秒(log₂ 值 6~10) |
| ntpd step 阈值 | 128 ms(超过则 step,>1000 s 触发 panic) |
| chrony makestep | makestep 1.0 3 = 前 3 次超 1 s 则 step |
| Kerberos 容忍偏差 | 5 分钟 |
| 推荐源数量 | ≥ 4 个(可靠剔除 1 个 falseticker) |
| monlist 放大倍数 | 约 556 倍(CVE-2013-5211) |
| 公网常用源 | ntp.aliyun.com、ntp.ntsc.ac.cn(国家授时中心)、cn.pool.ntp.org、time.cloudflare.com(支持 NTS) |
5.3 高频面试题
Q1:NTP 如何计算时钟偏移和往返时延?关键假设是什么?
A:用四个时间戳 t1(客户端发送)、t2(服务端接收)、t3(服务端发送)、t4(客户端接收):
offset = ((t2-t1) + (t3-t4)) / 2,delay = (t4-t1) - (t3-t2)。
关键假设是网络往返路径对称(去程与回程延迟相等)。路径不对称会引入约为"不对称量一半"的系统性偏差,这是 NTP 精度的主要限制。
Q2:Stratum 是什么?Stratum 越小越准吗? A:Stratum 表示距离参考时钟的层级:0 是参考钟本体(GPS/原子钟),1 是直连它的主服务器,逐级递增,16 表示未同步。不是越小越准——一个 RTT 300 ms 的远程 Stratum 1 精度可能远不如同机房 RTT 0.2 ms 的 Stratum 3。选源需综合 stratum、delay、dispersion、jitter。
Q3:为什么建议至少配置 4 个 NTP 源? A:NTP 用交集算法剔除 falseticker。1 个源无法判断真伪;2 个源分歧时无法裁决;3 个源能识别 1 个错误源但幸存者仅剩 2 个;4 个及以上才能在剔除 1 个错误源后仍有 3 个源做可靠的聚类与合并。
Q4:slew 和 step 的区别?为什么默认优先 slew?
A:slew 通过调整时钟频率(最大约 500 ppm)让时间缓慢逼近正确值,保证时间单调不倒退;step 直接跳变系统时间,可能造成时间倒退。倒退会破坏数据库事务顺序、定时器、日志时序、分布式租约。因此默认只在启动时允许一次 step,运行中只 slew。
Q5:NTP 用 UDP 而不用 TCP,为什么? A:① 时间同步对延迟确定性要求高,TCP 的重传、拥塞控制、Nagle 算法会引入不可预测的排队延迟,破坏时间戳准确性;② 单次交换即可完成,无需连接状态;③ 开销小,服务端可支撑海量客户端;④ 丢包不影响正确性——下次 poll 重来即可,反而比重传的"过期数据"更好。
Q6:什么是 NTP 反射放大攻击?如何防护?
A:攻击者伪造受害者源 IP,向开放的 ntpd 发送 mode 7 的 monlist 请求(234 字节),服务端返回最近 600 个客户端记录(约 48 KB),放大约 556 倍(CVE-2013-5211),洪水般打向受害者。防护:升级 ntpd ≥ 4.2.7p26;配置 disable monitor;restrict default ... noquery limited;改用 chrony(不实现 mode 7);边界做 UDP 123 出入向限速与源地址校验(BCP 38)。
Q7:chrony 相比 ntpd 的优势? A:① 收敛快(iburst + 更激进的算法,秒级完成初始同步,ntpd 需数分钟);② 断续网络友好(笔记本休眠、虚机迁移后能快速恢复,专门设计了频率补偿);③ 不实现 mode 7,天生免疫 monlist 放大;④ 能在没有网络时靠 RTC 与 drift 保持较好精度;⑤ 支持硬件时间戳与 NTS;⑥ 资源占用更低。现已是 RHEL 8+/Ubuntu 20.04+ 的默认实现。
Q8:闰秒是什么?现代如何处理?
A:为对齐 UTC 与地球自转,在 6/30 或 12/31 末尾插入一秒(23:59:60)。NTP 用报文的 LI 字段提前预告。历史上曾引发大规模故障(2012 年 Linux hrtimer 死锁)。现代主流方案是 leap smear(闰秒抹平):把这 1 秒分散到前后 12~24 小时内逐步微调,客户端无感。抹平源与非抹平源不能混用,否则互判 falseticker。CGPM 已决议最晚 2035 年前取消闰秒。
Q9:NTP 的时间戳纪元是哪一年?如何转成 Unix 时间戳?
A:1900-01-01 00:00:00 UTC(不是 Unix 的 1970)。64 位时间戳高 32 位为秒、低 32 位为小数(分辨率约 233 ps)。换算:Unix = NTP_seconds - 2208988800。32 位秒数将在 2036-02-07 溢出,NTPv4 用 Era 概念处理。
Q10:容器里的时间怎么同步?
A:容器不应该自己跑 NTP。容器与宿主机共享内核时钟(除非用了特殊的 time namespace),容器内改时间要么无效要么会影响宿主。正确做法:在宿主机上运行 chrony 保证时间准确;容器内只需正确挂载时区(-v /etc/localtime:/etc/localtime:ro 或设 TZ 环境变量)。Kubernetes 场景同理,在 Node 层面统一同步。
Q11:NTP 和 PTP 怎么选? A:NTP 是软件时间戳、普通 IP 网即可、精度毫秒级、部署简单,适合绝大多数 IT 场景;PTP(IEEE 1588)用硬件时间戳并需要支持边界时钟/透明时钟的交换机,精度可达亚微秒甚至纳秒,适合高频交易、5G 前传、电力自动化、工业控制。成本与精度成正比,按需选择;常见做法是 PTP 做机房内高精度分发、NTP 做跨域兜底。
Q12:如何确认一台机器的时间是准的?
A:chronyc tracking 看 System time ... slow/fast of NTP time(应在毫秒级以内)、Leap status: Normal;chronyc sources -v 确认有 * 标记的选中源且 Reach=377;timedatectl 显示 System clock synchronized: yes;再用 w32tm /stripchart 或 ntpdate -q 与独立第三方源交叉验证。