
1. 为什么我要用Chrony搭阿里云NTP而不是手动改时间1.1 时间不准到底会踩哪些坑先聊点实在的。你有没有遇到过这种情况服务器上的日志时间对不上排查问题的时候发现A机器报错的时间和B机器差了十几秒本来一条链路就能看明白的事硬是花了一个多小时去对齐时间线。或者更离谱一点调接口的时候服务端一直报签名过期代码翻来覆去看不出问题最后发现是服务器本地时间慢了两分钟。这些场景我在实际运维里都碰到过而且不止一次。时间同步这个问题平时不显山不露水一旦出问题轻则日志错乱、监控告警误报重则证书校验失败、分布式任务重复调度、数据库主从复制报错。尤其是现在很多业务都在上云容器、K8s、微服务这套东西对时间一致性要求非常高节点之间时间差个几秒分布式事务就可能出幺蛾子。手动改时间这种操作说白了就是应急用的不能当常规手段。你手动date一改时间跳变不说还可能引发依赖时间戳的进程异常。而且服务器多了之后一台台登录上去date -s既不现实也不优雅。所以NTP同步是必须做的而CentOS 7这个系统官方推荐的工具已经从ntpd换成了chrony性能更好同步速度更快配置也更简洁。1.2 Chrony和传统ntpd比赢在哪儿Chrony是CentOS 7自带的默认NTP实现很多老运维习惯了ntpd那套其实大可不必。Chrony的核心优势有两个一个是同步速度快一个是长时间离线后能快速校准。传统的ntpd为了保持时间的平滑性会一点一点地微调时间如果偏差太大可能需要好几个小时才能逐步逼近正确时间。而Chrony可以配置makestep策略允许在系统启动时或者偏差超过阈值时直接跳变时间几秒钟之内就能完成同步。这个特性对刚开机、或是刚从快照恢复的虚拟机来说特别实用。另外一个优势体现在网络不稳定的场景。Chrony对网络延迟和抖动有更好的滤波算法即使上游NTP服务器偶尔丢包它也能保持较为精准的本地时间。实测下来在同样的网络环境下Chrony的时钟偏移通常比ntpd更小根因在于它使用了更频繁的时间采样和更合理的权重分配。从配置角度来说chrony的配置文件是/etc/chrony.conf语法比ntp.conf简单不少常用的就几个关键字。而且chronyc这个命令行工具非常好用能直观看到当前同步源、时钟偏移、上次同步时间等信息排障体验比ntpdate好太多了。1.3 为什么选阿里云NTP服务器NTP服务器的选择其实挺有讲究。如果你用的是阿里云的ECS那首选肯定是阿里云提供的NTP地址。阿里云在经典网络和VPC网络内部都有内网NTP地址走内网的话延迟极低、不受公网波动影响同步速度和稳定性都更有保障。即使你用的是其他云厂商的机器或者自己的物理机也可以用阿里云的公网NTP地址比如ntp.aliyun.com这是阿里云对外开放的NTP服务国内访问速度不错。它背后是一组NTP集群会自动做负载均衡比那些随便从网上找来的NTP服务器靠谱得多。我之前见过有小伙伴配置NTP的时候随便填了一个国外的时间服务器地址结果同步一次要等好久偶尔还超时。这跟DNS解析、国际出口带宽都有关系生产环境千万别在这种地方省事。用阿里云NTP至少在连通性和稳定性上是有保障的。2. 准备阶段确认环境、装好Chrony2.1 检查当前系统状态与时间偏差动手之前先花两分钟看看服务器现在的状态。登录服务器后第一件事就是确认系统版本因为CentOS 6和CentOS 7的工具链差异比较大下面的操作都是基于CentOS 7的。cat /etc/redhat-release正常会输出类似CentOS Linux release 7.9.2009 (Core)的内容。接着看一下当前系统时间和时区date timedatectltimedatectl的输出信息更完整能告诉你系统时间、UTC时间、RTC时间、时区以及NTP同步是否启用。如果NTP synchronized后面显示no说明当前没有在做时间同步或者同步还没成功。接下来看时间偏差有多大。如果你手上没有参考时间源可以粗略地拿本机时间和当前真实时间对比一下或者直接看/var/log/messages里有没有相关告警。偏差如果只有几秒问题不大如果差了好几分钟甚至更多后面配置完Chrony之后大概率会触发一次时间跳变这个属于正常现象不用担心。另外检查一下系统里是不是已经有Chrony的包了。CentOS 7最小化安装时可能没有装用下面这个命令确认rpm -qa | grep chrony如果没有任何输出说明还没安装走后面的安装步骤即可。2.2 安装Chrony并处理旧的时间同步服务安装Chrony非常容易直接用yum就能搞定yum install -y chrony装完之后确认一下版本顺便验证一下安装是否完整chronyd --version输出会显示类似Chrony version 3.4的版本号这个版本完全够用。这里有个小坑要提醒一下如果你的服务器之前装了ntpd或者ntpdate并且开机自启了需要先把它停掉并禁用否则两个时间同步服务会互相打架都去改系统时间结果反而更乱。systemctl stop ntpd systemctl disable ntpd另外如果你习惯用ntpdate手动校时配置好Chrony之后就不要再手动跑ntpdate了。Chrony在运行的时候会维护自己的时钟状态你突然手动跳一次时间反而会影响它的校准算法。还有一个容易被忽略的东西/etc/ntp.conf这个文件在装了ntp的机器上可能存在卸载或者停用ntp之后不用去纠结它因为Chrony根本不读这个文件。2.3 内网、公网场景下的NTP地址选择配置之前先想清楚你用的NTP服务器是谁。如果是阿里云ECS而且服务器在VPC内网那么最快的方式是直接用内网NTP地址。阿里云的VPC默认NTP地址是根据地域分配的一般在/etc/chrony.conf里已经预置了装完系统就带着。如果你搞不清楚自己的内网NTP地址是什么可以直接去/etc/chrony.conf里看。阿里云公共镜像默认的配置一般是这样的server ntp.aliyun.com iburst或者写的是内网地址比如server ntp.cloud.aliyuncs.com iburst如果你连的是公网环境那就用阿里云对外开放的公共NTP服务器。阿里云官方提供的公共NTP地址有多个通常我们配置的时候选择ntp.aliyun.com这一个就够了它本身会做解析和负载均衡。这里有一个细节不管用哪个地址建议都要在server后面加上iburst参数。iburst的意思是在刚开始同步的时候会以2秒的间隔连续发送8个请求而不是按照正常的轮询周期慢慢来。这样能让首次同步在十几秒内完成大大缩短等待时间。不加iburst的话首次同步可能要等好几分钟。3. 核心配置把阿里云NTP写进chrony.conf3.1 chrony.conf关键参数逐行解析Chrony的配置文件位置是/etc/chrony.conf安装完之后默认自带了一些配置。我们不需要大改只要理解几个关键参数然后按需调整就行。先看server指令。这是最核心的用来指定上游NTP服务器server ntp.aliyun.com iburst可以写多行写多个server也没问题Chrony会自动选择延迟低、偏差小的服务器作为时间源。不过一般来说指向同一个NTP服务集群就够用了不需要写太多。然后是driftfile参数driftfile /var/lib/chrony/drift这个文件用来记录本地时钟的频率偏移Chrony每次校准之后会把当前系统时钟的漂移率存下来。下次重启服务的时候它能根据这个记录快速估算出本地时钟的运行快慢不用重新花时间慢慢测量。所以这个路径要保持可写别乱删。makestep参数绝对是Chrony的精髓makestep 1 3这句话的意思是如果系统时间偏差大于1秒那么在前3次更新中直接跳变时间而不是慢慢微调。这个策略非常适合物理机时间偏差较大、或者是刚刚启动的虚拟机场景。如果这个参数不配默认情况下Chrony只会微调时间大幅偏差时要等很久才能对准。rtcsync参数rtcsync这个参数让Chrony定期把系统时间同步到硬件时钟RTC上避免每次重启之后时间又回到很久以前。生产环境建议保留。bindaddress和allow参数是用来做访问控制的。如果你只打算让本机同步时间bindaddress可以不用动如果你想把它搭成内网NTP服务器让其他机器来同步那就在配置里加上allow网段后面的章节我会专门讲。3.2 一套可以直接抄的配置模板下面这套配置是我在阿里云ECS上实际用过的可以直接替换/etc/chrony.conf的内容改完重启服务就能用# 上游NTP服务器 server ntp.aliyun.com iburst server ntp1.aliyun.com iburst server ntp2.aliyun.com iburst # 记录时钟漂移 driftfile /var/lib/chrony/drift # 允许系统时间偏差超过1秒时快速跳变 makestep 1 3 # 同步系统时间到硬件时钟 rtcsync # 允许所有来源的NTP请求仅当需要提供时间服务时开启 # allow all # 默认禁用客户端访问如果只是本机同步保持注释即可 # deny all # 日志文件 logdir /var/log/chrony写完之后建议先做一次语法检查其实Chrony配置文件没有那么严格主要看server和allow这些指令有没有拼写错误。检查完直接重启服务systemctl restart chronyd systemctl enable chronydsystemctl enable这步千万别漏了不然重启服务器之后时间同步不会自动启动又回到手动改时间的落后状态了。3.3 防火墙、SELinux与安全组边界配置好之后如果在本机上用chronyc查看同步状态一般来说不需要额外开防火墙端口。因为Chrony客户端发出的是出站UDP 123端口请求而服务器返回的响应属于已建立的连接默认防火墙策略通常不会拦截。但如果你打算把这台机器作为内网NTP时间服务器让其他机器来请求同步那就必须注意入站规则了。NTP使用的是UDP 123端口在firewalld里要放行firewall-cmd --permanent --add-servicentp firewall-cmd --reload这里用的--add-servicentp是firewalld内置的服务定义底层对应的就是UDP 123端口比手动指定端口更语义化不容易记错。如果你用的是阿里云ECS记得还要在安全组里放行UDP 123端口的入方向规则否则外部机器即使防火墙是通的到安全组这一层还是会被拦掉。SELinux这一块CentOS 7默认是Enforcing模式但Chrony官方对SELinux策略的支持已经比较完善了。正常配置NTP服务端和客户端不需要额外调整SELinux的布尔值。如果真的遇到时间同步服务起不来的情况排查的时候可以先看SELinux的avc日志ausearch -m avc -ts recent如果日志里确实有chronyd相关的拒绝记录再考虑是不是要调整策略否则不要一上来就setenforce 0生产环境把SELinux关掉不是个好习惯。4. 启动同步与效果验证4.1 启动服务并设置开机自启配置改好之后启动服务这步就没啥悬念了systemctl start chronyd systemctl enable chronyd然后用systemctl status chronyd看一眼运行状态确保active (running)。如果启动失败大概率是配置文件里的语法有问题或者driftfile目录不可写用journalctl -u chronyd看具体报错就行。这里我再提一个经验改完配置重启服务之后不要马上就去挖同步数据稍微等两三秒让Chrony先发一轮NTP请求。如果server后面带了iburst参数正常情况下10秒以内就能完成第一次同步。4.2 用chronyc命令确认同步状态验证同步是否生效最直接的办法是用chronyc。先看时间源列表chronyc sources -v输出会有一个表格里面的^*符号表示当前正在使用的、正常同步的时间源。^?表示不可达^-或者^表示延迟较大或者被筛选掉了。看到^*就说明这台服务器已经和上游NTP正常通信了。再看详细的同步状态chronyc tracking这个命令输出的信息很丰富我挑几个关键的讲。System time那一行显示的是本机系统时间与参考时间源之间的偏差正常情况下应该在正负几毫秒之内。如果刚配置完可能偏差显示比较大等几分钟再跑一次会逐渐收敛。Last offset是最后一次校准的偏差值Update interval是两次校准之间的间隔Stratum是层级数数字越小越接近权威时间源。还有一个命令也经常会用到就是查看当前所有时间源的具体统计信息chronyc sourcestats -v如果你发现sources里一直是^?说明无法连接上游服务器按第五部分的内容逐步排查。4.3 同步硬件时间与时区调整Chrony本身只管系统时间硬件时间要不要一起管取决于你配没配rtcsync参数。我前面建议配置rtcsync就是为了让系统时间定期回写到硬件时钟RTC上。这样可以避免一个尴尬场景服务器每次重启系统时间都回到几个月前然后又要重新等NTP慢慢校准。如果你之前没配rtcsync并且希望手动同步一次硬件时间可以执行hwclock -w意思就是把当前系统时间写入硬件时钟。另外还有个命令hwclock -s方向相反是把硬件时间写到系统时间一般开机的时候用得上。时区问题也要顺带看一眼。CentOS 7默认时区可能是UTC如果你希望显示成北京时间用timedatectl设置timedatectl set-timezone Asia/Shanghai改完时区之后再执行date确认一下输出。这里要注意一点NTP同步的是UTC时间时区只是影响人类可读的显示方式改时区不会影响NTP同步本身所以放心大胆地改。5. 常见问题与排查技巧实录5.1 同步失败、一直没对上时的排查顺序时间同步失败这个问题我见过太多次了。按照下面的顺序排查大多数情况几分钟就能定位。第一步确认服务状态systemctl status chronyd如果服务没起来直接看日志journalctl -u chronyd -n 50 --no-pager第二步测试到NTP服务器的网络连通性。NTP用的是UDP 123端口用ping测试是测不出来的因为ping走的是ICMP协议即使UDP端口不通ping也可能是通的。更可靠的测试方法是chronyc sources -v如果显示^?再配合chronyc -n sources看解析出来的IP地址。你也可以用telnet测试UDP端口不过telnet默认走TCPNTP是UDP协议所以更合适的工具是ncnc -u -z -w 3 ntp.aliyun.com 123 echo UDP 123 OK或者干脆用chronyd自带的调试模式chronyd -Q -t 3 server ntp.aliyun.com iburst这个命令会以非守护进程的方式强制做一次时间源查询并打印结果如果网络不通这里会直接报错信息比日志更直观。第三步检查防火墙和安全组。本机排查确认udp 123出方向没问题但如果你把别的机器作为客户端来同步这台服务器而失败那就是服务器的防火墙或者阿里云安全组没有放行入方向的UDP 123。按3.3部分操作放行即可。我把常见的失败原因整理成了表格方便你快速对照报错特征可能原因排查命令处理方法sources显示^?网络不通或UDP 123被拦截chronyc -n sources检查防火墙、安全组、上游地址是否可达tracking没有输出服务未运行或配置错误systemctl status chronyd重启服务并查看journal日志同步成功但偏差大本机时钟晶振漂移严重chronyc tracking等待Chrony多次校准确认makestep参数本机同步但其他机器不行服务端未放行或未配置allowfirewall-cmd --list-all放行UDP 123并检查allow配置重启后同步慢driftfile缺失或不可写ls -l /var/lib/chrony/修正目录权限确保drift存在5.2 开机好久才同步、偏移过大的处理有朋友在配置完Chrony之后跟我反馈说开机之后过了十几分钟才看到时间同步成功觉得这玩意儿不靠谱。这里面其实有两层原因。第一个原因是没有用iburst参数导致Chrony按照正常的轮询间隔去请求上游初始同步可能要等个几分钟甚至更久。解决办法就是前面说的server后面加iburst。第二个原因是本机时间偏差太大Chrony默认策略是渐进式微调也就是每次只校正一点点通过拉长和缩短每秒的时长来慢慢纠正偏差。如果时间差了好几个小时这种微调方式就得跑很久。所以makestep 1 3这个参数很重要它允许偏差超过1秒的时候直接跳变。有了它即使服务器停机了半年开机后也能在十几秒内把时间拉回正常范围。我遇到过一种比较特殊的情况物理机的CMOS电池没电了每次断电重启时间都回到2000年附近。这种场景下即使有makestep因为时间偏差实在太大Chrony也可能在个别版本的逻辑下不给力。不过实测CentOS 7自带的chrony 3.4版本配了makestep 1 3之后都能正常跳变问题不大。如果实在担心还可以在配置文件里加一行makestep 1 -1-1表示永远允许在偏差超过1秒时跳变不做次数限制。生产环境一般不建议这么激进但对时间一致性要求极高的场景这招很管用。5.3 关于出入站规则和本地NTP的几个易错点NTP连接需要客户端出站UDP 123服务器入站UDP 123这个前面已经讲过了但我在实际运维中发现还是有很多人在配置的时候漏掉服务端的入站规则。尤其是用阿里云ECS的时候安全组规则和系统内防火墙是两套体系都要检查。另外一个容易踩的坑是如果你把/etc/chrony.conf里的allow注释掉默认策略就是禁止所有客户端访问。这时候你本机作为客户端去同步上游没问题但其他机器想同步你这台机器就会一直显示^?或者连接超时。所以当你确认服务端防火墙和安全组都放行了UDP 123客户端还是连不上的时候回头看一下服务端的allow配置。还有一个隐藏比较深的问题多条时间源同时存在但都没有配置iburst导致客户端开机后长时间无法完成首次同步。解决办法是在所有server行后面都加上iburst确保首次接触时快速握手。最后说一个容易被忽略的在配置NTP客户端时如果上游服务器的本地时间和客户端时间相差太大比如超过了一个小时某些版本的老式NTP客户端会直接拒绝同步因为NTP协议里的校验机制会认为这种大偏差不合法。Chrony的makestep策略本身就是为这种场景设计的所以这个问题在Chrony下基本不会遇到也算是一个选型优势。6. 进阶玩法把时间服务器再往外扩6.1 把当前节点改造成内网NTP服务器实际生产环境里很多公司内部有几十台甚至上百台服务器如果每台机器都直接连公网NTP服务器一方面外网带宽和请求量会被放大另一方面有些内网机器根本访问不了外网。更合理的做法是在内网挑一台机器作为NTP时间服务器其他机器都指向它。改造方法很简单。假设你这台机器已经同步了阿里云NTP现在想让它同时给内网其他机器提供时间服务只需要在/etc/chrony.conf里放行内网网段allow 192.168.1.0/24这里的192.168.1.0/24换成你实际的内网网段。allow后面可以写多个网段也可以写一个具体的IP地址。如果内网网段比较多可以多写几行allow。改完之后重启chronyd再检查一下端口监听ss -ulnp | grep 123正常会看到chronyd监听在0.0.0.0:123或者具体的IP:123上说明服务端已经就绪。然后在其他机器上把/etc/chrony.conf里的server地址改成这台机器的内网IP加上iburst重启chronyd即可。这里有个经验之谈内网NTP服务器的优先层级可以设置为Stratum 10避免它向外传播的时间层级被误认为权威源。在你允许对外提供NTP服务的同时如果想明确告诉客户端“我不是权威时间源”可以在配置里加local stratum 10这个参数的意思是即使这台服务器无法连接上游时间源它仍然可以向客户端提供本地时间并声明自己的层级是10。这个配置在内网测试环境里比较有用生产环境还是要谨慎使用因为一旦上游不可达整个内网都基于一台未同步的机器来做时间基准风险比较高。6.2 给生产环境写一个时间偏差巡检脚本时间同步不是配好就一劳永逸的。虽然Chrony本身很稳定但上游NTP服务器偶尔也会有波动内网服务端的漂移也可能变大。我自己的习惯是写一个简单的巡检脚本每天跑一次把同步状态和偏差记录下来超过阈值就告警。脚本核心逻辑很简单#!/bin/bash OFFSET$(chronyc tracking | grep System time | awk {print $4}) THRESHOLD0.1 if [ $(echo $OFFSET $THRESHOLD | bc) -eq 1 ]; then echo $(date) [WARN] NTP offset ${OFFSET}s exceeds ${THRESHOLD}s /var/log/ntp-check.log fi这个脚本里的OFFSET取的是System time那一行的值单位是秒可能是负数。判断绝对值是否超过0.1秒如果超了就写一条告警日志。有监控系统的话你也可以直接把结果推给Zabbix或者Prometheus用阈值触发告警。配合crontab每天定时执行一次0 */6 * * * /usr/local/bin/ntp-check.sh6.3 我的最后几点运维建议写了这么多最后说几点我自己在实际操作中沉淀下来的体会。第一配置完Chrony之后不要把date手动改时间这个习惯保留下来。手动改时间和NTP自动校时是两套逻辑混用会让Chrony很难判断你的真实时钟漂移长期下来反而降低同步精度。第二不要忽视硬件时钟。很多服务器重启后时间不准问题不在系统时间同步而在于硬件CMOS电池没电了。如果条件允许定期检查一下硬件时间hwclock -r和系统时间的差距差距过大就要考虑更换主板电池或者调整rtcsync策略。第三多级NTP架构下所有节点的时间精度取决于最上游的时间源。如果你的公司有内网NTP服务器尽量让内网服务器直接指向权威或准权威时间源比如阿里云NTP而不是让内网服务器再指向另一台内网服务器层级越深误差累积越大。第四chronyc这个命令行工具没事多看看。Chrony提供的可见性比ntp好太多无论是同步源状态、偏移详情、还是采样统计都有命令可以直接看排查问题时效率翻倍。我自己最常用的就是chronyc tracking和chronyc sources -v配合systemctl status chronyd和journalctl -u chronyd基本能覆盖90%以上的时间同步问题。第五如果是云上环境别忘了安全组和防火墙这两层都要放行UDP 123。系统层面firewalld放行了安全组没放行一样连不上。这个坑我踩过不止一次写出来希望大家少走弯路。时间同步这件事看起来是个小活儿但它是整个运维体系的基础设施。基础不牢上层业务随时可能被时间偏差坑一把。用Chrony把阿里云NTP配好5分钟真能搞定而且一劳永逸省心省力。