闰秒及其对计算机系统影响

来源:互联网 发布:手机炒股软件排名 编辑:程序博客网 时间:2024/05/01 06:54

说到闰秒我们首先明确3个概念,世界时,和原子时和世界协调时 。

世界时(UT):可以简单的理解为以地球自转为标准的计时。
原子时(TAI):国际原子时。采用基于铯原子(Cs 132.9)的能级跃迁原子秒作为时标。原理就是,通过束缚态光子,影响原子核和其电子的耦合,产生能级跃迁。这种跃迁是根据光子环绕原子核的位置往复运动的。因此形成了稳定的间隔,而这种间隔就用来确定时间。大概是如下图所示。

世界协调时(UTC):这个缩写比较诡异,是不能正常语法拼写出来的。
英语:Coordinated Universal Time ,法语:Temps Universel Coordonné
当时对于英法都想自己的语言成为世界协调时的缩写,因此争论不下,最后大家各退一步使用了 UTC(Universal Time Coordinated)作为其缩写。世界协调时简单的说,就是以 原子时 为计量单位,来表示世界时。

问题出现了,地球不是恒定转动的,而是越转越慢。当然这个慢是很细微的,不会是等几十年以后就不转了。。。- -b


闰秒是一个一秒的调整,偶尔应用到协调世界时(UTC),以保持其时间接近平均太阳时间或世界时。没有这样的校正,地球旋转计算的时间会偏离原子时间。

这个修正系统在1972年实施,已经插入了26个闰秒,最近在2015年6月30日在23:59:60 UTC,和下一个闰秒将插入2016年12月31日23:59:60 UTC。

具体来说,在所选择的UTC日期(一个月的最后一天,通常是6月30日或12月31日)的23:59:59和下一天的00:00:00之间插入正的闰秒。此闰秒在UTC时钟显示为23:59:60。负闰秒会在所选月份的最后一天的第二个23:59:59,该日期的23:59:58将紧接在下一天的00:00:00(负闰秒就很难见到啦。除非你现在开始从宇宙推地球让他转快点)。

这个是最近一个闰秒在The Official NIST US Time: 上的显示。

============ 背景介绍完后的分割线 =============

对于计算机来讲,我们如何同步到UTC时间呢。我们引进了NTP服务。

NTP(Network Time Protocol ):主要是用来同步网络上各个计算机上的时间。看起来好像很简单,但是在现在这个把时间掰成秒的快节奏社会,几秒的误差都可能造成很严重的问题。就像警匪片里行动前都要对表,计算机之间的时间也要统一,不然就会造成你一个人冲进匪窝,面对各式长枪短炮,大家还在外面数秒的尴尬情况。

NTP 版本0 是在1985年实现的,最早运用在了unix系统上。基本上是现存最老的互联网协议之一了。最近一次更新是2010年的版本4。
下图的老人家就是NTP之父,因为NTP引起的各种系统问题请直接算他头上。
当然他已经退休,在家颐养天年。

我们在系统中可以使用 ntpstat (unix Like系统)来看到时间源的层信息。理论上层数越低越好,但是考虑到网络因素的影响。也不绝对。 最高15层,16层默认是失败。

如果我们接入了互联网,我们可以通过互联网同步到时间源。

好了。下面我们谈谈闰秒对系统的影响。

从上面的知识我们得知,独立自己一台机器,在没有进行任何时间补丁更新的情况下。
是不会出现闰秒的。因为你根本接受不到 ntp服务器发出的闰秒计划信息。- -b

一些组织报告了在2012年6月30日闰秒之后由有缺陷的软件引起的问题。在报告问题的网站有reddit(Apache Cassandra)
Mozilla(Hadoop)
Qantas Airways
以及运行Linux的各种网站。

旧版本的摩托罗拉Oncore VP,UT,GT和M12 GPS接收器有一个软件错误,如果没有闰秒安排在256周,将导致一天的单一时间戳关闭。 2003年11月28日,这实际发生了。午夜时分,该固件的接收机报告2003年11月29日一秒钟,然后恢复到2003年11月28日。

较旧的Trimble GPS接收器具有软件缺陷,其将在GPS星座开始广播下一个闰秒插入时间(在实际闰秒之前几个月)时立即插入闰秒,而不是等待下一个闰秒发生。这使得接收者的时间在过渡期间暂停一秒钟。

较旧的基准Tymeserve 2100 GPS接收机和Symmetricom Tymeserve 2100接收机也有与旧的Trimble GPS接收机类似的缺陷,时间关闭一秒钟。一旦接收到消息,就应用闰秒的提前通知,而不是等待正确的日期。有针对此问题的固件升级。已经描述和测试了解决方法,但如果GPS系统重播广播,或者设备关闭电源,则问题会再次发生。

闰秒对商业部门的影响被描述为“一场噩梦”。由于金融市场容易受到技术和法律闰年问题的影响,洲际交易所母公司的7家结算公司和11家证券交易所,包括纽约证券交易所,在2015年6月30日的时候停止运营61分钟。

Cisco NEXUS 5000系列操作系统NX-OS(版本5.0,5.1,5.2)的几个版本受到影响。

Google服务器不是在一天结束时插入闰秒,而是在闰秒之前在时间窗口上稍微延长秒数。
因此没有受到影响。

其他的东西我们接触到的机会并不多。
主要对于系统运维的影响来自 linux 服务器。windows不会受到任何系统级影响。

linux受影响的内核版本:
linux-2.6.22 之前内核版本;
linux-2.6.25到2.6.27内核版本;
linux-3.4内核版本;
linux-2.6.32内核版本;


查看内核版本命令
# uname -r

我们说的是内核版本,因此全部使用 linux内核 的系统都会受到其影响。

原理:
在标准的Unix时间里会出现问题。这是由CLOCK_REALTIME系统时钟保持的时间,几乎每个需要知道当前时间的应用程序都会使用。它定义为1970年1月1日00:00:00 UTC后的秒数,但没有闰秒。系统时钟不能有时间23:59:60,因为每分钟有60秒,每天有86400秒,这是系统定义死的。
普通的计算机时钟不够稳定,不能保证时间精确到每年增加一秒或两秒,但是当一个时钟与NTP服务器以毫秒的精度同步时,时钟无法插入闰秒才是一个真正的问题。
当闰秒插入UTC时,系统时钟跳过一秒,因为它不能被表示,并突然超过UTC一秒钟。有几种方式如何可以纠正时钟。
1、最常见的方法是当时钟到达00:00:00 UTC时,简单地将时钟返回一秒钟。这是在Linux内核中实现的,并且默认情况下,向后时间跳跃不是恰好在00:00:00发生,而是在第一次系统时钟更新。时钟重复大部分23:59:59秒,也是从00:00:00秒开始的一小部分。结果是时钟关闭一秒钟一秒钟。

下图显示了NTPf服务如何在2015年6月30日使用默认配置更改的UTC时间的TAI偏移。
这种调整方式我们称其为跳跃式调整

此时 linux 系统会出现一句告警
kernel: [xxxxxx.xxxxxx] Clock: inserting leap second 23:59:60 UTC


闰秒代码从定时器那里中断处理程序, 每次时钟中断触发时会调用 tick_do_update_jiffies 更新 jiffies 的值,而 jiffies 主要记录了系统启动以来产生的处理频次,通过 jiffies/Hz 可以得到系统启动了多少秒。因此在这里需要对 xtime_lock 加入写锁。

闰秒代码调用second_overflow 这个函数处理润秒,
我们截取这个函数确定 时间状态的一段判定,发现,
switch (time_state) {
case TIME_OK:if (time_status & STA_INS) time_state = TIME_INS;else if (time_status & STA_DEL) time_state = TIME_DEL;break;
case TIME_INS:if (xtime.tv_sec % 86400 == 0) { xtime.tv_sec--; wall_to_monotonic.tv_sec++; /* The timer interpolator will make time change gradually instead * of an immediate jump by one second. */ time_interpolator_update(-NSEC_PER_SEC); time_state = TIME_OOP;clock_was_set(); printk(KERN_NOTICE "Clock: inserting leap second 23:59:60 UTC\n");}break;
case TIME_DEL:if ((xtime.tv_sec + 1) % 86400 == 0) { xtime.tv_sec++; wall_to_monotonic.tv_sec--; /* Use of time interpolator for a gradual change of time */ time_interpolator_update(NSEC_PER_SEC); time_state = TIME_WAIT;
clock_was_set(); printk(KERN_NOTICE "Clock: deleting leap second 23:59:59 UTC\n"); }break;
case TIME_OOP:time_state = TIME_WAIT;break;
case TIME_WAIT:if (!(time_status & (STA_INS | STA_DEL))) time_state = TIME_OK; }

这里的clock_was_set() 调用对 xtime_lock 的读锁
尴尬的是 现在 xtime_lock 还处于锁状态,死锁发生。

在之后的patch 里面 Thomas Gleixner 在函数里去掉了 clock_was_set() 函数
问题解决

--- a/kernel/time/ntp.c
+++ b/kernel/time/ntp.c
@@ -122,7 +122,6 @@ void second_overflow(void)
*/
time_interpolator_update(-NSEC_PER_SEC);
time_state = TIME_OOP;
- clock_was_set();
printk(KERN_NOTICE "Clock: inserting leap second "
"23:59:60 UTC\n");
}
@@ -137,7 +136,6 @@ void second_overflow(void)
*/
time_interpolator_update(NSEC_PER_SEC);
time_state = TIME_WAIT;
- clock_was_set();
printk(KERN_NOTICE "Clock: deleting leap second "
"23:59:59 UTC\n");
}

解决办法。
方法1:
升级内核到高版本。避开以上可能出现问题的版本,一劳永逸。
但是毋庸置疑,升级内核这种方法可能会带来一系列的问题。
特别是升级内核后要重启服务器,有可能升级过程中遇到莫名的问题。
生产系统没有必要冒这么大的风险。

方法2:
因为单机并不受影响,因此,我们只需要在闰秒发生之 前一天 开始将NTP服务停掉。
为什么是前1天,因为闰秒通知和闰秒处理不是同时进行处理的。不是前1分钟关上就可以的。
# service ntpd stop
过了闰秒的时间再开开。
# service ntpd start

方法3:
将NTP服务设置为 slew 模式
原理为: slew 模式并不使用跳跃式修改时间。比如一次调整1秒。
而是每秒调整 0.5ms 来缓慢修正时间。

这样就不会调用郁闷的 TIME_INS ,也就不会调用 clock_was_set() 产生锁冲突了。
当然这个模式不是很好,因为调整的太慢了。差1秒还好。差几十秒能调整出几天去。
在过了闰秒,调回来就好。

设置方法。
修改 /etc/sysconfig/ntpd 文件。在 OPTIONS="-g" 前加上 -x
重启服务。
注意 ,如果是做了集群。。请慎重。。。。
0 0