CentOS 7上做时间同步,绕不开chrony。我在生产环境里从ntpd切到chrony,踩过的坑比想象中多:时间源配错、防火墙没放行、时区不对、虚拟机时钟疯狂漂移……每次排查到最后都发现根源不复杂,但就是能让人卡上大半天。这篇把配置chrony时间源的核心细节一次讲透,包括为什么CentOS 7默认选它、chrony.conf每项参数怎么理解、chronyc怎么读结果、常见故障怎么定位。适合刚接手CentOS 7系统的运维新人,也适合被时间同步问题折腾过的老手翻一翻。
1. 为什么CentOS 7默认用chrony而不是ntpd
CentOS 7之后的系统已经在默认安装中把chrony作为首选时间同步方案,老牌的ntpd仍然可以装,但官方倾向已经非常明显。很多人一开始都会困惑:ntpd不是挺成熟吗?为什么说换就换?如果时间同步方案本身只是“能同步就行”,那两者确实差别不大;但在精度、速度和抗抖动能力上,chrony确实更有竞争力。
1.1 先从结构说起:chronyd和chronyc
chrony的实现不像老ntpd那样一个进程全包,而是明确分成两个程序。chronyd是常驻后台的守护进程,承担所有NTP网络通信和时钟调整工作;chronyc是命令行客户端,负责和chronyd通信,查看状态、修改配置、强制同步。两者通过本机回环地址交互,装好chrony后直接敲chronyc就能和本地守护进程对话,不需要额外指定IP。
这种拆分带来的好处是权限和工作域的隔离。日常查询和调试不需要碰守护进程本身,管理能力也可以独立授权。实际使用中,chronyc提供的子命令覆盖了状态查看、源切换、手工追时间、客户端统计等几乎所有运维动作,比老NTP工具链用起来顺手得多。
1.2 chrony比ntpd强在哪几个点
第一是启动同步速度。NTP的默认校准方式是一点一点往正确时间上靠,这在偏差小的时候没毛病,但如果系统刚开机或者CMOS电池老化导致时间差出几个钟头,还慢腾腾校正就出问题了。chrony配合配置文件里的makestep指令,只要检测到偏差超过阈值,直接一步跳到正确时间,之后再用微调维持精度。
第二是网络适应性。chronyd在算法层面做了更多功课,它会把每次NTP往返的延迟、偏移都记录下来,通过统计模型估算真实时间偏移及方差,而不是简单相信最近一次结果。网络抖动大的环境下,这个模型能明显减少错误跳跃,也不会因为某一次响应慢就把时间源标记为不可用。
第三是对漂移的自学习。本机晶振频率受温度、电压影响会漂移,chronyd会把这个漂移趋势估算出来并写进driftfile。这样即使系统重启,同步收敛速度也很快,不用重新从头学习一遍。下面这张表可以直观感受两者差异:
| 维度 | chrony | ntpd |
|---|---|---|
| 首次同步速度 | iburst下秒级完成 | 通常较慢,可能要几分钟 |
| 大偏差修正 | makestep直接跳变 | 默认缓慢爬升 |
| 网络抖动适应 | 基于统计模型,更稳健 | 一般,易受瞬时抖动影响 |
| 漂移学习 | 持续写入driftfile,重启后快速收敛 | 也有数据记录,但恢复较慢 |
| 配置文件 | 单文件语法清晰 | 配置分散,部分版本还依赖ntpdate配合 |
1.3 哪些场景建议切到chrony
严格说,在CentOS 7里chrony不是“可选”而是默认方案,系统服务就叫chronyd。如果你某台机器跑的还是ntpd,大概率是早期手动装的。从维护角度讲,官方已经减少对ntpd的投入,新特性基本都在chrony这边,所以建议回归到chrony。
另外,如果网络环境复杂、同步精度要求高,比如有交易审计、日志时间关联需求,chrony的优势就很明显。我见过不少环境要求所有服务器时间误差不超过几百毫秒,用chrony配合局域网内的高质量时间源是可以做到的。反过来,如果只是普通测试机,那用哪个其实差别不大,但既然系统默认给了chrony,就没有必要额外装一套ntpd。
2. 动手前的环境自检与安装
动手配置之前,我习惯先花几分钟看一遍系统现状。这一步能省掉后面很多排查时间,尤其是处理一台已经在跑时间服务的老环境。
2.1 先看时区、时间与同步状态
先执行timedatectl,一口气把时区、当前时间、NTP同步状态都确认了:
timedatectl输出结果里重点看三项。第一是Local time,也就是本地时间,确认它和当前实际时间大致对得上,如果差距离谱,说明硬件时钟或时区可能有问题。第二是Time zone,如果系统是Asia/Shanghai,通常没问题;如果显示成UTC之类,后面所有日志时间都会错乱。第三是NTP synchronized字段,它表示当前日期时间同步服务是否成功启用。看到yes说明之前已经有人管着时间同步,看到no就说明这台机器的时间基本处于没人管的状态。
云服务器初始化镜像一般会把时区预设好,但自建的物理机或者从模板克隆出来的虚拟机经常出问题,所以这一步别跳。时区不对的话,先用下面命令修正:
timedatectl set-timezone Asia/Shanghai改完再执行timedatectl确认。这一步只影响时间的本地展示,和NTP同步本身没关系,但如果你配置好了chrony,却发现“时间差8小时”,八成就是时区问题。
2.2 安装chrony并确认服务运行
CentOS 7的最小化安装一般也带上chrony,但保险起见还是确认一下:
rpm -qa | grep chrony如果没有输出,直接安装:
yum install -y chrony安装完成后,先别急着改配置,把服务状态看一下:
systemctl status chronyd如果显示active (running),说明服务已经在运行。如果显示inactive,让它跑起来再设置开机自启:
systemctl start chronyd systemctl enable chronyd这里有个细节:如果你刚装好chrony,开机自启务必打开,否则下次重启后又会回到没有时间服务的状态。别问我为什么强调,接手的机器里因为漏掉这一步导致时间失准的案例实在太多了。
3. 配置时间源:/etc/chrony.conf逐项拆解
配置chrony的核心就是编辑/etc/chrony.conf。每个发行版默认内容略有不同,但核心语法一致。我接下来说的,都是生产环境里真正用到的项,以及每项背后的道理。
3.1 server、pool和iburst该怎么选
配置时间源最常见的是server指令:
server 某个时间服务器域名或IP iburst比如用公共NTP池:
server 0.pool.ntp.org iburst server 1.pool.ntp.org iburst server 2.pool.ntp.org iburst要留意的是,server一行一个时间源,多配几个相当于给自己加了冗余。chronyd会从中选择最优源,而不是“众人抬轿”。至于iburst是干什么用的:它在服务刚启动时钟偏差较大时,连续发送8个请求加速首轮同步。没有这个参数,首次同步可能要等几十秒甚至更久,加上iburst之后通常几秒内就能完成。基本生产配置里都会加iburst。
除了server,还可以用pool关键字配置一个NTP服务器池。pool背后的机制是DNS解析时会返回一组随机服务器,chronyd自动从这组服务器里挑选。与之相比,server就是固定那几个IP,不会自动轮换。如果公司内部只有两三台固定时间服务器,用server就够;如果走公共NTP服务,用pool更合理。
看一下比较典型的混合配置:
pool 0.pool.ntp.org iburst server 10.0.0.1 iburst server 10.0.0.2 iburst这里内网固定时间源放前面,公共池兜底。chronyd在启动后会同时探测所有源,选中最可信的一个作为主同步源,同步失败时自动切换到其他源。我曾经遇到过内网时间服务器偶尔抽风的情况,公共池的存在让整条同步链没有中断。
3.2 别忽略makestep、driftfile和rtcsync
接下来是三个容易被忽略但极其重要的指令。
第一个是makestep。默认配置里一般是:
makestep 1 3含义是:如果系统时钟和正确时间的偏差超过1秒,那么在启动后的前3次时钟更新时,chronyd直接跳跃调整,而不是一点一点爬。写“1 3”是为了开机阶段快速纠偏;等到系统已经平稳运行,后续同步都走平滑微调,避免服务里的时间突然跳变带来麻烦。如果你发现某台机器重启后时间总是慢了几个小时,加不加makestep会直接决定你是等上半小时还是一分钟。
第二个是driftfile:
driftfile /var/lib/chrony/drift这行让chronyd把测量到的本机晶振漂移率存起来。重启之后,chronyd可以基于历史漂移数据更快收敛。没有driftfile的话,每次开机都要重新学习一遍漂移规律,同步质量会打折扣。
第三个是rtcsync:
rtcsyncrtcsync告诉chronyd:每次系统时间校准完之后,顺手把系统时间写入硬件时钟。CMOS电池供电的硬件时钟本来精度就差,加上长期不校准,偏差只会越来越大。rtcsync相当于让系统时间和硬件时间始终联动。如果不写这一行,重启后系统可能会用一块明显落后的硬件时钟作为初始时间,又得费劲校准一次。
3.3 allow/deny把服务范围管起来
chrony既能做客户端,也能做服务端,给局域网内其他机器提供时间。如果你不需要对外服务,默认配置就够。但如果你开了服务端,就一定要用allow管好范围:
allow 192.168.1.0/24 allow 10.0.0.0/8 deny 0.0.0.0/0allow后面跟网段,含义是只允许这些网段的客户端来查时间。deny 0.0.0.0/0是兜底拒绝,优先级上allow在deny之前,所以具体行为等价于白名单。生产环境里这步不能省,否则相当于把NTP服务裸奔到公网,容易被利用来发起流量放大攻击,虽然端口偶尔看着不起眼,但暴露后消耗的带宽都是实打实的。
3.4 local stratum做本地时钟兜底
还有一个很实用的配置:
local stratum 10意思是:如果chronyd无法从任何外部时间源同步(比如内网断网了),依然把自己宣告为stratum 10的本地时间服务器,让局域网里依赖它的其他机器不至于群龙无首。stratum是NTP的层级概念,值越小代表越接近权威时间源。普通时间服务器的stratum一般在2到4之间,本地兜底的10在时间源层级里已经属于“实在没辙才认”的级别,但总比让客户端完全没有时间来源强。
我在一个内网环境里专门验证过这个场景:把外部网络断开,客户端访问chrony服务端,依然能拿到时间,只是层级偏高。等外网恢复后,chronyd会自动回到正常外部源,整个过程不需要人工干预。
4. 重启服务与验证同步效果
配置文件改完,正式启动验证。这一章我会把生产环境里最常用的验证命令和使用心得一起说。
4.1 重启chronyd并确认状态
每次改完配置文件,都要重启chronyd才能让配置生效:
systemctl restart chronyd systemctl status chronyd如果配置文件语法有错误,服务可能会启动失败。这时可以通过systemctl status的输出或者journalctl -u chronyd查看日志,定位到哪一行配错。还有一个小习惯:改配置之前先备份一份,比如cp /etc/chrony.conf /etc/chrony.conf.bak,回滚起来比重新回忆改了什么快得多。
4.2 chronyc sources结果该怎么读
查看已配置时间源的当前状态,最常用的是:
chronyc sources -v输出结构类似:
210 Number of sources = 3 MS Name/IP address Stratum Poll Reach LastRx Last sample =============================================================================== ^* 192.0.2.1 2 6 37 28 +487us[+501us] +/- 12ms ^- 192.0.2.2 2 6 37 29 -102us[ -98us] +/- 18ms ^? 192.0.2.3 3 6 3 112 -896us[ -896us] +/- 120ms先看第一列M字符。^代表这是一台服务器,=代表对等体。第二列S字符是状态:^*表示这个源正在被chronyd作为当前同步源,^+表示它是候补源并且通过了基本校验,^-表示它可用但优先级较低,^?表示状态未知或不可达。看到一个^*就说明同步链路已经通了。
Reach是最近8次询环的成败掩码,数值是8次询问结果的二进制位掩码换算而来。能达到37这种值说明最近通信基本正常,Reach长期偏低就说明源有问题。
LastRx是多久前收到这个源的上一次响应,单位秒。如果这个值一直增长而没有新响应,说明时间源开始不响应你的请求了。Last sample是最近的偏移样本,比如+487us表示这个源认为本机快了487微秒。
4.3 chronyc tracking和sourcestats进一步确认
想知道当前时间的偏移到底多小,用:
chronyc tracking输出里最有用的是Last offset和System time。System time如果显示0.000000xxx seconds fast,说明系统时间比真实时间快了不到1毫秒。实际运维中,只要偏差在合理范围内就好,不用追求绝对零偏移。
chronyc sourcestats -v可以看每个源更详细的统计信息,包括样本数、频率偏移和残差方差。如果某个源的残差方差明显偏大,说明它不太稳定,这时候优先考虑换掉这个时间源。
如果时间已经差得很远,可以执行:
chronyc makestep手动让chronyd立即执行一次时钟跳跃,把偏差快速抹平。这个命令在服务刚启动、还没完成自动校准的情况下特别有用。执行完再查一下tracking,通常能看到偏移被大幅收敛。
5. 常见问题排查与避坑实录
时间同步相关的故障,九成以上集中在几个地方。这一章按我实际排查的经验把典型问题列出来,基本可以当速查表用。
5.1 时间源状态全是问号怎么办
如果chronyc sources里看到多个^?源,说明chronyd无法对这些源完成有效通信。排查顺序一般是:先确认这台机器能不能访问相应网络,再检查防火墙有没有放行UDP 123端口。云服务器和物理机的防火墙习惯不一样,云上iptables可能没开,但安全组规则里把UDP 123挡了;物理机上firewalld的默认zone也可能拦了入站请求。
简单验证网络通路,可以从其他机器用nc或tcpdump看报文,也可以直接看journalctl -u chronyd里有没有网络不可达的报错。UDP 123如果不放行,概率上讲就是网络配置问题。
5.2 日期没问题但时间总是差8小时
这个坑我在好几个新人团队里见过。系统时间本身是准的,但显示时间总是差8小时,原因是时区配置成了UTC。虽然chrony同步的是UTC时间戳,跟时区设置无关,但本地时间的展现完全由时区决定。处理起来很快:
timedatectl set-timezone Asia/Shanghai执行完timedatectl再确认,显示正常了。这类问题很典型,排查的时候如果发现NTP synchronized是yes,但时间看起来还是不对,第一个就该怀疑时区。
5.3 重启后时间容易跑偏
如果机器每次重启后系统时间都明显落后,多半是rtcsync没配置,或者硬件时钟本身出了问题。先确认是否开启了rtcsync,再手动同步一次硬件时钟:
hwclock --systohc这个命令把当前系统时间写入硬件时钟。加上chrony的rtcsync配置之后,正常就不需要频繁手工处理了。物理机和虚拟机都可能遇到这个问题,尤其在长时间关机或断电后更明显。
5.4 虚拟机环境下时钟漂移更快
虚拟化环境下,时间同步问题比物理机更常见。因为虚拟机的时钟由宿主机调度,CPU频率抖动、电源管理策略都会导致时间漂移更快。基本做法是,虚拟机的chrony配置里保留多个时间源,并开启makestep。如果用的是云主机,平台一般本身就提供了时间同步服务,可以优先把平台提供的时间服务器配置进去,效果更稳。
另外,不建议在虚拟机里同时运行ntpd和chrony两套服务,冲突会造成时钟反复跳跃。装好chrony后把ntpd停掉,并把开机自启禁用,避免下次重启又拉起来。
5.5 chronyc连不上chronyd
执行chronyc sources时如果提示无法连接,说明chronyd没在运行,或者它的本地通信socket有问题。先用systemctl status chronyd看看服务状态,如果是failed,再journalctl -u chronyd查看日志。配置文件写错、端口被占,都会导致启动失败。这种排查下来一般就是恢复chronyd运行,不需要大改配置。
最后再分享一个小经验:关键业务服务器上,建议把chrony日志接进系统日志统一收集,时间同步异常时能第一时间发现,比事后翻记录要省心得多。如果你遇到某台机器长时间同步不上,别死磕配置,先抓包看一眼UDP 123的报文往返,很多时候答案就在网络层。