服务器时间同步配置

结论:服务器时间同步的标准做法是「改时区 + 装 chrony + 指向可靠上游 + 开机自启 + 监控偏移量」五步:先 timedatectl set-timezone Asia/Shanghai,再安装 chrony 并在 /etc/chrony/chrony.conf 里配置 pool/server/allow/makestep,启动后用 chronyc sources -v 与 chronyc tracking 验证。内网机器建议自建 1~2 台时间服务器统一基准,只需在防火墙放行 UDP 123。

时间不准这件事,在单机上只是"日志看着别扭",一旦进入集群就是实打实的故障:分布式锁提前失效、数据库主从复制中断、HTTPS 证书校验失败提示"您的时钟快了"、Kafka/Redis 的消息过期判断错乱、对账系统按时间戳切分出错。更麻烦的是时间跳变——向后跳 1 秒可能让定时任务执行两次,向前跳 1 分钟可能让定时任务整段跳过。所以时间同步不是"装个 ntpdate 定时跑一下"就完事,而是一项需要按规划配置的基础设施。

时间同步先分清三件事:时区、系统时钟、硬件时钟

结论:时间同步管的是「UTC 绝对时刻」,时区只影响显示与日志格式,两者不要混为一谈。把服务器配成 UTC 还是 Asia/Shanghai 是策略问题,但无论选哪个,底层同步的永远是 UTC 时刻。

概念含义查看命令常见误区
系统时钟(System Clock)内核维护的软件时钟,所有程序读的就是它date、timedatectl status认为重启后会保留,实际从硬件时钟初始化
硬件时钟(RTC)主板电池供电的实时时钟hwclock --show误把 RTC 设为本地时间导致双系统时间差 8 小时
时区(Timezone)决定 UTC 时刻如何显示为本地时间timedatectl status改时区当成了"改时间",时间点其实没变
NTP 层级(Stratum)距离基准时钟的跳数,0 为原子钟/GPS,最大 15,16 表示不可用chronyc tracking以为 stratum 越小越准,实际主要看网络质量
偏移量(Offset)本机时钟与上游的差值,chrony 会持续微调chronyc tracking 的 Last offset只看"是否同步",不看 offset 大小

三个必须记住的原则:

  1. 硬件时钟统一用 UTC(timedatectl set-local-rtc 0)。Linux 默认如此,Windows 默认把 RTC 当本地时间,双系统共存时才需要特殊处理。
  2. 永远不要手工 date -s 改时间。手工跳变会打乱 chrony 的漂移估算,还可能让日志时间戳倒流。偏差大时交给 chronyc makestep。
  3. 一台机器只跑一个时间同步服务。chrony、ntpd、systemd-timesyncd 同时运行会互相争夺时钟,出现"A 刚校准 B 又拨回去"的抖动。

第一步:用 timedatectl 设置时区

结论:改时区用 timedatectl set-timezone Asia/Shanghai,改完立刻用 timedatectl status 确认 Local time、Universal time、RTC time 三行。这一步不影响绝对时刻,只影响显示,因此随时可安全执行。

bash
# 查看当前时间状态
timedatectl status

# 列出可用时区(可按关键词过滤)
timedatectl list-timezones | grep -i shanghai

# 设置中国标准时间
sudo timedatectl set-timezone Asia/Shanghai

# 确认硬件时钟使用 UTC(推荐)
sudo timedatectl set-local-rtc 0

# 开启/关闭网络时间同步(启用 chronyd 或 systemd-timesyncd)
sudo timedatectl set-ntp true

# 同步一次硬件时钟:把当前系统时间写入 RTC
sudo hwclock --systohc --utc

timedatectl status 输出中,System clock synchronized: yes 表示当前已与上游同步成功,NTP service: active 表示同步服务在运行。两个都是 yes 才算配置到位。若显示 NTP service: inactive,说明 chrony/timesyncd 没启动或被 mask 了。

第二步:安装并配置 chrony(2026 年主流发行版首选)

结论:新装机器直接用 chrony,它是 RHEL 8/9、Rocky、AlmaLinux、openEuler 与 Ubuntu/Debian 的默认时间同步方案。chrony 相比 ntpd 收敛更快、对虚拟机和不稳定网络更友好,且同时具备客户端与服务端能力。

bash
# Debian / Ubuntu(配置文件在 /etc/chrony/chrony.conf)
sudo apt update && sudo apt install -y chrony

# RHEL / Rocky / AlmaLinux / CentOS Stream(配置文件在 /etc/chrony.conf)
sudo dnf install -y chrony

# 启动并设置开机自启
sudo systemctl enable --now chronyd

# 确认监听 UDP 123(作为客户端时可不监听,作为服务端时必须)
sudo ss -lntup | grep chronyd

chrony 配置文件(以 RHEL 系为例,/etc/chrony.conf;Debian 系为 /etc/chrony/chrony.conf):

ini
# ---------- 上游时间源 ----------
# pool 会自动解析出多个 IP,适合公网;iburst 让启动时前 4 个包间隔 2s,快速收敛
pool cn.pool.ntp.org iburst
pool ntp.aliyun.com iburst
# 内网自建时间服务器优先:prefer 表示优先使用
server 10.0.10.11 iburst prefer
server 10.0.10.12 iburst

# ---------- 服务端能力(仅时间服务器需要)----------
# 允许内网网段向本机同步
allow 10.0.10.0/24
allow 10.0.20.0/24
# 上游全部不可用时,仍以本机作为 stratum 10 的源对外提供服务
local stratum 10 orphan

# ---------- 纠正策略 ----------
# 前 3 次时间更新时,若偏差超过 1 秒则直接跳变(slew 太慢)
makestep 1.0 3
# 时钟频率漂移记录文件,用于断电期间估算
driftfile /var/lib/chrony/drift
# 每 11 分钟把系统时间写回硬件时钟(替代 ntpd 的 11 分钟模式)
rtcsync
# 偏差超过 100 ppm 的测量值视为异常,不用于校准
maxupdateskew 100.0

# ---------- 日志 ----------
logdir /var/log/chrony
log measurements statistics tracking

几个关键参数的含义要理解到位:

  • iburst:启动时连发 8 个包(前 4 个间隔 2 秒),把首次同步从几分钟压到几秒。生产环境务必加。
  • makestep 1.0 3:chrony 默认用 slew(微调频率)慢慢追时间,追 1 秒的偏差要几十秒到几分钟。这个参数表示"前 3 次更新允许一步跳到位",让重启后能快速对齐,之后仍然走平滑微调,避免业务感知到时间跳变。
  • rtcsync:开启后 chrony 会定期把系统时间写回 RTC,关机期间也不会漂移太多。注意它与 hwclock --systohc 不冲突。
  • local stratum 10:让本机器即使失去外网也能继续给内网提供服务,代价是它给出的时间不再权威。生产内网建议配,但要在监控里标注"上游失联"。

第三步:用 chronyc 验证时间同步是否真的生效

结论:验证看两条命令——chronyc sources -v 看上游源状态,chronyc tracking 看当前偏移量与层级。前者确认"连得上",后者确认"准不准",缺一不可。

bash
# 查看上游时间源状态(重点看 Reach、Last sample 两列)
chronyc sources -v

# 查看同步详情(Reference ID / Stratum / Last offset / RMS offset)
chronyc tracking

# 查看每个源的统计(偏移均值、标准差、剩余误差)
chronyc sourcestats -v

# 强制立即跳变对齐(偏差很大且不想等 slew 时用)
sudo chronyc -a makestep

# 作为时间服务器时,查看有哪些客户端在同步
sudo chronyc clients

# 查看某个源的原始 NTP 数据
chronyc ntpdata 10.0.10.11

chronyc sources -v 输出里最容易看错的是这几列:

列含义健康值异常判断
M(模式)^=服务器,==对等体,#=本地参考钟^ 或 =出现 ? 表示尚未建立连接
Stratum上游层级2~4显示 0 表示未同步,16 表示不可用
Poll轮询间隔(2 的幂,秒)6~10(64~1024 秒)长期停在 6 说明网络不稳
Reach最近 8 次轮询成功情况的八进制位图377(全部成功)小于 17 说明丢包严重
LastRx距上次收到回应的时间(秒)小于 Poll 值持续增大说明上游失联
Last sample最近一次测量的偏移,方括号内为实测值绝对值 < 50ms(内网应 < 5ms)超过 1s 需排查

chronyc tracking 里最值得关注的是 Last offset(最后一次测量偏移)与 RMS offset(偏移的长期均方根)。内网环境 RMS offset 通常在 0.1~2ms,公网在 1~30ms。如果 Leap status 显示 Not synchronised,说明上游全部不可用或本地被拒绝。

chrony / ntpd / systemd-timesyncd 到底选哪个?

结论:服务器一律用 chrony;systemd-timesyncd 只适合桌面和极简容器宿主;ntpd 属于历史方案,新项目不再使用。这张对照表可以直接作为选型依据。

对比项chronyntpd(ntp / ntpsec)systemd-timesyncd
定位完整 NTP 客户端 + 服务端完整 NTP 客户端 + 服务端仅 SNTP 客户端
精度(LAN)0.1~2 ms1~10 ms10~100 ms
收敛速度数秒(配合 iburst)数分钟数分钟
虚拟机/云主机表现优秀(针对时钟漂移优化)一般(时钟不稳时易失锁)一般
断网后续航好(driftfile 补偿)好差
能否做内网时间服务器能(allow 指令)能(restrict 指令)不能
默认安装RHEL 8+/Ubuntu 20.04+ 默认需手动安装,RHEL 8 起移除systemd 自带
配置复杂度低中极低
建议场景全部服务器老系统兼容桌面、IoT、最小化镜像

如果机器上已经被安装了 systemd-timesyncd 且你打算改用 chrony,必须先停掉它,否则两者会互相干扰:

bash
# 停用 timesyncd,改用 chrony
sudo systemctl disable --now systemd-timesyncd
sudo apt install -y chrony
sudo systemctl enable --now chronyd

# 确认只有一个在跑
systemctl list-units --type=service | grep -Ei 'chrony|timesync|ntp'

内网自建时间服务器:推荐的标准架构

结论:内网应部署 2 台时间服务器对外同步、其余全部机器指向这 2 台,形成统一时间基准。这样只要 2 台机器有外网 NTP 权限,整个内网的时间就是一致的,既减少外网依赖,也便于审计与排障。

text
        [ 外网 NTP 池 / 运营商 NTP ]  stratum 1~2
                   │  UDP 123
        ┌──────────┴──────────┐
   ntp-master-01           ntp-master-02      ← 仅这 2 台需要公网 NTP 出方向
   10.0.10.11              10.0.10.12
   allow 10.0.0.0/8        allow 10.0.0.0/8
        └──────────┬──────────┘
                   │  内网 UDP 123
   ┌───────────────┼───────────────┐
   应用服务器       数据库服务器        中间件 / 容器节点
   server 10.0.10.11 iburst prefer
   server 10.0.10.12 iburst

落地要点:

  1. 两台时间服务器彼此互指。在 master-01 上写 peer 10.0.10.12,master-02 上写 peer 10.0.10.11,两者互为备份,一台失联时另一台仍能维持。
  2. 客户端必须配两个 server。只配一个,那台挂了整个内网时间就开始漂。
  3. 不要给时间服务器加 VIP 做主备。NTP 客户端按 IP 追踪源,VIP 漂移会让所有客户端的源测量失效,反而更慢。直接用两个 IP 即可。
  4. 容器节点同步宿主即可。容器共享宿主内核时钟,不需要也不应该在每个容器里跑 chrony。
  5. 监控 offset 而不是监控进程。chronyd 活着不代表时间准,应以 node_timex_offset_seconds 或 chronyc tracking 的 Last offset 作为告警指标,建议告警阈值:绝对值 > 100ms 警告,> 1s 严重。

防火墙与安全组:放行 UDP 123

结论:时间同步走 UDP 123,服务端入方向、客户端与服务端出方向都要放行,云平台安全组同样要开。这是内网时间服务器搭完却同步不上的第一大原因。

bash
# firewalld(RHEL / Rocky / AlmaLinux)
sudo firewall-cmd --add-service=ntp --permanent
sudo firewall-cmd --reload
sudo firewall-cmd --list-all | grep ntp

# 等价写法(按端口)
sudo firewall-cmd --add-port=123/udp --permanent

# ufw(Ubuntu / Debian)
sudo ufw allow from 10.0.0.0/8 to any port 123 proto udp
sudo ufw reload

# iptables 直写
sudo iptables -A INPUT -p udp --dport 123 -s 10.0.0.0/8 -j ACCEPT

排查 UDP 123 是否被拦,可以用 nc 或 chronyc 交叉验证:

bash
# 客户端侧探测服务端 UDP 123 是否可达(UDP 探测结果仅供参考)
nc -vzu 10.0.10.11 123

# 更可靠:让 chrony 自己报告源状态
chronyc sources | grep -E '^\^|^\?|^\*'