不想半夜爬起来处理监控告警?不想看到日志时间跳来跳去?那就老老实实把Linux时钟同步这件事搞定。这个标题看起来简单,但里面坑不少——从ntpdate到ntpd再到chrony,工具选型、时区设置、防火墙策略、虚拟化环境下的特殊处理,每一项踩过坑的人都懂。这篇文章我会把Linux时钟同步从原理到实操完整讲一遍,重点聊chrony的配置和排查思路,附上我平时处理问题时的习惯做法。
1. 为什么时钟同步是Linux服务器的“隐形地基”
很多刚接触Linux运维的朋友会觉得时间不准不是什么大事,顶多差个几秒。但等你真正跑起分布式应用、数据库集群、日志采集分析的时候,就会发现时间不同步带来的麻烦远超想象。
1.1 时间偏差会引发哪些真实故障
先说一个最典型的场景:数据库主从复制。MySQL或者PostgreSQL在做主从同步的时候,如果两台机器时间差超过一定阈值,从库会直接拒绝应用binlog,报出类似“Slave I/O thread”的错误,整个复制链路中断。你排查半天网络、账号权限,最后发现就是时间差了30秒,那种感觉真的哭笑不得。
再比如Kubernetes集群。K8s的证书机制、Pod调度、事件记录都强依赖时间一致性。如果节点时间漂移,kubelet的证书校验可能直接失败,节点状态变成NotReady。我在生产环境遇到过最夸张的一次,一台物理机时间快了将近10分钟,结果整个Node上的Pod全部被驱逐重建,业务抖动特别明显。
日志系统也一样。ELK或者Loki这类日志平台,如果各服务器时间不一致,你排查问题的时候按时间线去追日志,会发现同一个请求的日志散落在不同的时间点,顺序完全是乱的,排查效率直线下降。
1.2 时钟同步的核心原理简述
Linux系统里其实有两个时钟:一个是硬件时钟(RTC,Real Time Clock),就是主板上的那块电池供电的时钟芯片,系统关机了它还在走;另一个是系统时钟(System Clock),由内核维护,系统运行时所有进程读取的都是这个时间。
开机时,系统会从硬件时钟读取一次时间作为初始值,之后系统时钟就独立运行了。问题是,无论是硬件时钟还是系统时钟,都有晶振漂移的问题,时间久了自然会产生偏差。时钟同步要做的,就是通过NTP(Network Time Protocol)协议,定期从上游时间服务器拉取标准时间,校准本地系统时钟;同时可以通过hwclock命令把系统时间写回硬件时钟,保证重启后也准确。
注意:NTP协议本身是基于UDP 123端口的,无论是ntpd、chrony还是systemd-timesyncd,都是这个端口。配置防火墙的时候别搞错了。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 工具选型:ntpdate、ntpd、chrony到底怎么选
现在主流的Linux发行版里,常见的时钟同步工具就那么几个。选型这件事,我建议直接按系统版本来,新系统用chrony,老系统继续ntpd,都别折腾。
2.1 几种方案的横向对比
这里我整理了一个表格,可以直观地对比一下:
| 工具 | 首次同步速度 | 同步精度 | 是否常驻后台 | 配置复杂度 | 适用场景 |
|---|---|---|---|---|---|
| ntpdate | 快,秒级完成 | 较差,适合一次性粗同步 | 否,执行完就退出 | 极简单 | 临时校准、脚本里调用 |
| ntpd | 慢,渐进校准 | 较高,适合长期运行 | 是 | 一般 | 老版本系统(CentOS 6等) |
| chrony | 快,秒级完成且精度高 | 高 | 是 | 简单 | 新版本系统(CentOS 7+、Ubuntu 18.04+) |
| systemd-timesyncd | 较快 | 中等 | 是 | 极简单 | 轻量场景、桌面环境 |
很多人会问,既然chrony又快又准,为什么还有ntpd存在?主要还是历史原因。CentOS 6及更早的版本,标配就是ntpd,用习惯了就不想换。但如果你在CentOS 7或者Ubuntu 18.04以上的系统上,我强烈建议直接用chrony,配置文件简单,同步速度还快。
2.2 systemd-timesyncd是个“轻量替代品”
这里要特别提一下systemd-timesyncd。它是systemd自带的SNTP客户端,只能做简单的时间同步,不能提供时间服务给其他机器。对于只要求本机时间准确、不需要给局域网内其他设备提供时间源的场景,它够用了。但它有一个短板:不支持配置多个时间服务器做故障切换,也不支持复杂的策略。
所以我的建议是:生产环境服务器还是用chrony或者ntpd,桌面环境或者临时容器里用systemd-timesyncd就行。
3. 基于chrony的完整实操:从安装到配置再到验证
这一节我直接给出一套能落地的操作流程。我在CentOS 7/8/9、Rocky Linux、Ubuntu 20.04/22.04上都试过,流程基本一致,小细节我会标注出来。
3.1 安装与基础配置
首先是安装。CentOS/RHEL系列:
bash复制yum install -y chrony
systemctl enable chronyd
systemctl start chronyd
Ubuntu/Debian系列:
bash复制apt update
apt install -y chrony
systemctl enable chrony
systemctl start chrony
注意服务名不一样,CentOS上服务名是chronyd,Ubuntu上也是chrony但服务名也叫chrony,其实指的是同一个东西,只是打包的时候命名不同。你直接用systemctl status chrony看看就知道了。
然后是配置文件。默认配置文件在/etc/chrony.conf,我一般会改成这样:
bash复制# 上游时间服务器
server ntp.aliyun.com iburst
server ntp1.aliyun.com iburst
server ntp2.aliyun.com iburst
# 允许本机时间偏差较大时立即调整
makestep 1 3
# 启用RTC时钟跟踪
rtcsync
# 允许其他客户端同步本机时间(如果本机作为内网时间源)
# allow 192.168.1.0/24
# 日志目录
logdir /var/log/chrony
这里有几个关键点要说明:
iburst参数表示第一次同步时快速发送多个请求,让系统在几秒内完成粗同步,而不是慢慢等。makestep 1 3的含义是,如果系统时间偏差超过1秒,且在前3次时钟更新中,就立即跳变校准时间;否则通过逐渐微调(slew)的方式校正。这个参数很实用,避免了ntpd那种时间偏差大时同步极慢的问题。
提示:内网环境推荐设置一个本地时间源。如果公司内部有NTP服务器,直接把
server地址指向内网IP,访问外网NTP服务常常有防火墙限制,而且内网延迟低,同步精度更高。
3.2 验证同步状态
配置完成后,重启服务,然后验证:
bash复制systemctl restart chronyd
chronyc tracking
chronyc tracking的输出里,主要看几个字段:
Stratum:本机所处的层级,数字越小表示越接近权威时间源,一般客户端是3或者4Reference ID:当前同步的上游服务器IPSystem time:系统时间与上游时间的偏差,正数表示本地时间快了Last offset:最近一次校准的偏差量
再配合chronyc sources -v查看时间源状态,如果某个服务器前面是^*,表示这个时间源是当前正在使用的、状态正常;如果是^-,说明这个源被判定为不合格,不会使用。
我用一个示例输出方便你对照:
bash复制# chronyc sources -v
210 Number of sources = 3
.-- Source mode '^' = server, '=' = peer, '#' = local clock.
/ .- Source state '*' = current synced, '+' = combined , '-' = not combined,
| / '?' = unreachable, 'x' = time may be in error, '~' = time too variable.
|| .- xxxx [ yyyy ] +/- zzzz
|| Reachability register (octal) -. | xxxx = yyyy = last sync
|| Log interval in seconds. | | | zzzz = total interval
|| | | | / .- Clock offset
|| | | | | .- Frequency error
|| | | | | .- Residual
|| | | | | .- Skew
|| | | | | .- Root delay
|| | | | | .- Root dispersion
|| | | | | |
MH: M: S: | M: S: | M: S: | M: S: | M: S: | M: S: | M: S: | M: S: ...
^+ ntp1.aliyun.com 2 6 17 25 -167us[ -702us] +/- 21ms
^* ntp.aliyun.com 1 7 17 6 -1032ns[ -212us] +/- 11ms
^+ ntp2.aliyun.com 2 6 17 13 +52us[ -880us] +/- 20ms
3.3 如果系统时间偏差太大怎么办
有时候新上线的机器,时间可能偏了好几个小时,甚至差了好几天。这时候即使配置了chrony,它也需要一段时间来校准。虽然makestep能让它在偏差超过1秒时直接跳变,但如果你希望立刻完成粗同步,最稳的办法是先手动校准一次:
bash复制systemctl stop chronyd
chronyd -q 'server ntp.aliyun.com iburst'
systemctl start chronyd
chronyd -q命令会执行一次同步然后退出,逻辑上相当于手动ntpdate一次。这在初始化系统的时候特别有用,可以在安装脚本里加上这一句,确保服务器首次启动时时间就是准的。
我个人的习惯是把rtcsync加上,这样chrony在每次同步系统时间后会自动把系统时间写回硬件时钟RTC。别小看这个配置,很多服务器重启后时间又飘了,就是因为RTC和系统时间不一致,系统启动时读了一个错误的时间作为初始值。
4. 老系统怎么办:ntpd与ntpdate的兼容方案
虽然新系统用chrony,但存量服务器里还有大量CentOS 6、Ubuntu 16.04之类的老系统,只能跑ntpd。这一节聊聊老系统上的操作,以及新老系统混用时的注意事项。
4.1 ntpd的标准配置流程
CentOS 6上的操作:
bash复制yum install -y ntp
chkconfig ntpd on
vim /etc/ntp.conf
service ntpd restart
/etc/ntp.conf里最核心的内容:
bash复制server ntp.aliyun.com iburst
server ntp1.aliyun.com iburst
server 127.127.1.0 # 本地时钟作为最后兜底
fudge 127.127.1.0 stratum 10
这里127.127.1.0是ntpd内置的本地时钟参考源,fudge把它设置为stratum 10,意思是只有所有外部时间源都不可用时,才会把本地时钟当作时间源。这算是一种兜底策略,保证ntpd不至于因为上游全部不可达而退出。
但说句实话,ntpd的同步速度确实慢。如果系统时间偏差超过1000秒,ntpd的默认行为是拒绝同步的,它会写日志告诉你“time reset”之类的内容。所以我处理老系统时,习惯先跑一次ntpdate强制校准,再启动ntpd:
bash复制ntpdate -u ntp.aliyun.com
service ntpd restart
4.2 新老系统混用的坑
如果你的环境里既有chrony又有ntpd,需要注意一个问题:它们对时间源的选择策略不同,如果两台机器互相把对方当作时间源,可能出现时间“打架”的情况。最稳妥的做法是规划好一台主时间服务器,只让它从外网同步,其他机器全部指向它,形成层级关系。
我在实践中见过一个比较典型的问题:一台chrony服务器和一台ntpd服务器互相指向对方,结果两台机器的时间都在小范围跳动,始终无法稳定。排查到最后才发现是同步环路。解决方式就是理清层级,严禁同层级互相指。
5. 常见问题与排查技巧实录
这篇文章如果没有问题排查部分,总感觉少了灵魂。下面是我整理的一些高频问题和对应的处理思路,都是踩过的坑。
5.1 为什么chronyc sources显示所有时间源都是^?
^?表示该时间源不可达。先检查网络连通性:
bash复制ping ntp.aliyun.com
如果能ping通,再检查UDP 123端口是否被防火墙拦截:
bash复制iptables -L -n | grep 123
firewall-cmd --list-ports
CentOS 7及以上默认用的是firewalld:
bash复制firewall-cmd --permanent --add-service=ntp
firewall-cmd --reload
如果ping不通,就要排查上游DNS解析和路由了。另外还有一种情况,公司出口防火墙上对NTP流量做了限制,特别是只允许访问特定的NTP服务器,这时候需要联系网络管理员确认放行策略。
5.2 为什么设置了rtcsync但硬件时钟还是不准
rtcsync生效有一个前提:chronyd需要能正常同步到上游时间源。如果上游不可达,RTC自然不会被校准。另外,RTC芯片本身也有晶振漂移,rtcsync只会在同步系统时间后把当前系统时间写回RTC,但它不会像NTP那样周期性地修正RTC的漂移。
如果确实需要更精确的硬件时钟校准,可以启用hwclock的systohc功能,或者考虑购买带温补晶振的RTC模块(TCXO),这在一些对时间精度要求极高的嵌入式场景里比较常见。对于普通服务器来说,rtcsync已经足够。
5.3 时间老是跳变而不是缓慢微调,正常吗
如果你在日志里看到时间频繁跳变,首先要确认是不是makestep设置得太激进。makestep 1 3的含义是前3次同步时,只要偏差超过1秒就直接跳变。对于生产环境,我建议把这个值改得保守一点,比如makestep 10 3,只有在偏差超过10秒时才跳变;如果偏差在10秒以内,让chrony通过调整时钟频率的方式渐进式校准,这样对依赖时间连续性的应用(比如数据库、消息队列)更友好。
还有一个容易被忽略的点:如果你跑在虚拟机里,特别是VMware或者KVM环境,要考虑虚拟化时钟的问题。虚拟机的时间漂移往往比物理机严重得多,因为虚拟CPU调度本身会引入延迟。这时候建议给虚拟机也配置NTP同步,而不是依赖宿主机透传时间。另外像VMware Tools里的时间同步插件,和chrony同时开启可能会互相冲突,建议二选一。
5.4 使用date命令验证时间
同步完成后,最直接的验证方式:
bash复制date
hwclock -r
如果系统时间和硬件时间偏差特别大,可以直接手动写入:
bash复制hwclock -w
注意hwclock -w是把当前系统时间写入硬件时钟,hwclock -s是把硬件时钟读到系统。执行前务必要确认系统时间是对的,否则会把错误时间写进RTC,下次开机继续用错误时间启动。
5.5 高频问题速查表
| 现象 | 可能原因 | 处理方式 |
|---|---|---|
chronyc sources全为^? |
网络不通或UDP 123被拦截 | ping测试、检查防火墙 |
同步源前是^- |
该时间源质量差或被判定无效 | 换时间源,去掉多余配置 |
| 时间持续跳变 | makestep配置过激进 | 调大跳变阈值,改成微调 |
| 重启后时间又不准 | 未配置rtcsync或RTC电池耗尽 | 开启rtcsync,检查CMOS电池 |
| 虚拟机时间漂移严重 | 虚拟化时钟不稳定 | 配置NTP,关闭VM Tools时间同步 |
| 日志无任何时间同步记录 | chronyd未启动或配置为空 | systemctl status chronyd查看状态 |
6. 一些关于时间同步的补充建议
最后再啰嗦几句我自己在实际工作中总结下来的经验。
第一,时间同步是基础设施,建议纳入监控。就算你配置好了chrony,时间源故障、网络策略变更都可能导致同步悄悄失效。用Zabbix或者Prometheus监控一下每台机器的system time offset,超过阈值就报警。我一般设50毫秒就告警,虽然普通应用看不出问题,但提前发现总比事后追查好。
第二,内网尽量搭建自己的时间服务器。只需要一台能访问外网NTP的机器,配置好chrony,再加一行allow 192.168.0.0/16,局域网里其他机器都指向它。这样既避免了每台机器都请求外网NTP带来的出口带宽消耗,也降低了对上游时间源的依赖,内网同步延迟还低,精度更高。
第三,容器环境里做时间同步要分情况。Docker容器默认继承宿主机内核时间和/etc/localtime,所以容器里的进程看到的时间和宿主机是一致的,一般不需要单独跑NTP。但如果你用的是Podman、K8s里的某些特殊容器,或者宿主机本身时间漂移了,那就得先保证宿主机时间准确,再考虑容器内的时间配置。容器内跑ntpd这类改系统时间的操作需要CAP_SYS_TIME权限,普通容器默认没有,别白费力气。
第四,还有一个容易被忽略的细节:时区设置和时间同步是两件事。时钟同步保证的是“绝对时间”准确,时区决定的是“显示时间”是什么。建议统一使用timedatectl set-timezone Asia/Shanghai把时区设好,配合timedatectl set-ntp true开启系统自带的NTP服务。很多新手看到date命令输出时间不对,第一反应是去搞NTP,结果发现是时区没设置,白白折腾一圈。
根据我个人经验,Linux时钟同步这件事,做得好的话平时几乎感觉不到它的存在,但一出问题就是大问题。花十分钟把chrony配置好、把监控加上,后面能省下很多熬夜排障的时间。尤其是那些跑着数据库和微服务的机器,时间基准统一了,很多奇怪的问题自然就消失了。希望这篇内容对你部署的时候有帮助,有问题随时在评论区交流。
