Categories
程式開發

计算机的时间


前言

对于计算机系统中的时间,如果你曾经思考过下面的问题,但是没有结论,那么通过本文将给你详细的解答:

闰秒是怎么产生的,在2012年6月30日UTC插入一个闰秒后,大量linux服务器宕机的原因是什么?计算机系统是怎么保证自己的时间是准确的?计算机系统我们经常使用微妙甚至纳秒,它怎么来提供这么高精度的时间?计算机系统是没有时间概念的机器,那么它是怎么来计算与管理时间的?

背景

时间是一个非常抽象的问题,吸引着许多伟大的神学家、哲学家和物理学家花毕生精力去解释时间的本质是什么,然而依然没有定论。幸运的是我们只需要讨论计算机系统中的时间相关的问题,可以不用关心宇宙、黑洞、相对论和量子力学等等繁复的课题。但虽然仅仅局限在计算机这一个很小的范畴中,这看似已经不再复杂的主题,却并也不会如此简单。

计算机系统的时钟

在计算机系统中主要有两种时钟:一种是墙上时钟,一种是单调时钟。它们都可以衡量时间,但却有着本质的区别,下面我们一一来分析。

墙上时钟

墙上时钟又称为钟表时间,顾名思义,和我们平时使用的钟表的时间一样,表示形式为日期与时间。在linux系统中墙上时钟的表示形式为UTC时间,记录的是自公元1970年1月1日0时0分0秒以来的秒数和毫秒数(不含闰秒),linux系统需要处理闰秒的逻辑就是由于linux系统使用UTC时间,但是系统中记录的UTC时间是不含闰秒导致的,后面闰秒相关的部分会详细的介绍。

时间同步

根据定义可以发现,墙上时钟的标准是在计算机外部定义的,所以需要确保墙上时钟的准确性就变成一个问题。计算机内部的计时器为石英钟,但是它不够精确,存在过快或者过慢的问题,这主要取决于机器的温度。所以依靠计算机自身来维持墙上时钟的准确性是不可能的。目前普遍采取的一种方式为计算机与NTP时间服务器进行定期通过网络同步。当然这个方式受限于网络环境的影响,一般来说至少会有35毫秒的偏差,最大的时候可能会超过1秒。

对于一些对时间精度要求很高的系统,通过NTP进行同步是远远不够的,而通过GPS接收机接受标准的墙上时钟,然后在机房内部通过精确时间协议(PTP)进行同步。PTP是一种高精度时间同步协议,可以到达亚微秒级精度,有资料说可达到30纳秒左右的偏差精度,但需要网络的节点(交换机)支持PTP协议,才能实现纳秒量级的同步。

对于时间同步,Google的做法更酷,通过GPS接收机接受标准的墙上时钟,然后通过机房内部部署原子钟(精度可以达到每2000万年才误差1秒)来防止GPS接收机的故障。通过这些时间协调装置会连接到特定数量的主服务器,然后再由主服务器向整个谷歌网络中运行的其他计算机传输时间读数(TrueTime API)。Google正是基于上面的时间精度保证,在此基础上实现了第一个可扩展的、全球分布式的数据库Spanner。

闰秒出现的原因

目前存在两种时间计量系统:基于地球自转的世界时(UT1),它以地球自转运动来计量时间,但由于地球自转速率正在变慢,所以世界时的秒长会有微小的变化,每天达到千分之几秒。原子时是取微观世界的铯原子两个超精细能级间跃迁辐射频率来度量时间,精确度非常高,每天快慢不超过千万分之一秒。从上面可以看出,原子时是度量时间均匀的尺度,但是与地球空间位置无关;世界时度量时间的均匀性不好,但是它定义地球自转一周为一天,绕太阳公转一周为一年,这对人们的日常生产生活非常重要。

为了统一原子时与世界时直接的差距,就产生了协调世界时(UTC)。从1972年1月1日0时起,协调世界时秒长采用原子时秒长,时刻与世界时时刻之差保持在正负0.9秒之内,必要时用阶跃1整秒的方式来调整。这个1整秒的调整,就称为闰秒(增加1秒为正闰秒,较少1秒为负闰秒)。UTC从1972年1月正式成为国际标准时间,它是原子时和世界时这两种时间尺度的结合。

闰秒的处理

由于linux系统记录的是自公元1970年1月1日0时0分0秒以来的秒数和毫秒数,但是不含闰秒,这表示在linux系统中每分钟有60秒,每天有86400秒是系统定义死的。所以linux系统需要额外的逻辑来处理闰秒。

跳跃式调整

当UTC时间插入一个正闰秒后,linux系统需要跳过1秒,因为闰秒的这一秒钟在linux系统中不能被表示;当UTC时间插入一个负闰秒后,linux系统需要插入1秒,因为闰秒的这一秒钟在linux系统中不存在。目前linux系统就是采用该方式来处理闰秒的。在2012年6月30日UTC时间插入一个正闰秒的时候,由于linux系统的某些版本的闰秒处理逻辑触发了一个死锁的bug,造成了大规模的linux服务器内核死锁而宕机。

NTP服务的slew模式

NTP服务的slew模式并不使用跳跃式修改时间,而是渐进式的调整。比如当UTC时间需要插入一个正闰秒,NTP服务会每秒调整一定ms来缓慢修正时间。这样linux系统从NTP服务同步时间的时候就不会感知闰秒的存在了,内核也就不需要启动闰秒相关的逻辑了。

单调时钟

单调时钟它总是保证时间是向前的,不会出现墙上时钟的回拨问题。它非常适合用来测量持续时间段,比如在一个时间点读取单调时钟的值,完成某项工作后再次获得单调时钟的值,时钟值之差为两次检测之间的时间间隔。

但是单调时钟的绝对值没有任何意义,它可能是计算机自启动以后经历的纳秒数等等。因此比较不同节点上的单调时钟的值是没有意义的。

时间的管理

时间的概念对于计算机来说有些模糊,计算机必须在硬件的帮助下才能计算和管理时间。前面说的石英钟就是用来做计算机的系统定时器的,系统定时器以某种固定的频率自行触发时钟中断。由于时钟中断的频率是编程预定的,所以内核知道连续两次时钟中断的间隔时间(这个间隔时间就称为节拍)。通过时钟中断,内核周期性地更新系统的墙上时钟和单调时钟,从而计算和管理好时间。

时间的精度

目前系统定时器的中断频率为1000HZ,那么计算机能处理的时间精度为1ms。然而很多时候需要更加精确的时间,比如1微妙,计算机是怎么来解决这个问题的呢?

在每一次计算机启动的时候,计算机都会计算一次BogoMIPS的值,这个值的意义是处理器在给定的时间内执行指令数,通过BogoMIPS值,计算机就可以得到很小很小的精度了。比如1秒计算机执行了N条指令,那么计算机的精度就可以达到N分之一秒。很明显N是一个非常非常大的数目,因而计算机可以得到非常非常精确的时间。

总结

在本文中,我们讨论了计算机系统时间同步的方式,同时分析了闰秒产生的原因,以及linux系统应对的办法,然后概览性的讲了linux系统是怎么进行时间的计算与管理的,最后分析了linux系统可以提高高精度时间的方法。

参考

LKML: Chris Adams: Re: Bug: Status/Summary of slashdot leap-second crash on new years 2008-2009Bug 479765 – Leap second message can hang the kernel“Robert Love.Linux Kernel DevelopmentMartin Kleppmann.Designing Data-Intensive Applications