使用 Chrony 将原子钟带回家
这是一种设备,最终提供了几代科学家梦寐以求的东西:超精密的时间参考,一种精度令人难以置信的计时工具。这些不是简单的装置;一些物理实验,例如引力理论的验证,需要测量非常小的时间间隔。
美国国家标准与技术研究院 (NIST) 在科罗拉多州博尔德市设有一个实验室,专门运行原子钟并提供美国官方时间。在这个实验室中,NIST-F1 铯原子喷泉钟提供了一个时间参考,精度为 2 × 10-15(十亿分之一的百万分之二),方法是计数铯原子在约 9GHz 时的振动。一种更好的时钟正在研发中。它将测量单个汞离子的共振,频率约为该频率的 100,000 倍,并且精度将提高一千倍。

图 1. 原子钟
真正痴迷于精度的极客们的神圣职责现在已经明确了。他们只需要将他们的 Linux 机器的实时时钟与这样一个极其精确的时钟同步。
当然,您不能直接去电脑商店购买原子钟。(并不是我没试过——哎呀,那个销售员真够厚颜无耻的,居然想把一块镭表盘闹钟塞给我。)下一个最好的选择是无线电同步时钟,并且有各种型号可供选择。它们可以连接到 PC 的串行端口,并提供与 NIST 时钟同步的时间信号。
但是,当设计精良的免费软件可以完成这项工作时,为什么要购买硬件呢?网络时间协议 (NTP) 的创建是为了同步计算机并在网络上分发时间参考。NTP 服务器尽可能地保持时间与官方参考时间接近。远程 NTP 客户端查询这些服务器并同步机器的本地实时时钟 (RTC)。由于分布式计算的性质,计时是一个复杂的问题。在机器之间传播数据包需要非零的可变时间。NTP 中集成了各种校正方案,以考虑可变的延迟。
有几种 NTP 客户端和服务器可用于 Linux。使用 NTP 最简单的方法是启动一个程序,例如 xntpd,并将其指向 NTP 服务器。但是,此程序和大多数其他 NTP 客户端在持续连接到互联网时效果最佳。不幸的是,通过调制解调器的间歇性连接仍然是大多数家庭访问互联网的方式。
这就是 chrony 的用武之地。Chrony 是一个显式支持间歇性连接的程序。它功能全面,但有点令人生畏,因此我们将逐步完成最常见情况的安装和配置:使用调制解调器连接的家庭用户。
Chrony 由 chronyc(一个基于文本的客户端程序)、chronyd(一个作为后台守护进程运行的 NTP 服务器)和各种配置文件组成。要与 chronyd 守护进程 (chronyd) 交互,您需要运行 chronyc 客户端并发出命令。
一些 Linux 发行版包含 chrony 的版本。这个版本很可能是一个较旧的版本,例如 1.15 或更低版本。在这种情况下,您可以在安装新版本之前卸载 chrony 包。
首先,从其主页(请参阅“资源”)下载 chrony tarball。在撰写本文时,当前版本为 1.16.1。它由 1.16 版本和 1.16.1 的补丁组成。我们从 tarball 中提取源代码并应用补丁
tar -zxvf chrony-1.16.tar.gz # extracts source cd chrony-1.16 # dir created from tarball gunzip < ../chrony-1.16-1.16.1-patch.gz | patch -p1 patching file NEWS patching file configure patching file rtc_linux.c patching file version.txt
该程序使用 configure 脚本,这使得自定义变得轻而易举。您需要手动指定的唯一选项是安装目录,使用 --prefix 选项。默认情况下,chrony 会将客户端 chronyc 安装到 /usr/local/bin,并将守护进程 chronyd 安装到 /usr/local/sbin。这相当于
# In the same chrony-1.16 dir as before ./configure --prefix /usr/local一旦您运行了 configure,您可能需要在运行 make 之前清理一下源代码。为什么?因为源代码带有几个语法陷阱,会让 GCC 预处理器抱怨。如果您立即运行 make,您最终会得到大量的警告,例如
warning: extra tokens at end of #endif directive没有任何东西被破坏,但是很容易使其干净地编译。编辑文件 regress.h、reports.h 和 rtc_linux.h。最后一行是 #endif 语句,后跟一个常量名称。您需要注释掉该名称。例如,在 report.h 中,更改
#endif GOT_REPORTS_H为
#endif /* GOT_REPORTS_H */chrony 就会像魅力一样编译。
现在,执行
# In the same chrony-1.16 dir as before make su root # You need to be root to install install
下一步是确保 chronyd 在启动时启动。如果您的发行版附带了旧版本的 chrony,那么您就一切就绪了;只需确保新版本安装在与旧版本相同的位置即可。否则,有几种方法。最简单的方法是在您的 /etc/rc.d/rc.local 中添加 chrony 文档提供的段落。
现在,是时候配置 chrony 了。因为您希望在 NTP 服务器上同步您的机器的时钟,所以您需要选择一个。实际上,您需要选择几个不同的服务器,以防其中一个无法访问。请参阅“资源”中的 NTP 服务器列表的 URL。
该列表将 NTP 服务器分为几个层级。现在,什么是层级?我们这里不是在谈论地质岩层。而是想想洋葱圈。层级 1 由直接与原子钟同步的服务器组成。层级 2 是一组 NTP 服务器,它们由层级 1 提供时间戳,依此类推。远离层级 1,除非您运行物理实验室或您的私有网络拥有数百台机器。层级 1 机器应保留用于将时间参考分发到辅助服务器或无法满足于使用层级 2 带来的几微秒不精确度的机器。为了我们的目的,选择层级 2 甚至层级 3 中的服务器就完全足够了。
请注意,某些 NTP 服务器的管理员要求您在要与他们的机器同步时通过电子邮件通知他们。请这样做。如果一千台家用机器突然开始向一台可怜的大学 NTP 服务器请求时间戳,管理员需要知道这实际上是为了同步时钟,而不是某种新型的洪水攻击。
理想情况下,您应该选择一个离您的机器不太远的 NTP 服务器(在 IP 方面)。但这并不总是与地理位置相同。一个经验法则是检查 traceroute 的输出,它列出了数据包在您的机器和目标之间遍历的系统。例如,由于我住在纽约,所以我选择了以下机器:来自哥伦比亚大学的 ntp.ctr.columbia.edu,来自宾夕法尼亚州立大学的 clock.psu.edu 和来自康奈尔大学的 ntp0.cornell.edu(如果您使用此服务器,请发送电子邮件至 pgp1@cornell.edu)。
成为 root 用户并编辑您的 /etc/chrony.conf 文件以添加这些定义
server ntp.ctr.columbia.edu offline server server ntp0.cornell.edu offline
当然,将这些服务器名称替换为您附近 NTP 服务器的名称。请注意,这些服务器被声明为离线。大多数通过调制解调器连接的机器在启动时不会启动连接。因此,当 chronyd 启动时,它不应开始查询服务器。另外,请注意,chrony 文档坚持您应该使用 NTP 服务器的 TCP/IP 数字地址,以减轻对 DNS 的依赖。好吧,大多数 NTP 服务器的管理员都希望您仅使用 DNS 声明的名称,以便他们保留移动服务器的能力。此外,您的调制解调器连接有望访问您 ISP 的 DNS,因此我建议您在 chrony.conf 文件中使用 NTP 服务器名称。
NTP 协议支持数据包身份验证。毕竟,如果您经营一家公司,您不希望不法分子将您机器的时钟设置为任意时间。带有不正确时间戳的财务记录可能会让您的审计员陷入困境。
Chrony 通过一个简单的密码方案支持该身份验证。您可以定义几个由数字标识的 chrony 用户,并为他们提供不同的密码。chrony.conf 文件中的相关语句是
commandkey 9
keyfile /etc/chrony.keys
这指定此机器使用密钥编号 9 从存储在 /etc/chrony.keys 中的密码中读取密码。后者包含,例如
9 zack
Zack 是我的猫的名字。在我开始使用 chrony 之前,这只野兽是我家里最接近精密时钟的东西。每天早上 7:30,它都会可怜兮兮地喵喵叫,直到我喂它——包括周末。它很快就非常擅长躲避枕头。此外,chrony 需要存储您的机器时钟偏离或漂移 NTP 服务器时间的速率。使用以下方式指定漂移文件的位置
driftfile /etc/chrony.drift
这样,chrony 就不必在每次启动时都累积测量值并重新计算漂移。
您可能在家中有几台计算机。在这种情况下,同步它们的时钟也是一个好主意。默认情况下,chronyd 严格充当相对于您在服务器语句中定义的服务器的 NTP 客户端。但是您可以将 chronyd 设置为充当您自己的子网络的服务器。只需在您的 chrony.conf 中添加一个 allow 语句,并指定一些机器或一个子网络。例如,我的家用机器的以太网卡在(不可路由的)192.168 子网中具有地址,并且充当服务器的机器具有语句
allow 192.168
在其 chrony.conf 文件中。这样,我家中的其他机器可以通过运行 chronyd 和这个简单的配置文件与我的服务器(地址 192.198.0.1)同步
server 192.198.0.1 keyfile /etc/chrony.keys commandkey 9 driftfile /etc/chrony.drift总而言之,您的调制解调器连接机器的 chrony.conf 文件如下所示。注意:将此示例中的 NTP 服务器替换为您在 NTP 服务器列表中选择的服务器(请参阅“资源”)
server ntp.ctr.columbia.edu offline server server commandkey 9 keyfile /etc/chrony.keys driftfile /etc/chrony.drift
因此,现在 chrony 已安装,请验证 chronyd 是否在后台运行(必要时启动它)。请记住,配置文件指定(使用 offline 关键字)chronyd 在未经您许可的情况下不应查询服务器。启动您的调制解调器连接,验证您是否已连接到您的 ISP,然后启动 chronyc 客户端。图 2 显示了一个示例会话。
Password 命令——请注意,您的密码不会回显。
online 命令告诉 chronyd 开始使用 NTP 服务器。
source 命令列出 chronyd 已知的 NTP 服务器:^ 表示服务器,* 表示 chronyd 当前同步到的源,+ 表示其他可接受的源。
层级 2 已经足够好了。
两次服务器轮询之间的时间(以秒为单位)的以 2 为底的对数:7 是 128 秒,8 是 256 秒。
自上次从源接收到样本以来的时间(以秒为单位,除非您看到 m、h、d 或 y 表示分钟、小时、天或年)。
来自上次样本的偏移量测量值。首先是原始测量值,然后是方括号中的实际偏移量,然后是误差幅度。
您在 chronyc 中输入的第一个命令应该是 password 命令。然后,使用 online 命令命令守护进程开始与 NTP 服务器对话。列出 NTP 服务器(sources -v,它是 sources 命令的详细形式)。看到第二列中的波浪号 (~) 了吗?它表示该服务器尚不可用。现在还为时过早;守护进程需要几分钟来累积时间戳并确保 NTP 服务器的响应不是胡言乱语。由于某种宇宙巧合,我的机器时钟与 NTP 时间戳之间的差异恰好是 42 秒(向道格拉斯·亚当斯致敬!)。
稍等片刻,然后发出另一个 sources 命令。过一会儿,您会看到其中一个服务器已被 chronyd 选择(星号出现在第二列中),并且您的机器的偏移量正在减小
^* cudns.cit.cornell.edu 2 6 54 +2999ms[+2999ms] +/- 3653ms
Chrony 缓慢地加速或减慢您的时钟,使其反映 NTP 时间。因此,在几分钟的过程中,通过逐步校正,任何偏移都会消失。
其他有用的命令包括
tracking:显示您的系统时钟的运行情况,即它相对于 NTP 源的快慢。
sourcestats -v:显示 chronyd 对迄今为止从测量中获得的源的看法。
makestep:立即将您的系统时钟设置为 NTP 时间,而不是逐渐倾斜时钟。这相当于设置时间。如果您野蛮地将时间调回,某些版本的 X11 可能会冻结。
最后,请记住在断开调制解调器之前在 chronyc 中发出 offline 命令。否则,chrony 会认为它选择的源已变得无法访问,并会疯狂地尝试选择一个新的源。
您可以猜到,chronyc 恳求自动化操作。您可以轻松创建两个小脚本,它们将 chrony 设置为在线和离线。在线脚本
#! /bin/sh
# This script is called after connect
/usr/local/bin/chronyc <<EOF
password zack
online EOF
应在建立调制解调器连接后调用,离线脚本
#! /bin/sh
# This script is called before disconnect
/usr/local/bin/chronyc <<EOF
password zack
offline
EOF
应在您断开连接之前立即调用。如果您使用特殊的拨号器,请检查它是否具有允许连接后和断开前命令的选项。我正在使用 ATT Global Network 拨号器,它允许我将此类脚本放在其 /opt/attdial/bin 中。如果您使用的是普通的 PPP,您可以将在线脚本插入 /etc/ppp/ip-up 文件,将离线脚本插入 /etc/ppp/ip-down。某些发行版希望您保持 ip-up 和 ip-down 不变,而仅修改 ip-up.local 和 ip-down.local(检查这些文件是否存在)。
我发现 chrony 是通过每周仅运行几个小时的调制解调器连接同步我的机器的理想工具。我要感谢 chrony 的作者 Richard Curnow,他向我发送了宝贵的提示并迅速回答了许多问题。

Fred Mora 自 1990 年以来一直担任 UNIX 系统管理员和开发人员。他出版并与他人合著了几本书籍和技术手册。他正在尽最大努力通过摆弄 Linux 和撰写更多书籍来失去他剩余的理智,并得到了他精通技术的妻子的鼓励。他在 IBM 工作。