本文改编自: Control your computer time and date with systemd

大多数人都需要注意时间。我们需要按时起床并通勤上班(如今对我们中的许多人来说通勤相当于一次短途旅行),休息一下吃午饭,赶上项目截止日期,庆祝生日和假期,赶飞机等等.

我们中的一些人甚至沉迷于时间。我的手表采用太阳能供电,可通过位于科罗拉多州柯林斯堡的美国国家标准与技术研究院 (NIST)WWVB 时间信号无线电台获取准确时间。时间信号与原子钟同步,原子钟也位于柯林斯堡。我的小米智能手环同步到我的手机,手机同步到网络时间协议 (NTP) 服务器,最终同步到原子钟。

为什么时间对计算机很重要

我们的设备和计算机需要准确时间的原因有很多。例如,在银行、股票市场和其他金融业务中,交易必须保持正确的顺序,而准确的时间顺序对此至关重要。

我们的手机、平板电脑、汽车、GPS 系统和计算机都需要精确的时间和日期设置。我自己也希望我电脑桌面上的时钟保持准确,这样我就可以依靠我的本地日历应用程序在正确的时间弹出提醒。正确的时间还可以确保 SystemV cron 作业和 systemd 计时器在正确的时间触发。

正确的时间对于日志记录也很重要,因此根据时间定位特定的日志条目会更容易一些。举个例子,有个同学在北卡罗来纳州电子邮件系统的 DevOps 工作。它们每天需要处理超过 2000 万封电子邮件。当相关计算机保持准确时间时,通过一系列服务器跟踪电子邮件或通过使用不同的主机上的日志文件来确定事件的确切顺序会容易得多。

各种时间

Linux 主机有两个时间需要考虑:系统时间和 RTC 时间。 RTC 代表实时时钟,这是系统硬件时钟的一个花哨且不是特别准确的名称。

通过使用系统主板上的电池,硬件时钟持续运行,即使在计算机关闭时也是如此。 RTC 的主要功能是在与时间服务器的连接不可用时保持时间。在个人电脑的黑暗时代,没有互联网连接到时间服务器,所以电脑唯一可用的时间是内部时钟。操作系统在启动时必须依赖 RTC,用户必须使用硬件 BIOS 配置界面手动设置系统时间以确保其正确。

硬件时钟无法理解时区的概念;仅仅是把时间存储在 RTC 中,而不是计算时区或与 UTC(世界协调时间,也称为 GMT 或格林威治标准时间)的偏移量。您可以使用我将在本文后面探讨的工具设置 RTC。

系统时间是操作系统已知的时间。它是您在桌面 GUI 时钟、date 命令的输出、日志时间戳以及文件访问、修改和更改时间中看到的时间。

rtc 手册页包含对 RTC 和系统时钟以及 RTC 功能的更完整叙述。

那么 NTP 是什么呢?

全世界的计算机都使用 NTP(网络时间协议)通过 NTP 服务器的层次结构将它们的时间与互联网标准参考时钟同步。主要时间服务器位于第 1 层,它们通过卫星、无线电或通过电话线的调制解调器直接连接到第 0 层的各种国家时间服务。第 0 层的时间服务可以是原子钟、调谐到原子钟广播信号的无线电接收器,或使用 GPS 卫星广播的高精度时钟信号的 GPS 接收器。

为了防止来自层次结构中较低(即具有较高层数)的时间服务器或客户端的时间请求压倒主要参考服务器,数千个公共 NTP 层 2 服务器是开放的,可供所有人使用。很多需要 NTP 服务器的主机数量较多的组织和用户(包括我)选择自己架设时间服务器,因此只有一台本地主机访问2层或3层时间服务器。然后他们将网络中的其余主机配置为使用本地时间服务器。在我的家庭网络的情况下,这相当于是一个第 3 层服务器。

在 Linux 系统中的 NTP 实现方案

最初的 NTP 软件方案是 ntpd,目前又有了两个较新的方案,chronyd 和 systemd-timesyncd。这三个都使本地主机的时间与 NTP 时间服务器保持同步。 systemd-timesyncd 服务不如 chronyd 强大,但对于大多数用途来说已经足够了。如果 RTC 不同步,它可以进行大的时间跳跃,如果本地系统时间有点漂移,它可以逐渐调整系统时间以与 NTP 服务器保持同步。 systemd-timesync 服务不能用作时间服务器。

Chrony 是一个强大的 NTP 方案,包含两个程序:chronyd 守护进程和一个名为 chronyc 的命令行界面。Chrony 有一些特性使其成为许多环境的最佳选择,主要是:

  1. Chrony 可以比旧的 ntpd 服务更快地同步到时间服务器。这对于不经常运行的笔记本电脑或台式机很有用。
  2. 它可以补偿波动的时钟频率,例如当主机休眠或进入睡眠模式时,或者当时钟速度因频率步进而变化时,这会在负载低时降低时钟速度。
  3. 它处理间歇性网络连接和带宽饱和。
  4. 它针对网络延迟和延迟进行调整。
  5. 在初始时间同步之后,Chrony 从不停止时钟。这确保了许多系统服务和应用程序的稳定和一致的时间间隔。
  6. 即使没有网络连接,Chrony 也可以工作。在这种情况下,可以手动更新本地主机或服务器。
  7. Chrony 可以充当 NTP 服务器。

你需要知道的是,NTP 是一种使用 Chrony 或 systemd-timesyncd.service 在 Linux 主机上实现的协议。

NTP、Chrony 和 systemd-timesyncd RPM 包在标准 Fedora 存储库中可用。 systemd-udev RPM 是一个基于规则的设备节点和内核事件管理器,默认情况下随 Fedora 安装但未启用。

您可以安装所有三个并在它们之间切换,但大多数情况下你只需要安装其中一个就行了。 Fedora、CentOS 和 RHEL 的最新版本已经从 NTP 转移到 Chrony 作为它们的默认计时实现,并且它们还安装了 systemd-timesyncd。我发现 Chrony 运行良好,提供比 NTP 服务更好的界面,提供更多信息,并增加控制选项,这些对于系统管理员来说都是极好的功能。

使用 systemd-timesyncd 实现 NTP

虽然 Chrony 有诸多的好处,但是本文想要介绍的是 systemd-timesyncd 的使用方法。systemd-timesyncd 较为简洁,功能简单,但是这是 systemd 项目自带的计算机时间软件。对于大多数使用者来说,功能也足够使用了。

禁用其他 NTP 服务

NTP 服务可能已经在您的主机上运行。如果是这样,您需要在切换到其他 NTP 服务之前禁用原来的服务。我一直在使用的是 chronyd,所以我使用以下命令来停止和禁用它:

1
2
3
# systemctl disable chronyd ; systemctl stop chronyd
---
Removed /etc/systemd/system/multi-user.target.wants/chronyd.service.

开始前检查状态

systemd 时间同步的状态指示 systemd 是否已启动 NTP 服务。因为你还没有启动 systemd NTP,timesync-status 命令没有返回任何数据:

1
2
3
# timedatectl timesync-status
---
Failed to query server: Unit dbus-org.freedesktop.timesync1.service not found.

但是直接的状态请求提供了一些重要信息。例如,不带参数或选项的 timedatectl 命令暗示 status 子命令为默认值:

1
2
3
4
5
6
7
8
9
# timedatectl status
---
Local time: Fri 2021-11-12 09:20:34 CST
Universal time: Fri 2021-11-12 01:20:34 UTC
RTC time: Fri 2021-11-12 01:20:34
Time zone: Asia/Shanghai (CST, +0800)
System clock synchronized: no
NTP service: inactive
RTC in local TZ: no

这将返回主机的本地时间、UTC 时间和 RTC 时间。显示系统时间设置为 Asia/Shanghai 时区,RTC 设置为格林威治时间,NTP 服务未激活。 如果 RTC 时间偏离了系统时间,请不要诧异,对于时钟未同步的系统,这是正常现象。主机上的漂移量取决于自系统上次同步以来的时间量以及每单位时间的漂移速度。

设置时区

通常,您在安装过程中已经设置了计算机的时区,并且永远不需要更改它。如果你需要更改时区,可使用一下方法。

Linux 使用时区文件来定义主机使用的本地时区。这些二进制文件位于 /usr/share/zoneinfo 目录中。我的时区的默认值由链接 /etc/localtime -> ../usr/share/zoneinfo/America/New_York 定义。

您需要知道您所在位置的官方时区名称。假设您要将时区更改为洛杉矶,首先列出有哪些时区:

1
2
3
4
5
6
7
8
9
10
# timedatectl list-timezones | column
---
<SNIP>
America/La_Paz Europe/Budapest
America/Lima Europe/Chisinau
America/Los_Angeles Europe/Copenhagen
America/Maceio Europe/Dublin
America/Managua Europe/Gibraltar
America/Manaus Europe/Helsinki
<SNIP>

找到你要设置的时区的名字后就可以设置时区了。我使用 date 命令来验证更改,但您也可以使用 timedatectl:

1
2
3
4
5
6
7
8
9
10
# date
---
Tue 16 Nov 2021 04:47:49 PM EDT

# timedatectl set-timezone America/Los_Angeles
---

# date
---
Tue 16 Nov 2021 01:48:23 PM PDT

您现在可以尝试使用 timedatectl set-timezone 命令修改时区。

配置 systemd-timesyncd

systemd 时间同步守护进程提供了一个易于在 systemd 上下文中管理的 NTP 实现。它默认安装在 Fedora 和 Ubuntu 中,默认在 Ubuntu 中启动,但 Fedora 不默认启动。我不确定其他发行版;您可以通过以下方式检查您的系统是否启动 systemd-timesyncd:

1
# systemctl status systemd-timesyncd

systemd-timesyncd 的配置文件是 /etc/systemd/timesyncd.conf。这是一个简单的文件,包含的选项比旧的 NTP 服务和 chronyd 少。以下是我的 Fedora VM 上此文件默认版本的完整内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#  This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Entries in this file show the compile time defaults.
# You can change settings by editing this file.
# Defaults can be restored by simply deleting this file.
#
# See timesyncd.conf(5) for details.

[Time]
#NTP=
#FallbackNTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org 2.fedora.pool.ntp.org 3.fedora.pool.ntp.org
#RootDistanceMaxSec=5
#PollIntervalMinSec=32
#PollIntervalMaxSec=2048

除了注释之外,它包含的唯一部分是 [Time],所有行都被注释掉了。这些是默认值,不需要更改或取消注释(除非您有理由这样做)。如果您没有在 NTP= 行中定义特定的 NTP 时间服务器,Fedora 的默认设置是使用 Fedora 时间服务器池。我喜欢使用自定义的时间服务器,比如使用腾讯云的时间服务器。

1
NTP=time3.cloud.tencent.com

启动时间同步

启动和启用 systemd-timesyncd 就像任何其他服务一样:

1
2
3
4
5
6
7
# systemctl enable systemd-timesyncd.service
---
Created symlink /etc/systemd/system/dbus-org.freedesktop.timesync1.service → /usr/lib/systemd/system/systemd-timesyncd.service.
Created symlink /etc/systemd/system/sysinit.target.wants/systemd-timesyncd.service → /usr/lib/systemd/system/systemd-timesyncd.service.

# systemctl start systemd-timesyncd.service
---

设置硬件时钟

这是我的一个系统在启动 timesyncd 后的样子:

1
2
3
4
5
6
7
8
9
# timedatectl    
---
Local time: Sat 2020-05-16 14:34:54 EDT
Universal time: Sat 2020-05-16 18:34:54 UTC
RTC time: Sat 2020-05-16 14:34:53
Time zone: America/New_York (EDT, -0400)
System clock synchronized: yes
NTP service: active
RTC in local TZ: no

RTC 时间与当地时间 (CST) 相差大约 1 秒,并且在接下来的几天内差异会增加几秒。因为 RTC 没有时区的概念,timedatectl 命令必须做一个比较来确定哪个时区是匹配的。如果 RTC 时间与本地时间不完全匹配,则认为它不在本地时区。

为了寻找更多信息,我检查了 systemd-timesync.service 的状态,发现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# systemctl status systemd-timesyncd.service
---
● systemd-timesyncd.service - Network Time Synchronization
Loaded: loaded (/usr/lib/systemd/system/systemd-timesyncd.service; enabled; vendor preset: disabled)
Active: active (running) since Sat 2020-05-16 13:56:53 EDT; 18h ago
Docs: man:systemd-timesyncd.service(8)
Main PID: 822 (systemd-timesyn)
Status: "Initial synchronization to time server 163.237.218.19:123 (2.fedora.pool.ntp.org)."
Tasks: 2 (limit: 10365)
Memory: 2.8M
CPU: 476ms
CGroup: /system.slice/systemd-timesyncd.service
└─822 /usr/lib/systemd/systemd-timesyncd

May 16 09:57:24 testvm2.both.org systemd[1]: Starting Network Time Synchronization...
May 16 09:57:24 testvm2.both.org systemd-timesyncd[822]: System clock time unset or jumped backwards, restoring from recorded timestamp: Sat 2020-05-16 13:56:53 EDT
May 16 13:56:53 testvm2.both.org systemd[1]: Started Network Time Synchronization.
May 16 13:57:56 testvm2.both.org systemd-timesyncd[822]: Initial synchronization to time server 163.237.218.19:123 (2.fedora.pool.ntp.org).

请注意表示系统时钟时间未设置或向后跳的日志消息。时间同步服务根据时间戳设置系统时间。时间戳由 timesync 守护程序维护,并在每次成功的时间同步时创建。

timedatectl 命令没有能力从系统时钟设置硬件时钟的值;它只能根据在命令行中输入的值设置时间和日期。但是,您可以使用 hwclock 命令将 RTC 设置为与系统时间相同的值:

1
2
3
4
5
6
7
8
9
10
11
12
# /sbin/hwclock --systohc --localtime
---

# timedatectl
---
Local time: Mon 2020-05-18 13:56:46 EDT
Universal time: Mon 2020-05-18 17:56:46 UTC
RTC time: Mon 2020-05-18 13:56:46
Time zone: America/New_York (EDT, -0400)
System clock synchronized: yes
NTP service: active
RTC in local TZ: yes

--localtime 选项确保硬件时钟设置为本地时间,而不是 UTC。

你真的需要 RTC 吗?

任何 NTP 实现都会在启动期间设置系统时钟,那么使用 RTC 是否必要呢?我认为不一定,只要您的计算机可以连接到时间服务器就可以了。但是,许多系统无法全天候的访问网络连接,因此硬件时钟非常有用,因此 Linux 可以读取它并设置系统时间。这是比手动设置时间更好的解决方案,即使它可能会偏离实际时间。

总结

本文探讨了使用一些 systemd 工具来管理日期、时间和时区。 systemd-timesyncd 工具提供了一个不错的 NTP 客户端,可以使本地主机上的时间与 NTP 服务器同步。但是,systemd-timesyncd 不提供服务器服务,因此如果您的网络上需要 NTP 服务器,则必须使用其他东西,例如 Chrony,来充当服务器。

我还想说明一点:您完全可以不使用 systemd 工具来实现 NTP。您可以使用旧的 ntpd 或 Chrony 或其他一些 NTP 实现。 systemd 由大量的服务组成;其中许多是可选的,因此可以禁用它们并在其位置使用其他东西。它并不是一些人认为的巨大的、整体式的怪物。不喜欢 systemd 或它的一部分是可以的,但您应该做出明智的决定。

我并不讨厌 systemd 对 NTP 的实现,但我更喜欢 Chrony,因为它更好地满足了我的需求。可以完全个性化设置就是 Linux 的精髓所在。