1 硬件时钟和系统时钟的同步机制
硬件时钟记录在服务器主板的CMOS芯片里面,与主板的南桥芯片(目前Intel与AMD的主板仅有南桥,北桥已集成到CPU)相连。硬件时钟一般叫做RTC(Real Time Clock)、CMOS clock或者BIOS clock,主板上面有一个独立电源(一般是纽扣电池CR2032)保持在操作系统关机、服务器下电后,每1秒嘀嗒计时一次。一般服务器在开机时,操作系统向硬件时钟同步时间。
由于BIOS是只读存储器(ROM),无法保存配置信息,CMOS芯片是一个可读写的存储器,主板会将BIOS的配置信息保存到CMOS芯片中。
纽扣电池一般可以支撑10年左右的寿命,但是如果服务器长时间没有上电,会使纽扣电池的寿命提前终止,导致服务器的BIOS配置无法保存,硬件时钟不准确。
而系统时钟也叫做操作系统时间、kernel clock或者software clock,是基于时间中断器的软件计数器。系统时钟和硬件时钟在一定的场景下会互相影响,比如:
- 服务器开机时,系统时钟会读取硬件时钟;
- 操作系统使用过程或者正常关机时,也有可能将系统时钟写入到硬件时钟,缩小硬件时钟与系统时钟的差距;
- 在UEFI和Legacy两种BIOS的引导模式下,硬件时钟和系统时钟之间的影响程度也不同。具体可以看后面的案例
在Linux操作系统里面,可以使用hwclock、timedatectl查看或者同步硬件时钟的具体状态。
[root@localhost ~]# date;hwclock -r;timedatectl
Wed Apr 19 15:15:38 CST 2023 #date输出,软件时钟,24小时制,时区为当前时区东8区
Wed 19 Apr 2023 03:15:38 PM CST -0.383302 seconds #hwclock -r输出,硬件时钟,12小时制,时区为当前时区东8区
Local time: Wed 2023-04-19 15:15:38 CST #timedatectl输出,软件时钟,24小时制,时区为当前时区东8区
Universal time: Wed 2023-04-19 07:15:38 UTC #timedatectl输出,UTC+0时间
RTC time: Wed 2023-04-19 07:15:38 #timedatectl输出,硬件时钟,实际上为UTC+0时间
Time zone: Asia/Shanghai (CST, +0800)
NTP enabled: n/a
NTP synchronized: no
RTC in local TZ: no
DST active: n/a
[root@localhost ~]# dmesg|grep -E "RTC|system clock"
[ 0.418401] RTC time: 7:06:26, date: 04/19/23 #开机时识别到的硬件时钟
[ 1.536044] rtc_cmos 00:01: setting system clock to 2023-04-19 07:06:28 UTC (1681887988) #同步硬件时钟到系统时钟中
从命令的输出中可知,操作系统开机时,读取到的RTC为UTC+0时间,Linux内核读取RTC时间为系统时钟的过程中也是同步为UTC+0时间(这与/etc/adjtime配置有关),并且操作系统再读取/etc/localtime将UTC+0时间转换为对应时区的本地时间。
[root@localhost ~]# ls -l /etc/localtime
lrwxrwxrwx. 1 root root 35 Apr 19 09:36 /etc/localtime -> ../usr/share/zoneinfo/Asia/Shanghai
在Windows里面,默认使用本地时间(localtime)的方式记录时间,并且没有具体的工具或命令能够直接读取到硬件时钟。通过内核引导的过程中可以发现,Windows操作系统开机时通过HalQueryRealTimeCLock读取硬件时钟,再使用KeSetSystemTime同步到系统时钟。
例如我向事件查看器写入一条事件记录后,会发现实际上Windows也会将内核的UTC+0时间(就是事件查看器中的SystemTime,应该是使用KeQuerySystemTime获取的,)转换为localtime时间,localtime就是我们当前的本地时间,UTC+0时间有可能就是内核或者RTC的时间了。
PS C:\Users\samremote> Write-EventLog -LogName Application -Source "ESENT" -EntryType Information -EventId 1234 "事件记录产生时间为 $(Get-Date -Format "dddd MM/dd/yyyy HH:mm K")"
2 案例分享
遇到一台HPE DL380 Gen10服务器上安装了Windows Server 2012,使用NTP同步时间,每间隔86400秒同步一次时间。但是自2022年起,出现了3次时间回拨的问题。
根据系统日志的提示,Windows操作系统默认使用localtime(也就是系统设置时区的当前时间)的方式向硬件时钟同步了时间,即不会考虑时区的设置,直接读取硬件时钟,导致服务器出现时间回拨。HPE服务器的硬件时钟与引导模式(UEFI、Legacy)和ILO版本有关,参考(Document - Notice: (Revision) HPE ProLiant, Synergy and Apollo Gen9, Gen10, and Gen10 Plus Servers - Time and Date Synchronization Details | HPE Support),为此需要从该服务器的硬件时钟运作层面进行分析:
- 引导模式
- UEFI:BIOS与操作系统中的所有关于日期、时间、时区的设置都会互相同步,互相影响。
- Legacy:BIOS的时钟与操作系统时钟独立运行,设置互不影响。
- ILO版本:
- iLO5的默认时区为GMT格林威治时间(零时区),与北京时间相差8小时,开机时会将iLO的时区同步到服务器。
- iLO4的默认时区是大西洋时间(UTC-4时区)。
根据问题现象和HPE官方的文章可以得出下面的逻辑结构图:
综上所述,可以考虑使用以下步骤解决时间回拨问题:
- 参考HPE的BUG修复说明,设置BIOS中的时间格式为“Local Time”,并且确保BIOS中的时区与ILO中的时区一致。(推荐)
- 使服务器向NTP更加频繁地向NTP同步时间,生产环境中,每10分钟或15分钟向NTP进行一次校时非常常见,目前设置86400秒同步一次,时间变慢的概率会更高。(推荐)
- 或者使用Legacy启动模式,但引导模式的更改,有可能导致服务器无法正常引导进入操作系统。(不推荐)