NTP 时间服务完全指南:chronyd 与 ntpd 自建内网服务器、客户端跨平台配置、以及常用命令与排障
时间不准=证书过期=Kerberos 全炸=HDFS/HBase 数据块错乱=分布式 trace 全拼不上,公司到几十台机器就该自建内网 NTP。本文从 stratum 层级与 UDP 123 基础开始,先给 chronyd vs ntpd 一份《场景+优缺点+性能差》对比表告诉新环境选谁,再分别讲 chrony(RHEL 7+/Ubuntu 18.04+ 默认)与 ntpd 两套从 0→1 搭内网服务器的完整配置,客户端覆盖 Linux chrony / systemd-timesyncd / Windows w32tm / macOS / 旧 ntpd,最后把 chronyc / ntpq / timedatectl / hwclock 常用命令与 8 个高频坑(reach 0、虚拟机跳时、时区 UTC、离线恢复慢、stratum 16、RTC 与系统时钟不同步…)全部列好示例。
NTP 时间服务完全指南:chronyd 与 ntpd 自建内网服务器、客户端跨平台配置、以及常用命令与排障
适用:CentOS 7 / RHEL 7 8 9 / Rocky / AlmaLinux、Ubuntu 18.04
24.04、Debian 1012、Windows Server 2016~2025 / Win10/11、macOS 12+。
一. 前置概念:时间为什么重要 + NTP stratum 层级 + 常见名词
0.1 为什么公司过了 10 台机器就必须自建内网 NTP
时间不准是那种”平时没事,一出就是爆炸级事故”的基础设施:
- Kerberos / AD / LDAP:时间差超过 5 分钟(KDC 默认
clock_skew)就直接拒绝登录,全公司上不了域 - JWT / SSL / 代码签名证书:证书的
notBefore / notAfter是按本机时间比的,时钟差几个月浏览器全报 ERR_CERT_DATE_INVALID - HDFS / HBase / Ceph / etcd / Consul:要求集群节点间时间差 < 100ms,差太多 HDFS 会以为数据块过期、etcd 选主乱跳、Ceph OSD 反复 down
- 分布式链路追踪 / 日志:ELK / Jaeger / Prometheus 都靠
@timestamp串,节点间差 1 秒 trace 直接拼不上、告警全乱序 - 数据库双写 / Kafka exactly-once:用 wall clock 做幂等判断的业务,差 5 秒可能出现丢单或重复扣款
- 安全审计:等保 2.0 要求日志时间戳误差 < 1 秒、要有可信时间源
0.2 NTP 基础:stratum(层级)1~16
flowchart TB S0["Stratum 0<br/>原子钟 / GPS / 北斗 / 铯钟(真实时钟源,不是网络节点)"] S1["Stratum 1<br/>NTP 一级源服务器(直连 Stratum 0)"] S2["Stratum 2<br/>公司内网 NTP 主服务器(对 S1 同步)<br/>← 我们要搭的"] S3A["Stratum 3<br/>业务服务器"] S3B["Stratum 3 ...<br/>办公电脑 / 交换机"] S0 -->|"串口 / PPS / USB 直连"| S1 S1 -->|"UDP 123 同步"| S2 S2 -->|"对下给几百 ~ 几千台"| S3A S2 -->|"对下给几百 ~ 几千台"| S3B
- Stratum 0:真实时钟源,不出现在 NTP 协议里
- Stratum 16:表示”这个服务器根本没同步成功,不可信任”。客户端
chronyc sources看到 Stratum=16 → 当它不存在 - 经验值:内网服务器建议选 4~7 个上游 S1/S2(数量太少不稳定、太多浪费带宽)。国内公开一级和二级 S2 在 §3.1 里列了。
0.3 时间系统里的”几对兄弟概念”
| 术语 | 意思 | 命令看它 |
|---|---|---|
| 系统时钟 (System Clock) | Linux 内核维护的软时钟,开机后所有程序读的就是它 | date / timedatectl |
| 硬件时钟 (RTC / Hardware Clock) | 主板电池驱动,关机走它 | hwclock -r / timedatectl 里 RTC time |
| TAI / UTC / 本地时 / 时区 | UTC=不含闰秒的国际原子时+累计闰秒偏移;本地时=UTC+时区偏移 | timedatectl list-timezones / TZ=Asia/Shanghai date |
| NTP 同步 vs 手动调时间 | 同步是”慢慢拉回”(slew);手动调是”突然跳一下”(step)。生产 step 会把连续日志戳出洞,尽量用 NTP 慢慢拉。 | chrony 的 makestep 控制 step/slew 阈值 |
二. chronyd vs ntpd 深度对比表(选哪个直接看这里)
一句话结论:所有新部署 95% 直接选 chronyd。 只有「你要对接的嵌入式设备/老交换机只支持老 NTP v3 变种 + 有一堆祖传 ntpd 脚本」才守 ntpd。
| 维度 | chronyd(默认推荐) | ntpd(经典 ntp.org 实现) |
|---|---|---|
| 发布 / 维护者 | 2012 年 Miroslav Lichvar 新写,活跃维护中 | 1980s 起的 ntp.org 参考实现,代码量大、bug 出得慢但出了大 |
| RHEL/CentOS 默认 | RHEL 7+ / Rocky / Alma 默认 | RHEL 6 及以前默认 |
| Ubuntu 默认 | Ubuntu 18.04+ 默认(之前用 ntpdate + ntp) | Ubuntu 16.04 及以前默认 |
| 虚拟机/离线恢复速度 ⭐ | 优秀:启动后用 iburst 连发 8 包,数秒内拿到首个样本;离线很久恢复后通常 10~30 秒收敛到 <100ms | 一般:首次冷启动至少 1 分钟;长时间断网后恢复要 5~15 分钟,还有可能卡住不更新 |
| 对抖动网络 / 非对称延迟的补偿 | 自带更好的算法(频率跟踪模型更简单、稳定),无线/跨公网更准 | 也行,但默认配置在坏网络下鲁棒性比 chrony 差 |
| 精度 | 现代机器局域网内都能跑到 ±100us 级,肉眼没差;局域网 chrony 通常略好(更少干扰) | 一样准(NTP 精度瓶颈主要是网络+硬件 PPS,不是实现) |
| 最小上游数 | pool/server 随便写 2 个也能跑,有 local stratum 10 做兜底 | 4~7 个官方起步;少于 4 个可能”找不到 consensus”拒绝 step |
| 系统无网/无上游时 | 支持 local stratum 10 与孤立模式(orphan mode)——断外网也能继续用自己的时钟给内网提供一个统一时间 | 也支持 orphan,但配置更啰嗦 |
| RTC / 硬件时钟同步 | rtcsync 指令直接开启,每 11 分钟把系统时间刷到 RTC;关机时也刷 | 要用额外 hwclock cron 或 -A 参数 |
| 配置文件语法 | /etc/chrony.conf / /etc/chrony/chrony.conf:短小直白,~15 行够用 | /etc/ntp.conf:restrict 权限语法稍复杂,小白容易写错 |
| 管理命令 | chronyc(交互式+子命令,有 help) | ntpq / ntpdc / ntpstat 三件套(ntpdc 在新版已不推荐) |
| 监控/导出指标 | chronyc tracking / sources / sourcestats 直出 JSON-like 文本;社区有 chrony_exporter 给 Prometheus | 要写脚本解析 ntpq -pn,没 chrony 直观 |
| 漂移文件 | driftfile /var/lib/chrony/drift 一个文件搞定 | driftfile /var/lib/ntp/drift + 一堆 stats 文件(statsdir) |
| 安全扩展(NTS / Network Time Security) | chrony 4.0+ 支持 NTS over TLS(时间也能不被中间人污染) | 主分支进展慢,NTS 还没正式合入 |
| 额外功能 | 给 VMs 用 autoselect、对 PTP 硬件时间戳支持更好、leapsectz 直接读 tzdata 的闰秒 | 老而全,支持 broadcast/multicast 自动发现 |
| 适合的场景 | 云主机 / 笔记本 VM / 办公笔记本休眠唤醒 / 网络抖动环境 / 新部署 95% | 真·物理机房+GPS/PPS 直连原子钟 + 一堆老脚本不动 |
| 端口 | 客户端:UDP 123 出方向(发请求);服务端:UDP 123 入方向(对外答)。chronyd 额外 Unix Socket /var/run/chrony/chronyd.sock 给本机 chronyc 用 | 同左,管理走 ntpq 也用 UDP 123 特殊模式包 |
三. 场景快速结论
| 你的场景 | 选哪个服务端? | 选哪个客户端? |
|---|---|---|
| 新机房 100 台以内、CentOS 7+/Ubuntu 20.04+ | ✅ chronyd | ✅ chrony(和服务端同包,省得装两个) |
| 要跟 S350/老 Cisco Catalyst 3560 的 NTP v3 对时 | chronyd(它兼容 NTP v3/v4 协议,默认 v4 自动协商) | 老设备照旧 |
| 有 GPS / PPS / 原子钟直连机器做 Stratum 1 | chronyd 或 ntpd 都行,老运维选 ntpd 更熟 | chrony |
| 纯 Windows AD 环境 | ✅ 直接让 PDC 模拟器角色 DC 对外对时,域内机器自动跟 DC(不用另搭 Linux NTP) | 域控 / w32tm |
| 笔记本 / 经常休眠的 VM / 无线办公机 | ✅ chrony(休眠唤醒秒级同步回来) | ✅ chrony |
| 嵌入式 tiny Linux 只有 8M Flash | chrony 更轻量(~500KB vs ntpd ~2MB) | chrony |
四. 方案 A:chronyd 自建内网 NTP(推荐)
以 RHEL 系(CentOS/Rocky/Alma)路径为主,括号里是 Debian/Ubuntu 的路径差异。Ubuntu 22.04 实测全通。
3.1 选上游服务器(给你的 NTP 对时的”老大哥们”)
不建议直接指向 pool.ntp.org 这种动态 RR,建议写 4~7 个固定 FQDN 并加 iburst。国内常用稳定源:
# 中国 NTP 联盟(edu 背景,Stratum 1/2,非常稳)
server ntp.ntsc.ac.cn iburst
server ntp.aliyun.com iburst
server ntp1.aliyun.com iburst
server ntp.tencent.com iburst
server time1.cloud.tencent.com iburst
# 国内教育网备选
server s2a.time.edu.cn iburst
# 国际兜底(放最后,没国内的优先)
server time.cloudflare.com iburst阿里云
ntp.aliyun.com/ntp1~7.aliyun.com、腾讯ntp.tencent.com/time1~5.cloud.tencent.com、Cloudflaretime.cloudflare.com(全球 Anycast,回国也还行)。
3.2 安装 + 开机启动
# ---- RHEL 系(CentOS 7-9 / Rocky / Alma)----
sudo dnf install -y chrony
sudo systemctl enable --now chronyd
sudo systemctl status chronyd # 看 active (running)
# ---- Debian / Ubuntu 18.04+ ----
sudo apt install -y chrony
sudo systemctl enable --now chronychrony 配置文件路径:
- RHEL 系:
/etc/chrony.conf - Debian/Ubuntu:
/etc/chrony/chrony.conf
3.3 一份可直接抄的 chrony 服务端配置(含关键字解释)
# ---- RHEL 系:覆盖 /etc/chrony.conf ----
cat | sudo tee /etc/chrony.conf > /dev/null <<'EOF'
# ========== 1. 上游服务器(写 4~7 个,iburst 启动时 4 秒打 8 包快速同步)==========
pool 2.centos.pool.ntp.org iburst maxsources 4
server ntp.aliyun.com iburst
server ntp1.aliyun.com iburst
server ntp.tencent.com iburst
server time.cloudflare.com iburst prefer
server ntp.ntsc.ac.cn iburst
# ========== 2. 漂移文件:记录本机晶振偏频,重启后不用重新学习 ==========
driftfile /var/lib/chrony/drift
# ========== 3. makestep 跳时阈值:仅前 3 次更新、若误差 > 1 秒才硬 step,之后一律慢慢 slew ==========
# 虚拟机/新机器首次开机时间差经常有好几小时,不做 makestep 要几个星期才能拉回
makestep 1.0 3
# ========== 4. rtcsync:每 11 分钟把系统时钟刷回主板 RTC,断电不丢 ==========
rtcsync
# ========== 5. 给内核用 PPS/硬件时间戳(带 GPS 卡才打开,普通物理机可注释)==========
# hwtimestamp eth0 minpoll 2
# ========== 6. 允许内网哪些网段来问我(allow 一行一段,写最精确的 CIDR)==========
# 公司内网 VLAN
allow 10.0.0.0/8
allow 172.16.0.0/12
allow 192.168.0.0/16
# 办公 WiFi
allow 100.64.0.0/10
# 别写 allow 0.0.0.0/0 ::/0,会被当成开放反射打 DDoS
# ========== 7. 孤立模式:外网全断时,我仍用 local 时钟作为 stratum 10 对外答 ==========
# 这样即使断外网,全公司几百台机器也会"互相同步到同一个时间"(只是不准 UTC,但至少是统一的)
local stratum 10 orphan
# ========== 8. 密钥 / NTS / 认证(默认 keyfile,没 NTS 需求就这样)==========
keyfile /etc/chrony.keys
# 开启 NTS(NTP over TLS,防中间人,chrony 4.0+,需要证书)
# ntsserver cert /etc/pki/chrony/ntp.crt key /etc/pki/chrony/ntp.key
# ntsserver port 4460
# ========== 9. 闰秒:直接读系统 tzdata,不用自己下 leap-seconds.list ==========
leapsectz right/UTC
# ========== 10. 日志(出问题好回查;正常跑可以关掉省 I/O)==========
logdir /var/log/chrony
log tracking measurements statistics
EOFDebian/Ubuntu 版文件放
/etc/chrony/chrony.conf,其余内容 100% 通用,driftfile 路径换成/var/lib/chrony/chrony.drift即可。
关键字释义速查:
| 指令 | 含义 | 注意事项 |
|---|---|---|
pool xxx iburst maxsources N | 从一个 DNS RR 池里挑 N 台 | iburst = 启动时 4 秒打 8 包快速收敛,建议每个 server/pool 都加 |
server xxx iburst prefer | 指向单个服务器;prefer 表示其他条件相同时优先选这台 | 别给太多 prefer,一个就行 |
driftfile <path> | 保存本机晶振偏频(PPM) | 路径所在目录必须可写,chrony 用户权限 |
makestep <阈值> <N> | 启动前 N 次更新时误差>阈值就硬 step,之后慢慢 slew | 1.0 3 是最佳实践,调太小会 step 太频繁 |
rtcsync | 每 11 分钟把系统时钟刷 RTC | 有 VM 会关 RTC,没效果但无害 |
allow <CIDR> | 允许哪些 IP 段来请求你(服务端必加) | 小白最容易忘 → 客户端永远 REACH=0 |
local stratum 10 orphan | 当所有上游挂了,我对外宣称 stratum 10 | 一定加!断外网不至于全公司时钟各奔东西 |
hwtimestamp <if> | 启用网卡硬件时间戳 | 物理机千兆网卡普遍支持,精度从 ms 级到 us 级 |
leapsectz right/UTC | 自动处理闰秒 | 需要系统有 right/ 时区数据(glibc 都带) |
log tracking measurements statistics | 三档日志;measurements 每个样本都写,一天几十 MB | 排障完可以关掉 |
3.4 开防火墙 + SELinux
# ===== firewalld(RHEL 系默认)=====
sudo firewall-cmd --permanent --add-service=ntp # NTP 协议=UDP 123
sudo firewall-cmd --reload
sudo firewall-cmd --list-services # 看到 ntp 就对了
# ===== ufw(Ubuntu / Debian 默认)=====
sudo ufw allow from 10.0.0.0/8 to any port 123 proto udp comment 'NTP from Corp LAN'
sudo ufw allow from 172.16.0.0/12 to any port 123 proto udp
sudo ufw allow from 192.168.0.0/16 to any port 123 proto udp
sudo ufw reload
# ===== SELinux(RHEL 系):chronyd 端口默认就在策略里,一般不用额外动作,确认一下 =====
sestatus | head -3
sudo ausearch -m avc -ts recent # 空的就 OK3.5 重启 chronyd + 三条验收命令
sudo systemctl restart chronyd
sleep 6
# ===== 验收 1:sources(选了哪些源、状态如何)=====
chronyc sources -v
# 关键列:
# S(状态) = ^ 服务器 / = pool / # 本地RTC / ? 不可达
# State = * 正在跟它同步 / + 是健康候选 / - 健康但被淘汰 / ? 不可达 / x 假时间(falseticker)
# LastRx = 距上次收到回复多久(秒),理想 32~1024
# Reach = 8 位十六进制,'377' 表示最近 8 次请求全收到回包(⭐最关键!!=0 才算通)
# Stratum:上游层级,16=不可信
# 理想输出第一行的最后应该有一个 *
# MS Name/IP address Stratum Poll Reach LastRx Last sample
# ===============================================================================
# ^* ntp1.aliyun.com 2 6 377 34 -1423us[-1428us] +/- 33ms
# ===== 验收 2:tracking(本机自己同步到什么水平)=====
chronyc tracking
# 关注字段:
# Stratum → 本机层级(上游 S2 + 1 = S3 正常)
# Leap status → Normal(00)= 没闰秒安排;Add second / Delete second = 马上闰秒
# Last offset → 最近一次调整和 UTC 差多少秒(±0.000xxx 就很好)
# RMS offset → 长期均方根误差,理想 < 0.010(局域网<1ms)
# Root delay / Root dispersion → 越小越好
# ===== 验收 3:sourcestats(每个上游的抖动/偏移统计)=====
chronyc sourcestats -v
# SampleCount > 10 说明已经学习了一会,Freq / Skew 指标稳了小抄:
chronyc sources里 Reach 第一位变成非零就说明 UDP 123 通了;* 号出现就代表”已经在跟着某源同步”,一般 10~30 秒内出。
3.6 让 chronyd 开机后即使没上游也”看起来已经同步”(系统工具不认 unsync)
很多系统脚本 / systemd-time-wait-sync.service 会等 TimeSync=yes。加:
# RHEL 系
sudo tee -a /etc/sysconfig/chronyd >/dev/null <<'EOF'
OPTIONS="-s"
EOF
# Ubuntu / Debian
sudo tee -a /etc/default/chrony >/dev/null <<'EOF'
OPTIONS="-s"
EOF-s = 启动时先从 RTC 设一次系统时间(RHEL 默认行为,但 Ubuntu 需要手动加)。
五. 方案 B:ntpd 自建 NTP(老环境兼容)
同样建议能不用就不用,除非维护了 10 年的祖传
restrict notrap noquery配置不想动。
4.1 安装 + 开机启动
# RHEL 7/8/9
sudo dnf install -y ntp ntpstat
sudo systemctl disable --now chronyd # chrony 和 ntpd 冲突,关一个
sudo systemctl enable --now ntpd
# Ubuntu 22.04
sudo apt install -y ntp ntpstat
sudo systemctl disable --now chrony
sudo systemctl enable --now ntp4.2 一份可复制的 /etc/ntp.conf(服务端模板)
cat | sudo tee /etc/ntp.conf > /dev/null <<'EOF'
# ========= 1. 上游 =========
server ntp.aliyun.com iburst
server ntp1.aliyun.com iburst
server ntp.tencent.com iburst
server time.cloudflare.com iburst
server ntp.ntsc.ac.cn iburst
# ========= 2. 孤立模式(上游全挂时当 Stratum 8 对外)=========
server 127.127.1.0
fudge 127.127.1.0 stratum 8
# ========= 3. 漂移 + 统计 =========
driftfile /var/lib/ntp/drift
statsdir /var/log/ntpstats/
statistics loopstats peerstats clockstats
filegen loopstats file loopstats type week enable
filegen peerstats file peerstats type week enable
filegen clockstats file clockstats type week enable
# ========= 4. restrict 权限:先 deny all,再一条条放(最容易写错的部分)=========
restrict default kod nomodify notrap nopeer noquery # 外部默认只能给我提供时间、且不能操控我
restrict -6 default kod nomodify notrap nopeer noquery
restrict 127.0.0.1 # 本地全部权限(给 ntpq 本机管理用)
restrict ::1
# 内网允许同步(不允许管理)
restrict 10.0.0.0/8 mask 255.0.0.0 nomodify notrap nopeer noquery
restrict 172.16.0.0/12 mask 255.240.0.0 nomodify notrap nopeer noquery
restrict 192.168.0.0/16 mask 255.255.0.0 nomodify notrap nopeer noquery
# ========= 5. 加密 =========
#crypto # 有对称对称/非对称 Autokey 才开
includefile /etc/ntp/crypto/pw
keys /etc/ntp/keys
trustedkey 1
EOFrestrict 关键字逐个翻译:
| 关键词 | 效果 | 要不要加给内网客户端 |
|---|---|---|
kod | Kiss-of-Death:客户端太暴力问就发”别问了”包 | 加给 default,对内网别加 |
nomodify | 不让对方通过 ntpq/ntpdc 改我配置(安全) | 所有非本机都要加 |
notrap | 不让对方 trap 模式(抓日志流) | 加 |
nopeer | 不接受对方作为 peer(对称对时模式),只接受 server | 加,防止陌生人跟你对等 |
noquery | ntpq/ntpdc 远程读状态也不允许 | 对内网不要加(否则管理机 ntpq -p 不到) |
noserve | 连时间都不提供,纯我自己当客户端 | 不写 |
4.3 防火墙 + 验收
防火墙和 chrony 一样(NTP=UDP 123),略。
验收三件套:
sudo systemctl restart ntpd
sleep 10
ntpq -p
# 关键列:
# remote = 上游;前缀 * 已同步、+ 备选、x 被算法判假时间、. 候选池成员、空格不可达
# refid = 上游在跟谁同步(.GPS./.PPS./.LOCL. 或 IP)
# st = stratum;t = type;when = 距上次询问多久秒;poll = 轮询间隔(2^N 秒)
# reach = 八进制,和 chrony 一样,全 377 最理想
# delay / offset / jitter = 延迟/偏移/抖动,越小越好
ntpstat # 这个命令输出一行最直观:synchronized to (IP) at stratum X
watch -n 2 'ntpq -p ; echo ----; ntpstat'六. 客户端配置(Linux chrony / systemd-timesyncd / Windows / macOS / ntpd)
5.1 Linux 客户端推荐:chrony(和服务端同包,省得装两份)
最精简 /etc/chrony.conf(Ubuntu:/etc/chrony/chrony.conf):
# 内网两台 NTP 主备
server ntp01.mycompany.com iburst
server ntp02.mycompany.com iburst
driftfile /var/lib/chrony/drift
makestep 1.0 3
rtcsync
# 客户端别写 allow,别把自己也变成服务器对外答开机关机启动:
sudo systemctl enable --now chronyd
sleep 4 ; chronyc tracking5.2 Linux 客户端轻量选项:systemd-timesyncd(无 chrony 依赖,只有客户端功能)
Ubuntu 20.04+、Debian 11+、RHEL 9 都自带,只做客户端、不能对外当服务器:
# 关掉 chrony / ntpd 其中之一,跟 timesyncd 只留一个
sudo systemctl disable --now chrony ntp 2>/dev/null || true
# 写配置
sudo mkdir -p /etc/systemd/timesyncd.conf.d
cat | sudo tee /etc/systemd/timesyncd.conf.d/10-mycompany.conf > /dev/null <<'EOF'
[Time]
NTP=ntp01.mycompany.com ntp02.mycompany.com
FallbackNTP=ntp.aliyun.com time.cloudflare.com
RootDistanceMaxSec=5
PollIntervalMinSec=32
PollIntervalMaxSec=2048
EOF
sudo systemctl restart systemd-timesyncd
sudo systemctl enable systemd-timesyncd
sudo timedatectl set-ntp true # 设为用 NTP 同步(开 timesyncd)
timedatectl timesync-status # 看同步状态(和 chronyc tracking 同级命令)
timedatectl status # 会显示 System clock synchronized: yes + NTP service: active对比 chrony:systemd-timesyncd 只做 SNTP(简单 NTP,不是完整 NTP 算法),精度一般 100ms 级,办公机/普通业务够;对时钟精度有要求的数据库/etcd 节点还是上 chrony。
5.3 Linux 客户端 ntpd(兼容旧)
cat | sudo tee /etc/ntp.conf > /dev/null <<'EOF'
# 只写内网主备,不需要 restrict allow 啥的(我是客户端)
server ntp01.mycompany.com iburst
server ntp02.mycompany.com iburst
driftfile /var/lib/ntp/drift
restrict default nomodify notrap nopeer noquery
restrict 127.0.0.1
EOF
# RHEL
sudo systemctl enable --now ntpd ; sleep 8 ; ntpq -p
# Ubuntu(服务名为 ntp,不带 d)
sudo systemctl enable --now ntp ; sleep 8 ; ntpq -p5.4 Windows:域控 / 工作组 / 普通 PC
5.4.1 有 AD 域(99% 公司场景):只在 PDC 模拟器 DC 上手工指上游,域内机器自动跟 DC 同步
在 PDC(五大角色持有者)上管理员 CMD:
:: 指向两台内网 NTP + 一个公网兜底
w32tm /config /manualpeerlist:"ntp01.mycompany.com,0x9 ntp02.mycompany.com,0x9 ntp.aliyun.com,0xa" /syncfromflags:manual /reliable:YES /update
w32tm /config /update
net stop w32time & net start w32time
w32tm /resync /rediscover /nowait
:: 看 Source / Stratum / Last Successful Sync Time
w32tm /query /status
:: 打 5 包看 offset
w32tm /stripchart /computer:ntp01.mycompany.com /dataonly /samples:5域内其他机器(DC + 客户端 + 服务器)啥都不用改,默认走域层级自动:客户端 → 本地站点 DC → PDC Emulator。
0x9/0xa 这两个 flag 的含义:
0x1= SpecialPollInterval(按 SpecialPollInterval 定时间隔轮询,默认 3600s)0x8= Client mode(NTP 客户端模式)0x9 = 0x1 | 0x8= 常用”专用对等体 + 客户端模式”0xa = 0x2 | 0x8= UseAsFallbackOnly + Client(兜底)
5.4.2 工作组 / 非域机器 / 个人 Win10/11:
管理员 CMD:
w32tm /config /manualpeerlist:"ntp01.mycompany.com,0x9 ntp.aliyun.com,0x9 time.cloudflare.com,0x9" /syncfromflags:manual /update
w32tm /config /update
net stop w32time & net start w32time
w32tm /resync /force图形界面(个人 PC):设置 → 时间和语言 → 日期和时间 → 立即同步 → 换服务器地址点”立即同步”。
5.5 macOS / OS X
# 终端命令(需要 sudo)
# 设置 NTP 服务器(systemsetup 一次只设一个,多台用逗号分隔传给 timed)
sudo systemsetup -setnetworktimeserver "ntp01.mycompany.com"
sudo systemsetup -setusingnetworktime on
# 手动触发一次强制同步
sudo sntp -sS ntp01.mycompany.com
# 查看当前配置与同步状态
sudo systemsetup -getnetworktimeserver
sudo systemsetup -getusingnetworktime
# 查看 timed 守护进程日志(排查同步失败)
log show --predicate 'subsystem == "com.apple.time"' --last 1h图形界面:系统设置 → 通用 → 日期与时间 → 源 → 自定义:写 ntp01.mycompany.com。
七. 常用命令速查(chrony / ntpd / timedatectl / hwclock 四张表)
所有命令”非 root 用户看状态都不写 sudo,只有写/重启/set 才写 sudo”。
6.1 chronyd 客户端/服务端都用 chronyc
| # | 命令 | 作用 | 什么时候用 |
|---|---|---|---|
| 1 | chronyc sources -v ⭐ | 列出所有上游 + Reach/Stratum/State | 第一眼看通不通:有没有 *、Reach != 0、St != 16 |
| 2 | chronyc sourcestats -v ⭐ | 每个源的抖动/样本/频偏统计 | 同步了还不稳时看是哪个源飘 |
| 3 | chronyc tracking ⭐ | 本机自己同步水平:Stratum/Last offset/RMS offset/Leap | 常用一句话判断:“sync 好了没” |
| 4 | chronyc activity | 多少台 peer 在线/离线/可达 | 脚本健康检查一行拿 |
| 5 | chronyc makestep | 立即硬 step 一次(忽略阈值) | 手动把大误差(>1s)直接拉回,不用等三次更新 |
| 6 | chronyc burst 4/10 <server> | 对某源打 4 个 burst 包 | 重启 chronyd 嫌慢手动打 |
| 7 | chronyc offline -a / online -a | 所有源离线/上线(笔记本合盖前/后) | 避免 suspend 恢复后一大堆历史超时 |
| 8 | chronyc serverstats | 服务端统计:收到多少请求/哪些 IP | 想看”今天多少客户端问了我” |
| 9 | chronyc clients | 最近客户端列表 IP/历史请求数 | 排查谁在暴力问(DDoS 前观察) |
| 10 | chronyc refresh | 强制重新解析所有 server FQDN | DNS 换 IP 了不重启 chronyd 生效 |
| 11 | chronyc reselect / chronyc reselectdist 0 | 立刻重新选 best source | 某个源挂了不等算法自动 |
| 12 | chronyc waitsync 30 0.01 | 阻塞等 30 秒或同步到 <10ms 才返回 | CI 里脚本跑前先等同步,不会拿错时间戳 |
6.2 ntpd 三件套
| # | 命令 | 作用 | chrony 对应 |
|---|---|---|---|
| 13 | ntpq -pn ⭐ | 列源 + reach/offset/jitter,-n 不反解 IP | chronyc sources -v |
| 14 | ntpstat | 一行输出同步状态 | `chronyc tracking |
| 15 | ntpq -c rv | 看变量:stratum/offset/jitter/rootdisp | chronyc tracking |
| 16 | ntpdate -d ntp01.mycompany.com | 不设时钟、仅调试客户端能不能收到回复 | chronyc burst + LastRx |
| 17 | ntpq -p -c as | 查看 association id + 是否选上 | chronyc activity |
| 18 | ntpd -gq | 一次 step 然后退出(开机前校准常用) | chronyc makestep |
6.3 时钟/时区/系统硬件互相同步:timedatectl + hwclock
| # | 命令 | 作用 | 备注 |
|---|---|---|---|
| 19 | timedatectl status ⭐ | 一屏全览:时区 / NTP 服务是否 active / System clock synchronized / RTC time | 每次接手一台新机第一条查 |
| 20 | timedatectl list-timezones | grep -i shanghai | 找时区字符串 | 永远用这个拼 Continent/City,不要手动 ln -sf /usr/share/zoneinfo/… /etc/localtime |
| 21 | sudo timedatectl set-timezone Asia/Shanghai | 设置时区 | 完了所有进程读 TZ 会自动更新(Java 进程除外,JDK 读的是启动那一刻缓存的,要重启) |
| 22 | date / date -Iseconds / date -u | 看本地时间 / ISO8601 / UTC | 拿时间戳的最小命令 |
| 23 | sudo timedatectl set-time "2026-08-27 15:03:00" | 手动设时间(生产禁用,除非断网没同步) | NTP 开着时会报 “Automatic time synchronization is enabled” → 先 sudo timedatectl set-ntp false |
| 24 | sudo timedatectl set-ntp true / false | 开/关 systemd NTP 服务(timesyncd 或 chrony 接管的那个) | |
| 25 | hwclock -r / hwclock --show | 读主板 RTC | timedatectl 也会显示 RTC time |
| 26 | sudo hwclock --systohc ⭐ | 把系统时钟 → 硬件时钟(对好了 NTP 后刷回 RTC,防止关机丢) | chrony 的 rtcsync 每 11 分钟自动做这个 |
| 27 | sudo hwclock --hctosys | 把硬件时钟 → 系统时钟(RTC 比系统准的极罕见情况) | systemd 带了 systemd-hwdate.service 开机已经做过 |
| 28 | sudo hwclock --set --date="2026-08-27 15:03:00" | 改 RTC | 除了 BIOS 没电导致 RTC 回到 1970/2000,否则别碰 |
| 29 | timedatectl show | 机读格式拿状态 | 脚本里用 |
6.4 Windows w32tm 常用
| # | 命令 | 作用 |
|---|---|---|
| 30 | w32tm /query /status | 本机同步状态 |
| 31 | w32tm /query /peers | 我正在跟哪些 peer 同步 |
| 32 | w32tm /query /configuration | 所有 w32time 注册表配置大 dump(排查组策略) |
| 33 | w32tm /resync /rediscover /force | 立即重同步,忽略冷却时间 |
| 34 | w32tm /stripchart /computer:ntp01 /dataonly /samples:5 | 连打 5 包看 offset |
| 35 | w32tm /config /update | 应用了新配置后刷新 |
| 36 | net stop w32time & w32tm /unregister & w32tm /register & net start w32time | w32time 炸了/报错 1290 直接重置服务(最狠招) |
八. 8 个最高频的坑(按出现率排序)
🐞 1. chronyc sources 里 Reach = 0 / Stratum 全 16 / ^? xxx ...
99% = 网络没通。 一步步查:
# ① DNS 能解析吗?
getent hosts ntp01.mycompany.com
# ② UDP 123 能出去吗?(NTP 是 UDP,不能 nc -zv,用 chronyd/ntpdate 调试更准)
sudo chronyd -Q -q 'server ntp01.mycompany.com iburst' # 调试模式跑一次,退出码 0=拿到了样本
# ③ 服务端防火墙漏开 UDP 123?上服务端:
sudo ss -ulpn | grep :123
# ④ 服务端写 allow 了吗?(chrony.conf)没有 allow 客户端永远 Reach=0
# ⑤ AWS/阿里云安全组、OSI 4-7 层 ACL、公司出口防火墙是不是挡了 UDP 123?🐞 2. chronyc tracking 里 System time 永远不 “synchronized: yes”
- 等够时间:冷启动一般 10~30 秒。用
chronyc waitsync 30 0.01阻塞等一下 - 上游只有一个/全挂了:chrony 找不到”可信的共识”会一直等。再加 1~2 个上游
- 本机时间差太大 + makestep 没开:
date先看一下,误差>几小时的话开 makestep 1.0 3 然后重启 chronyd
🐞 3. 虚拟机 / VMware / KVM / 笔记本合盖后唤醒,时间差几分钟到几小时
- chrony 首选:
makestep 1.0 3+rtcsync。休眠唤醒后 chrony 30 秒内自动收敛 - 同时关 VMware Tools / open-vm-tools 的 “跟宿主机同步时间”:否则宿主机不准会把你硬拽回(Tools 的同步跟 chrony 打架,时间来回跳)
# VMware: 把 tools.syncTime = "FALSE" 放进 .vmx;或者在虚拟机里: vmware-toolbox-cmd timesync disable # open-vm-tools: 编辑 /etc/vmware-tools/tools.conf 设 time.synchronize.tools.enable=false sudo sed -i 's/^time.synchronize.tools.enable.*/time.synchronize.tools.enable=false/' /etc/vmware-tools/tools.conf 2>/dev/null || true sudo systemctl restart open-vm-tools 2>/dev/null || true - Hyper-V / KVM:看
virt-manager→ VM → 显示 → “Clock” 里不要勾选 “Sync host time with guest”
🐞 4. 时区 UTC / 本地时区 / 时间差 8 小时
根因:把系统时钟设成本地时间了(Windows 默认;Linux 默认 UTC)。永远用 UTC 当系统时钟,时区偏移交给 /etc/timezone。
# 正确姿势:
sudo timedatectl set-timezone Asia/Shanghai
timedatectl # 看 TZ/System clock synchronized/在 UTC 那一栏一致就对了
# 错误姿势(不要做):
# sudo ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime 这会导致 RTC=local time有一台 Windows + Linux 双系统机器时间差 8 小时的经典坑:Windows 默认 RTC=本地时间,Linux 默认 RTC=UTC。统一方式(推荐改 Windows 让 RTC=UTC,不要反过来改 Linux):
Windows 管理员 CMD → reg add "HKLM\System\CurrentControlSet\Control\TimeZoneInformation" /v RealTimeIsUniversal /t REG_DWORD /d 1 /f
然后把 Windows NTP 重新同步一次。🐞 5. ntpq -p 一直显示 .INIT. / reach=0
同 chrony 的坑 1,另外还有一个 ntpd 独有的:
restrict default ... noquery noserve如果你把 noserve 写到 restrict 里了,上游会连时间都不回给你。检查 restrict 行不要乱加 noserve。
🐞 6. 时间对但日志/程序看的还是旧时间
- Java / Go / 部分 daemon 进程启动时会缓存时区+闰秒偏移。改了
timedatectl set-timezone后一定要重启这些进程。最常见的是 Java 应用。 - 验证:
sudo cat /proc/<PID>/environ | tr '\0' '\n' | grep TZ,如果进程自己显式设了 TZ,系统设置无效。
🐞 7. Kerberos 报错 “Clock skew too great” / kinit 失败
- KDC 与两端机器时间差超 5 分钟
- 全量排查:
for h in kdc01 kdc02 app01 app02; do ssh $h timedatectl status | head -4; done,看 Time zone、System clock、NTP service 三样是不是一致 - 紧急临时修:KDC + 客户端都
chronyc makestep立刻对齐,然后再找根因(比如有台机器 chronyd 根本没开)
🐞 8. RTC / 主板电池没电(BIOS 时间回到 2000-01-01 或 1970)
# 症状:关机后再开机时间全错;chrony 即使同步了关机一丢
sudo hwclock -r # RTC 直接读错成 1970/2000- 短期:
timedatectl set-timezone+ 开rtcsync/每次hwclock --systohc顶一顶 - 根治:换主板 CR2032 电池(台式机 3 元钱,服务器要联系供应商)
附录:NTP 新部署自检清单(6 条勾完再上线)
- 服务端:
chronyc sources→ 有一个*,Reach 列至少有非零值,Stratum <= 10 - 服务端:
chronyc tracking→ Leap status = Normal,RMS offset < 100ms - 服务端:内网任意一台新机
chronyc -h ntp01.mycompany.com sources能拿到响应(或直接chronyd -Q -q 'server ntp01 iburst') - 客户端:
timedatectl→ NTP service: active,System clock synchronized: yes,TZ 统一 Asia/Shanghai(或你所在时区) - 跨平台:Windows
w32tm /query /status的 Source 指向你 PDC/内网 NTP,Stratum 不是 0 或 16 - 监控接入:Prometheus + node_exporter 暴露
node_ntp_offset_seconds/ chrony_exporter 暴露chrony_tracking_last_offset_seconds,设告警 > 500ms warning、> 5s critical
延伸:如果你机房有 GPS/北斗 PPS 卡想搭真 Stratum 1,或想上 PTP/IEEE 1588(给金融交易/5G/TSN 亚微秒级同步),可以按 chrony 的
hwtimestamp+pps文档或 Linux PTPptp4l / phc2sys体系再做一层;大多数场景到 NTP + chrony 内网两台主备已经够用。