1、写在前面

因为最近一段时间以来,本人在项目遇到的因为Linux系统时间所引发的问题比较多,所以在此进行总结。

2、Linux系统时间与BIOS硬件时间之间的关系

2.1、RTC芯片、i2c总线和BIOS之间的关系

实时时钟(RTC)芯片是普遍应用在集成电路上的一个模块,采用内置的高精度晶体振荡器作为时钟源,在PC和服务器中,为了保证RTC在主机断电后还可以继续保持运转,整机厂商还会在主板上焊接电池模块对RTC进行供电。也就是说,对于一个整机设备而言,RTC芯片是一切时间的来源。
i2c总线是集成电路上的一种通信链路,连接集成商电路上各个硬件模块,在本文中主要是用于连接主机(BIOS)和RTC芯片,通常情况下,系统关机时CPU会清空其寄存器,这就导致了设备在再一次启动时,会通过i2c总线初始化访问RTC。
粗略的逻辑如下图所示:
在这里插入图片描述
而站在BIOS的角度,实际上是开放了一个i2c接口供上层的操作系统进行调用,以读取RTC时间,因此本文后文中所阐述的“BIOS时间”,本质上就是BIOS通过i2c总线读取到的RTC芯片时间。
关于主机(BIOS)通过i2c总线和RTC芯片进行通信和数据传输的具体原理涉及集成电路相关知识,站在Linux系统运维的角度,只要了解上述最基本概念即可。

2.2、Linux将BIOS时间视作UTC时间(协调世界时),而Windows则认为BIOS时间就是本地时区的时间

Linux系统对于BIOS硬件时间的处理方式与Windows对于BIOS硬件时间的处理是有区别的,Windows和Linux的系统时间在没有NTP服务器的情况下,均读取自BIOS的时间。Windows系统会BIOS时间作为当下本地时区的时间;而Linux系统则会将BIOS时间作为UTC时间(协调世界时),然后根据系统设定的本地时区进行增加或者减少相应的小时数。(如,假使BIOS时间是10:00,且两个系统的时区都设定为东八区的上海时间,Windows系统会认为10:00就是上海时间,而Linux会在10:00的基础上增加8个小时,最后认为18:00为上海时间)
Windows和Linux对待BIOS硬件时间不同所造成的最直接的现象在于,在安装Windows+Linux的双系统时,两个系统之间的系统时间会相差8个小时(相对于东八区而言)。而如果想要消除“双系统8小时时差”这样的现象,可以在Linux系统上通过“hwclock -w”命令将Linux系统时间和BIOS时间同步为一致,即可解决。
在这里插入图片描述

2.3、Linux怎样更新系统时间

Linux系统有两个时间,一个是系统时间,另一个是BIOS时间。Linux系统在启动时,会自动读取BIOS时间作为系统时间,如果读取不到BIOS时间,则会将上一次成功读取到BIOS时间作为本次的系统时间,Linux系统成功启动完成后,假使Linux开启了时钟自动同步功能并成功连接到NTP服务器上,则会将NTP服务器上的时间作为本机的系统时间。相关流程图如下所示:
在这里插入图片描述
以上流程图是Linux系统启动时的流程图,Linux关机时,还会将系统时间写入到BIOS时间中,以保持软硬件时间同步。

3、未安装ntpdate或chronyc的情况下,Linux如何实现与NTP服务器时间的同步

在很多Linux教材中,谈到时间同步的时候,绝大多数都是通过ntpdate命令与安装有ntpd的时钟服务器同步,或者是通过chronyc命令与安装有chrony的时钟服务器同步,但对于客户端而言,ntpdate和chronyc都不是Linux自带的时间同步命令,需要额外安装。而像debian等这样的Linux发行版,其本身又可以进行时间同步,那这样的时间同步又是怎样实现的呢?其实这都归功于Linux中的systemd-timesyncd.service服务,相关服务可以通过命令“systemctl status systemd-timesyncd.service”命令查看,如果相关的服务为active状态,说明时间同步服务时开启的,如下图所示:
在这里插入图片描述
既然有相关服务,就会有相关的配置文件,systemd-timeryncd.service服务的配置文件位于“/etc/systemd”路径下,文件名称为“timesyncd.conf”,如下图所示:
在这里插入图片描述
将相关配置文件打开后,我们可以看到内容如下:
在这里插入图片描述
按照译者金步国的博客(http://www.jinbuguo.com/systemd/timesyncd.conf.html#NTP=)针对于timesyncd.conf文件参数字段的解释,我们可以获知到以下信息:

参数字段解释
NTP=一个空格分隔的NTP服务器列表, 可以使用主机名,也可以使用IP地址。在运行时, 此处设置的列表将与 systemd-networkd.service(8) 中已配置的NTP服务器列表合并在一起。 systemd-timesyncd 将会依次尝试列表中的每个NTP服务器, 直到同步成功为止。 如果为此选项设置一个空字符串, 那么表示清空所有此选项先前已设置的NTP服务器列表。 此选项的默认值为空。
FallbackNTP=一个空格分隔的NTP服务器列表,用作备用NTP服务器。 可以使用主机名,也可以使用IP地址。如果所有已配置在 systemd-networkd.service(8) 中的NTP服务器以及上述 NTP= 中设置的NTP服务器都尝试失败, 那么将尝试此处设置的备用NTP服务器。 如果为此选项设置一个空字符串, 那么表示清空所有此选项先前已设置的NTP服务器列表。 若未设置此选项, 则使用编译时设置的默认备用NTP服务器。
RootDistanceMaxSec=最大可接受的"root distance"秒数(最大误差)。 默认值为 5 秒。
PollIntervalMinSec=, PollIntervalMaxSec=NTP消息的最小/最大轮询间隔秒数。 PollIntervalMinSec= 必须不小于 16 秒。 PollIntervalMaxSec= 必须大于 PollIntervalMinSec= 。 PollIntervalMinSec= 默认为 32 秒, PollIntervalMaxSec= 默认为 2048 秒。

换言之,我们在NTP字段后添加了一个NTP地址后(需要删除前面“#”以取消注释),通过命令“systemctl restart systemd-timesyncd.service”即可完成与NTP服务器的时间同步,而不需要额外安装ntpdate和chronyc工具,如果NTP字段后的服务器连接或同步失败,则会去匹配FallbackNTP字段后的NTP服务器。
上述提到,配置文件timesyncd.conf在路径/etc/systemd下影响时间同步服务的进行,而有的发行版(如deepin V20.2.4),在/etc/systemd目录下还有一个timesyncd.conf.d文件夹,该文件夹下还有一个配置文件,在deepin系统中,该文件的文件名为deepin.conf,其内容编写规则与/etc/systemd/timesyncd.conf一致。如果某个Linux发行版和deepin一样具有/etc/systemd/system.d/timesyncd.conf文件夹,那么systemd-timesyncd.service服务将优先选择这个文件夹下的.conf文件作为自己的优先配置文件,而原有的/etc/systemd/timesyncd.conf将作为备用的配置文件,优先级相对较低。

4、Linux系统时区的注意事项

4.1、Linux的世界里,没有北京时间

本章节具体阐述前,我们或许可以这样说——“Linux的世界里,实际上不存在北京时间”。
之所以这样说,是因为Linux系统普遍采用IANA(互联网数字分配机构)的时区数据库(Time Zone Database)作为系统的时区。在该数据库中,中国地区的IANA标准时区有四个——上海、香港、澳门和台北,因此“北京时间”在Linux系统里面本质上是没有的,不过不同的Linux发行版会对这个时区数据库做修改,如debian系统,增加有“重庆时间”,deepin系统则将中国省份增加得更多,如北京、重庆、成都、西安、南京、乌鲁木齐等等,这些时区各对应了一个时区相关文件,位于/usr/share/zoneinfo或/usr/share/zoneinfo/Asia目录下。而针对于debian、deepin等系统自行修改添加的时区,其本质上是在相应的目录下创建了一个链接文件指向上海时区的时区文件,毕竟上海时区是IANA规定的标准时区。相关链接文件如下所示(以debian中的重庆时间为例):
在这里插入图片描述
当然也有例外,像OpenEuler,则没有采用链接文件形式指向上海。
在这里插入图片描述

4.2、Linux设置时区时应尽可能设置IANA标准时区

之所以要将Linux尽可能设置为IANA标准时区,是针对于和涉及到时区相关定制开发Linux软件而言的。因为全球的Linux发行版有几百种,并且这些发行版的非IANA标准时区都不同,在不同的开发人员采用不同的Linux发行版当开发环境情况下,会出现他们所开发的软件没能适配很多非IANA标准时区,这将导致一些问题——比如某个Linux系统时区为非IANA标准的北京时区,因运行的软件只适配了IANA标准的上海时间,所以此时软件内的时间会显示为UTC时间(数值上等同于零区的格林尼治时间,与北京时间有8小时时差),但系统时间仍旧是正确的北京时间,这会给最终的使用者带来很不好的体验。

4.3、典型故障——无论怎样修改时区,Linux系统始终都显示零区的格林尼治时间

出现这样的情况一般是因为/usr/share/zoneinfo目录遭到严重破坏造成的,针对这样的故障,最简单粗暴的方式就是将找到一套同版本、正常运行的Linux发行版,将其/usr/share/zoneinfo目录复制出来,对故障Linux系统的相关目录进行替换。

4.4、典型故障——安全软件在启动时强制打开操作系统时间同步功能,后因安全软件服务端时间错误导致时钟错误同步

在信创领域,Linux杀毒软件经常被安装在Linux电脑上,用于病毒查杀和违规外联等功能。而主流的Linux杀毒软件都具有审计功能,审计会产生大量的日志纪录,这些纪录需要有一个时间对应,因此这些杀毒软件的服务端会自带时钟同步,并且会在Linux终端启动完成后强制打开和配置操作系统的时钟同步功能,如果杀毒软件服务端的本地时间时错误的,或者说同一个局域网内有多个存在一定时间差的NTP服务器,将可能会对Linux终端带来时间上的错误。

4.5、典型故障——Linux系统在启动完成后,时间大约是上一次关机后的时间

针对于这样的故障情况,不要尝试重启Linux系统,因为时间出现问题的现象很可能是概率性的,重启后故障可能就不会复现出来了,所以此时可以按照以下几个思路进行排查:
(1)通过输入“date”命令查看系统时间,以及“hwclock --show”命令查看硬件时间,对比两者是否一致,如果不一致,且显示出来的硬件时间接近设备上一次关机的时间,则需要检查硬件主板上相应的供电模块是否工作正常,以及主板存在多少块RTC芯片,如果有多块RTC芯片,就需要查看两块RTC芯片的时间是否一致,而如果出现下图所示的错误信息,则代表系统本身无法读取硬件,则需要进一步排查硬件层面原因,如RTC芯片和i2c总线;(在这里其实可以不用再排查Linux系统的时钟驱动了,因为前提是“错误时间大约是上一次关机的时间”,说明上次使用时,时间是正常的,正常就代表系统的时钟驱动本身是可以正常运转的)
在这里插入图片描述
(2)如果需要进一步排查RTC芯片,上述(1)中已经说明需要查看存在多少块RTC芯片,相关操作方式为——查看/etc/sys/class/rtc目录下的文件,会出现rtcX形式的文件夹,有多少个这样文件夹,就说明设备有多少个RTC芯片,我们可以进入rtcX文件夹,并输入“cat time”命令去查看time文件,如果报出下图所示错误,则说明Linux系统或BIOS之间存在i2c总线层面的通信存在错误:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
(3)系统通过命令“hwclock --show”读取硬件时间时,实际上并不是两块RTC芯片都会读取,而是会选择其中一块RTC进行读取,如果读取到错误时间的RTC芯片,则可以手动将系统时间修改正确后,通过“hwclock -w”命令将系统时间写入硬件后,做后续观察;

5、扩展补充:协调世界时(UTC)和格林尼治标准时(GMT)的区别

格林尼治标准时(GMT),是指英国皇家格林尼治天文台的标准时间,因地理学上的本初子午线被定义为通过在格林尼治天文台的经线,因此理论上格林尼治标准时间的正午是指当太阳横穿本初子午线时的时间。由于地球在其椭圆轨道里的运动速度不均匀,该时刻可能和实际的太阳时相差16分钟。 加之地球每天的自转是不规则的,且自转速度正在缓慢减速。所以,格林尼治时间已经不再被作为标准时间使用,取而代之的是基于国际原子时秒长为基础的协调世界时(UTC)。
原子时秒的定义:铯-133原子基态的两个超精细能级间在零磁场下跃迁辐射9,192,631,770周所持续的时间。
目前,UTC被应用在互联网和万维网标准中,例如NTP(网络时间协议)就是UTC被使用在互联网中的一种方式,而日常生活中,在不需要将时间精度控制在秒的情况下,UTC可以被视作和GMT等同。

Logo

更多推荐