Linux时钟系列-01-系统时钟漂移问题
1.前言
最近碰到了一个服务器时间漂移的问题,一台Linux服务器运行12小时后,系统时钟漂移了700多ms,而且在机器负载不同的时候,漂移程度还不一样。
其实碰见这个问题已经好多好多年了,只不过没有时间深究,正好最近得空研究下,整理几篇文章出来。
事先声明:由于本人并非专业硬件工程师,有些表述可能比较浅显或者不够准确,对于此类信息我会尽量注明信息来源供参考,防止误导读者。
另外,参考资料部分的几个视频,质量都很高,强烈建议观看学习。
2.基础概念
在Linux系统中,有两种“日期-时间”时钟,即硬件时钟和系统时钟。这里所讨论的时钟概念,仅表示“日期-时间”时钟,即用于保存和维持系统的日期-时间正常流逝的时钟(Clock),而非系统定时器(Timer)、计数器(Counter)等概念,请注意区分。
2.1 硬件时钟(Hardware Clock)
硬件时钟是一个独立于CPU等其他计算机部件的硬件设备,一般采用纽扣电池供电(CR2032,能用10年左右),能在服务器下电后正常维持系统日期和时间更新。
这个设备除了被叫做硬件时钟(Hardware Clock)外,还可能被叫做Real Time Clock(RTC)、BIOS Clock、CMOS Clock,都是一个意思。RTC是它的正式名字,叫BIOS Clock和CMOS Clock是因为RTC和BIOS的CMOS都需要在关机时保持供电,前者用于保持时间流逝,后者用于保存一些BIOS设置信息,所以一般会放在一起。
Linux一般仅在启动时与硬件时钟通信,获取当前日期时间用于初始化操作系统时间,Linux启动成功后,就按照自己的逻辑维持时间流逝了,不再与上述硬件时钟通信了。
在Linux系统下,使用hwclock命令可以查看硬件时钟的当前时间(需要root权限):
2.2 系统时钟(System Clock)
在Linux系统中,系统时钟是指由定时器中断驱动更新的时钟。
2.2.1 时钟源
产生定时器中断的硬件,叫做时钟源(Clock Source)。
使用如下命令可以查看系统的可用时钟源以及当前正在使用的时钟源:
Linux会在启动后自动选择时钟源,选择优先级是TSC(Time Stamp Counter) > HPET(High Precision Event Timer) > ACPI_PM(ACPI Power Management Timer) > PIT(Programmable Interval Timer) > RTC(Real Time Clock)。
关于TSC:所有的x86处理器都包含了一个CLK输入针脚,可以接收外部振荡器的时钟信号。从Pentium(奔腾)开始,x86处理器引入了一个计数器,这个计数器每收到一个CLK信号就增加1,最新值存放于TSC寄存器中,可通过rdtsc汇编指令读取。通常情况下,对于一个3.5GHz的CPU而言,其CLK信号每秒可触发35亿次,那么理论上,基于TSC的计时精度可达0.2857ns。
关于PIT:PIT顾名思义是一种可编程的,按照固定频率(可由内核指定)产生定时器中断的芯片,该定时器中断可被操作系统内核捕获并处理,用于驱动内核做一些跟时间有关的事情。Intel 8254 CMOS芯片就是一个常用的PIT芯片。PIT其实是单核时代的产物,它能被内核编程每秒产生HZ个时钟信号,所以其频率只能是100、250、300、1000,也就是最大精度为1ms,太低了。
关于HPET:HPET相当于PIT的升级版,未来是要完全取代PIT的(比如在我们的机器上已经看不到PIT了,只有HPET)。典型的HPET芯片可内置多达8个独立的计数器,每个计数器都由独立的时钟信号驱动,且频率至少可达10MHz。HPET通过寄存器向内核暴露计数器的值,支持可编程的一次性中断和周期性中断。HPET的精度和速度和功能都比较OK,所以被当做第二优先的系统时钟源,但它的问题是,并不是所有的系统都有HPET,而且有些HPET时钟是不可靠的。
关于ACPI_PM:它是跟TSC一样广泛存在的计时器,但跟TSC不同的是,TSC是基于CPU寄存器的,可被CPU直接读取,而ACPI_PM是基于设备寄存器的,需要通过IO端口读取寄存器的值,因此速度慢很多。
关于RTC:RTC即前一小节我们提到的那个自带电池用于维护系统日期时间的设备,它的问题在于精度太差。
2.2.2 TSC时钟源
现代Linux服务器广泛采用TSC作为时钟源,本节中我们深入分析一下TSC。
虽然TSC是时钟源,但其实TSC只是CPU时钟信号的消费者而非生产者,既:TSC并不为CPU产生CLK引脚信号,它其实只是CPU根据CLK引脚信号定期更新的一个寄存器。CPU的CLK信号源是外部晶振,通常是由位于主板的主晶振经过倍频而来。
这一个视频以一种简单易懂(但不精确)的方式解释了主晶振的时钟信号如何变成CPU的CLK引脚信号的:
大概就是:主板上的主晶振是驱动主板各核心芯片组工作和协调的最终时钟源,主晶振的频率通过倍频放大N倍后输入到CPU的CLK引脚,CPU内部的频率合成器电路再将倍频处理为最终的处理器主频,驱动CPU工作。
所以,在Linux运行期间,最终驱动CPU和内核更新系统时间的,是位于主板上的主晶振,那么最终决定系统时间漂移程度的最大因素,其实也是这个主晶振。
2.2.3 晶振
晶振(Crystal Oscillator),即晶体振荡器,现在一般专指石英晶体振荡器(Quartz Crystal Resonator),是利用石英晶体的压电效应,用来产生高精度振荡频率的一种电子器件。
1)晶振分类
石英晶振的其中一种分类方式如下:
- 普通晶振:简称SPXO(Simple Packaged Crystal oscillator)
- 温补晶振:简称TCXO(Temperature compensated crystal oscillator)
- 恒温晶振:简称OCXO(Oven-controlled crystal oscillator)
- 压控晶振:简称VCXO(Voltage-controlled crystal oscillator)
普通晶振是最基本的晶振,其稳定性完全由晶体谐振器本身的固有特性(主要是材料和工艺)决定。在-55℃至+105℃之间的环境温度范围内,普通晶振也能提供相对稳定的频率,可实现±25ppm的稳定性(ppm即Parts Per Million,±25ppm表示该晶振的工作频率相对于其标称频率可能有±百万分之25的误差,例如,假设某晶振的标称工作频率为100MHz,±25ppm即意味着该晶振的工作频率可能在99.999975~100.000025之间变化)。
温补晶振即温度补偿晶体振荡器。如果石英晶体的固有频率和温度稳定性不能满足应用要求,可以增加温度补偿单元,抵消晶体的漂移。根据温补晶振的类型和温度范围,其典型稳定性规范范围为小于±0.5ppm至±5ppm。
恒温晶振即恒温控制晶体振荡器。其工作原理是利用恒温槽使晶体振荡器中石英晶体谐振器的温度保持恒定,将由周围温度变化引起的振荡器输出频率变化量削减到最小。在环境温度范围内,恒温晶振的稳定性可以达到0.001ppm。
压控晶振即电压控制晶体振荡器,其设计不是为了提供更高的精度,而是调谐或调整振荡器的频率,因此这里不再讨论。
2)晶振工作频率
普通Linux服务器上一般有三种频率的晶振:
32.768KHz晶振:该频率经过分频器进行15次2分频后可以得到1Hz秒信号,即1秒1次,因此非常适合用于日期-时间时钟。工作频率越高的晶体,品质系数一般难以做高,频率稳定度不高。而32.768K的晶体稳定度等各方面都不错,品质系数比较容易做高,于是就形成了一个工业标准。上文我们所说的硬件时钟(RTC)的工作频率就是32.768KHz。
14.318MHz晶振:一般用作主板的主时钟,经过分频和倍频后用于驱动主板上的不同元器件。例如CPU、PCI设备、USB设备等。至于为什么会是14.318MHz,是因为最早的计算机主频是4.77Mhz,14.318MHz经过一次二分频可以降到4.77MHz。美国模拟电视制式NTSC的彩色副载波的频率是3.579545MHz,14.318MHz经过2次2分频就可以得到该频率。后来该频率就逐渐成为标准了。
25MHz晶振:一般用于网卡,并且是单独的晶振芯片。具体原因有二:一是网卡需要较高频率的工作时钟来保证数据传输的精确性,以降低丢包的概率,所以要提高工作频率;二是高频率时钟在走线时要尽量靠近网卡主芯片,以增加可靠性,所以要采用单独芯片。
2.3 总结
读到这里我们知道了,Linux服务器的两种维持时间更新的方式,即硬件时钟和系统时钟,都是由晶振驱动更新的,其中硬件时钟是由工作频率为32.768KHz的晶振直接驱动的,系统时钟是由工作频率为14.318MHz的晶振间接驱动的,其实决定机器在连续运行情况下的时钟漂移程度的,就是间接驱动系统时钟的这个14.318MHz的主时钟晶振。
为了改善系统时钟漂移的问题,有两个比较可行的方案,一是将主板主时钟的晶振芯片换成恒温晶振,二是引入专用ntp授时设备,使用ntp协议实时对时。
1)恒温晶振方案
普通Linux服务器的主晶振为非恒温晶振,每24小时的守时精度大概在±1~2s,即每小时大概偏移60ms。
恒温晶振的守时精度就好很多了,每24小时为±8us,即每小时大概偏移333ns,跟普通晶振不在一个数量级上。但是恒温晶振的价钱也高很多,一个恒温晶振模块大概小几万,抵得上一台Linux服务器的价钱了。
2)专用授时设备方案
如果不采用恒温晶振,那可以考虑引入专用的ntp授时设备,这种设备除了标配恒温晶振外,还可选内置铷原子钟,原子钟相比恒温晶振的守时精度又上升了一个数量级,24小时偏移小于200ns。
3.参考资料
- Linux man page :hwclock
- RHEL Document:Timestamping
- RHEL Document:How to change the clock source in the system
- 晶诺威科技:XO,VCXO,TCXO及OCXO四种晶振性能优势介绍
- 北斗邦泰:专用授时设备
- ITFreeTraining:Clock Speeds and Bus Speeds
- 创客中芯:晶振,为什么不能被集成到芯片中?
- 创客中芯:MCU为什么不仿效RTC,把晶振和芯片封装在一起?
- 创客中芯:从32.768K到一秒钟,芯片内部的逻辑电路,是如何实现的?
- 老石谈芯:揭秘时钟信号:计算机与芯片的心跳,是怎样产生的?