timekeeping watchdog expired 时间跳跃的 chrony makestep 与 hwclock 修复

4次阅读

chrony的makestep未生效是因为默认禁用跳变,需显式配置且满足偏差超限、已完成初始同步两个条件;常见原因包括未重启服务、启动时网络不可达导致卡在initializing状态。

timekeeping watchdog expired 时间跳跃的 chrony makestep 与 hwclock 修复

chrony 的 makestep 为什么没生效?

默认情况下 chrony 不会主动跳变系统时间,即使偏差远超阈值——这是设计使然,防止意外跳变破坏日志、数据库事务等依赖单调时间的场景。只有显式启用 makestep 才可能触发跳变,且需满足两个条件:偏差超过设定阈值,且 chronyd 已完成初始同步(即进入“synchronized”状态)。

常见错误是只在 /etc/chrony.conf 中写了 makestep 1.0 -1,但没重启服务,或 chronyd 启动时网络未就绪、NTP 源不可达,导致始终卡在“initializing”状态,makestep 根本不触发。

  • makestep 的第二参数为负数(如 -1)表示“对所有启动阶段生效”,但仅对首次同步有效;后续运行中若时间偏差再次超限,仍需手动干预或配合 chronyc makestep
  • 检查状态用 chronyc tracking,确认输出中 Leap statusNormalSystem time 行有数值,才说明已同步
  • 若 chronyd 启动时网络未通,可加 makestep 1.0 0(0 表示仅对启动后首次同步生效),再配合 network-managersystemd-networkd 的启动顺序控制

timekeeping watchdog expired 错误的真实含义

这不是 chrony 报的错,而是内核在检测到长时间未更新 clock_gettime(CLOCK_MONOTONIC)CLOCK_REALTIME 时触发的 panic 或 warning,常见于虚拟机暂停后恢复、CPU 长时间离线、或系统时间被暴力修改(如直接写 /dev/rtc)导致内核 timekeeper 逻辑失步。此时 chrony 可能还在跑,但内核已拒绝更新时间。

该错误出现后,chronyc tracking 常显示 Leap status: Not synchronised,且 chronyc sources -v 中延迟异常高,因为 chronyd 尝试校正时被内核拦截。

  • 不要立刻执行 hwclock --hctosys,这会加剧失步;先用 cat /proc/sys/kernel/watchdog_thresh 查看当前看门狗阈值(默认 60 秒),再确认是否真有 CPU hang 或 VM pause
  • 在 KVM/qemu 虚拟机中,需确保启用了 kvm-clock(检查 dmesg | grep kvm-clock),并关闭 host-passthrough 模式下不兼容的 TSC 特性
  • 物理机上若频繁触发,检查是否有 bios 时间同步功能(如 Intel RAS “Time Sync”)与 chrony 冲突

hwclock 修复的边界在哪?

hwclock 只操作硬件时钟(RTC),它不能替代 chrony 的时间同步逻辑,也不能修复内核 timekeeper 失步。它的作用非常有限:仅在系统启动早期、chronyd 尚未启动前,把 RTC 时间载入系统时钟;或在关机前把系统时间写回 RTC。一旦 chronyd 运行起来,它默认忽略 RTC,完全依赖 NTP 源。

典型误用是发现时间错乱后执行 hwclock --hctosys && systemctl restart chronyd——这可能导致系统时间瞬间倒退或跳跃,触发应用报错,且 chronyd 启动后仍会按自己的逻辑覆盖。

  • 若 RTC 本身不准(如电池老化),hwclock --show 显示时间与网络时间差几百秒,应先用 hwclock --set --date="2024-06-01 12:00:00" 手动校准 RTC,再重启 chronyd
  • chrony 配置中 rtcsync 选项会让 chronyd 定期(默认 11 分钟)把系统时间写回 RTC,比 hwclock --systohc 更可靠,但前提是系统时间本身已正确
  • 某些嵌入式设备无 RTC,/dev/rtc 不存在,此时 hwclock 直接失败,必须依赖 chrony + makestep 或外部授时源

时间跳跃后最易被忽略的三件事

哪怕 chrony 成功跳变了时间,应用层未必感知一致:日志时间戳、数据库事务 ID、TLS 证书有效期验证都可能因时间突变出问题。这些不是 chrony 能管的,得靠运维动作补救。

  • 检查 journalctl --since "1 hour ago" 是否有大量 clock skew detectedtime jumped backwards 记录,重点排查 rsyslogauditdpostgresql 等对时间敏感的服务
  • docker 容器若使用 --privileged 或挂载了 /dev/rtc,其内部时间可能与宿主不同步,需在容器内也部署 chrony 或使用 docker run --time=...(v24.0+)
  • kubernetes 集群中,node 时间偏差超过 1 秒会导致 kubelet 拒绝上报心跳,Pod 状态卡在 Unknown;此时仅修 chrony 不够,还要 kubectl drain & uncordon 强制刷新节点状态
text=ZqhQzanResources