解决 Red Hat Enterprise Linux 中的闰秒问题
内容
简介
闰秒是 UTC(Coordinated Universal Time)的一个定期的一秒钟的调整,以便使系统的时间尽量接近于平均太阳时(mean solar time)。但是,因为气候和地理事件的因素,地球的转动速度可能会有变化。因此,UTC 的闰秒是不规律且不可预测的。本文包括了闰秒本身的信息,以及 Red Hat Enterprise Linux 是如何处理闰秒的。
即将发生的闰秒事件
目前,还没有已知的将要发生的闰秒调整事件。
环境
- Red Hat Enterprise Linux versions 4, 5, 6, 7 和 8
了解闰秒
对于世界上几乎所有的本地时间,它们所基于的时间被称为协调世界时 UTC,UTC 派生自一批分布在世界各地的原子时钟。地区的旋转速度并不是非常恒定的,且会随时间而有所变化,同时会缓慢地减少平均轮转速度。这就是在 UTC 时间中需要加入闰秒的原因,它会调整 UTC 时间以反映实际的地球旋转速度。
为什么需要额外的秒?地球会在自己的轴上旋转,这决定了白天和晚上。在一个非常长的时间段内,地球的旋转会因为月亮-太阳相吸的效果而减慢。另外,地球也会受到其内部(地核,地幔)和外部(大气层,海洋)因素的影响。现在,时间主要是由 250 个分布在世界各地的原子时钟进行计算,它们通过测量原子中的能量级别的转换来决定时间。 这些分布在世界各地的时钟被用来计算出 UTC,这个时间测量机制与地球的旋转速度是相互独立的,因此需要定期使用闰秒进行调整来保持两者之间的一致。 此外,我们还要考虑到,当前天的长度比 1820 年时的长度长 2 毫秒。因此,UTC 会慢慢地变为与地球的旋转速度不同步。
International Earth Rotation Service, IERS 会测量地球实际的旋转速度,并决定在什么时候需要添加闰秒来进行调整。添加闰秒始终会被安排在一个月的最后一天(通常倾向于在 6 月末或 12 月末的 UTC 时间的午夜)进行。过去,所有添加闰秒都是在其中一个时间进行的(*)。 IERS 会在其 Bulletin C 中公布是否要增加闰秒的事件。当前,在到下一个可能的闰秒事件发生的半年前,Bulletin C 会对其进行公布。
IERS Bulletin C #30(2005 年 7 月)公布了要在 2005 年 12 月 31 日 UTC 午夜增加一个闰秒的信息。这是自 1998 年底起,插入的第一个闰秒。这就是为什么在之前的 7 年中开发的许多应用程序都无法正确地处理闰秒。
因为闰秒需要在世界各地的同一时间插入,因此插入闰秒的本地时间将取决于针对 UTC 的时区偏移。例如,如果所处的时区是 UTC +3h,则闰秒将在本地的午夜后的 3 小时插入。
处理 UTC 时间插入闰秒的标准方法是:
2011-12-31 23.59.57
2011-12-31 23.59.58
2011-12-31 23.59.59
2011-12-31 23.59.60 <-- leap second
2012-01-01 00.00.00
2012-01-01 00.00.01
2012-01-01 00.00.02
如果系统时钟为 TAI,且使用 right/* 时区,则可能会列出 23:59:60;但是,因为在 Unix 的实现中并不存在 23:59:60,因此 linux 内核会在 0:00 UTC 后第一次更新时钟时将系统时钟调后一秒。 本地时间取决于具体的时区偏移,例如,如果是 UTC+3h,您应该会观察到 :
2012-01-01 02:58:00.000
2012-01-01 02:58:00.500
2012-01-01 02:59:00.000
2012-01-01 02:59:00.500
2012-01-01 03:00:00.0xx <-- leap second inserted
2012-01-01 02:59:00.0xx
2012-01-01 02:59:00.500
2012-01-01 03:00:00.000
2012-01-01 03:00:00.500
闰秒不具有连续性。因此,时间并不是连续增加的,而是以一秒为单位步进。我们来看一下插入闰秒时的时间戳,以及闰秒后的秒:
2011-12-31 23.59.60 <-- leap second
2012-01-01 00.00.00
我们可以对闰秒的时间和日期进行规范化:
60 秒为 1 分钟,使分钟从 59 递增到 60
60 分钟为 1 小时,使小时从 23 增加到 24
24 小时为 1 天,使日期递增,以此类推。
最后,我们可以说以上两行都代表相同的时间,或者说连续的 2 个秒具有相同的时间戳。
在 IERS 决定后,其他一些关于时间的服务也会处理相应的闰秒信息。这包括 German long wave transmitter DCF77,以及基于卫星的导航系统 GPS,因此接收这些系统的信号的接收方也会解码闰秒的公布信息。如果应用程序从这些接收方中读取时间信息,它们会决定是否将闰秒的信息包括在相关的协议中,如接收方传输的时间字符串。
请注意,时间代码接收器只会将闰秒信息发送到应用程序,且只在该期间正确计算时间。正确处理闰秒是应用程序和/或操作系统的任务。
(*):在北美地区内的一些 NTP (Network Time Protocol) 服务器错误地公布了一个在 2012 年 8 月 31 日 UTC 午夜的额外闰秒的信息。 两个 stratum 1 服务器 -- truechimer.cites.illinois.edu 和 time-b.nist.gov -- 被发现错误地发出了闰秒通知。任何更高的 stratum (stratum 2, 3, 4....) NTP 服务器如果在其层次结构中包括了这两个服务器中的一个,则会被认为有不正确闰秒的问题。 使用这些服务器的 NTP 客户端会设置内核的 leap indicator 标志,该标志在系统重新引导前不会被清除。
处理闰秒
有两个处理闰秒的主要方式,具体取决于系统时钟配置。
系统时钟使用 UTC,通过 NTP 或 PTP 进行同步
如前所述,当系统使用 UTC 时需要跳过闰秒,因为它并不存在。 因此,为了避免系统时钟比 UTC 快一秒,需要在出现闰秒后,对系统时钟进行相应的修正。 您可以按照以下方法对时钟进行修正:
通知内核,使其对时钟进行调整
大多数守护进程的默认方法是通知内核,使其插入闰秒。 例如,在需要插入闰秒的前一天,NTP 服务器需要通知其客户端将于 23:59:59 UTC 插入一个闰秒,Linux 内核应通过使 60 秒发生两次或完全删除它来添加或删除额外的一秒。因此,对于运行 NTP 客户端的 Red Hat Enterprise Linux 系统(带有默认配置),在进行闰秒调整的最后一秒期间,会有以下时间:
2008-12-31 23:59:59:052549000 UTC <-- 1st occurrence of the 60th second
2008-12-31 23:59:59:259988000 UTC
2008-12-31 23:59:59:465214000 UTC
2008-12-31 23:59:59:669629000 UTC
2008-12-31 23:59:59:873936000 UTC
2008-12-31 23:59:59:079184000 UTC <-- 2nd occurrence of the 60th second
2008-12-31 23:59:59:284011000 UTC
2008-12-31 23:59:59:488648000 UTC
2008-12-31 23:59:59:692691000 UTC
2008-12-31 23:59:59:896577000 UTC
2009-01-01 00:00:00:052378000 UTC
当出现闰秒时,内核会输出一个系统日志消息。
使守护进程调整时钟
守护进程也可能会自己调整系统时钟,而不是通知内核来调整时钟。 对于插入的闰秒,其时间的计算方法与内核类似。因为守护进程执行实际的闰秒插入,所以特定于内核的程序错误不会发生。
Slew 闰秒
RHEL 6.8 和 RHEL 7.2 引进了一个使用 Chrony 在系统中对闰秒进行 slew 处理,将闰秒的一秒分散到一段时间内进行调整而不是马上步进一秒。这个 Slew 会处理在 00:00:00 UTC(插入闰秒)或 23:59:59 UTC(删除闰秒)时积累的一秒的偏移。这一秒钟的偏移是在一段时间内进行积累的。 当应用程序对系统时间突然变化敏感,且可以允许时钟在一段较长的时间段内不完全正确,则可以使用 slew 方法来处理闰秒。
忽略闰秒
守护进程也可能被配置为完全忽略闰秒而不处理它,以便在方便的时间点来修正时间。 对于这种配置,时钟继续使用错误的时间,直到通过正常操作解决了这个问题为止。 如果使用此方法配置了多个系统,则多个系统中的时间可能会有一定的偏差,因为其修正过程是相对独立的。 对于需要同步通信的系统,不建议使用这个方法。
NTP 服务器上的闰秒涂抹(smear)
RHEL 6.8 和 RHEL 7.2 引入了一个选项,当 Chrony 在 NTP 服务器上运行时可以对闰秒进行涂抹(smear)处理。 这个方法不是让客户端对闰秒进行 slew 处理,而是在服务器上对闰秒进行控制,对其进行 slew 处理来缓慢地调整服务器所提供的时间,而不是以步进的方式一次调整闰秒。 客户端不需要任何特殊的配置,因为它们不知道有闰秒,并且将继续遵循服务器时间,直到它们与 UTC 同步。 在服务器上涂抹闰秒要比在单个客户端上进行闰秒调整要慢;但是,它可以保证所有客户端都可以进行连接。
当将 NTP 服务器配置为涂抹闰秒时,必须确保所有使用该服务器的客户端都指向使用相同方式执行涂抹的服务器。如果客户端被配置为接收多个服务器的更新,并且这些服务器以不同的方式处理闰秒,则会产生不一致的结果。
选项表
下表显示了每个守护进程可用的选项:
方法 | NTPD | CHRONYD | PTP4L | PHC2SYS |
---|---|---|---|---|
内核步进(Kernel Step) | 是(默认) | 是(默认) | 是(默认) | 是(默认) |
守护进程步进(Daemon Step) | 是(禁用带有 ntp 4.2.6 的内核) | 是 (leapsecmode step) | 否 | 否 |
Slew | 否 | 是 (leapsecmode slew) | 否 | 否 |
Ignore | 是 (-x) | 是 (leapsecmode ignore) | 是 (kernel_leap 0) | 是 (-x) |
配置示例的列表可在此页的底部找到(在 示例配置)。
下表展示了每个配置方法的效果:
客户端内核步进 | 客户端守护进程步进 | 客户端 slew | 客户端忽略 (ntpd -x) | 服务器 slew (smear) | |
---|---|---|---|---|---|
持续的时间 | 否 | 否 | 是 | 是 | 是 |
关掉时钟的长度 | 1 秒 | 1 秒 | 几秒或几分钟 | 几小时 | 几小时 |
频率错误 | 零* | 零* | 大 | 小 | 小 |
内核 bug | 是 | 否 | 否 | 否 | 否 |
客户端相互保持同步 | 是* | 是* | 是 | 否 | 是 |
* 忽略时间上的不连续
系统时钟保持 TAI-10 秒形式的时间,不会被同步,并使用 right/* 时区
通过将 tzdata
软件包更新至最新版本,将 /usr/share/zoneinfo/right
目录层次结构中合适的文件拷贝到 /etc/localtime
,并将时钟重置回正确的本地时间,系统也可以被配置为报告校正的闰秒时间。/usr/share/zoneinfo/right
中的文件包含自 1970-01-01 00:00:00 UTC 新纪元开始以来所发生的所有闰秒的本地时间信息。/usr/share/zoneinfo
中的其他时区文件没有添加闰秒校正。 在添加了 2008 年的闰秒后,自新纪元以来,已共添加了 24 个闰秒。 任何期望时间为 UTC 的应用程序,在使用 right/* 时区时将会遇到问题。
例如,如果某个系统位于 America/Los_Angeles (US Pacific) 时区,您可以重新配置系统,通过运行以下命令来报告已对闰秒进行了正确处理的时间,并将时钟重置为 Pacific Time:
cp /usr/share/zoneinfo/right/America/Los_Angeles /etc/localtime
更改 /etc/localtime
后, glibc
会自动重新载入此文件。请注意,调整时区不会更改系统时间,只会更改系统时间到本地时间的转换,这是通过 glibc 函数(如 localtime()
、ctime()
)在应用程序中发生的。 在这个更新中,不需要重启系统;但是,如果任何应用程序会缓存来自这些功能的结果,则在更新了 tzdata
后可能需要重启这些应用程序。
注:红帽不推荐在没有启用时间同步源的情况下运行,因为无法保证系统相互保持同步。 根据其时钟源,不同系统间中可能会存在时间偏差。 如需在没有 NTP/PTP/Chrony 的情况下运行,则需要针对每个具体的系统或集群,考虑发生时间偏差时造成的影响。
默认情况下,没有使用 NTP 或 PTP 来同步其时间的 Linux 系统不会对闰秒进行正确的调整。当发生闰秒的情况后,这样的系统会与 UTC 相差一秒钟。您应该在闰秒后手动重置时钟。
已知问题
RHEL 4
- 打印此消息可能会导致 Red Hat Enterprise Linux 4 内核崩溃。这个问题的具体信息包括在System hangs on printing the leap second insertion message。
- Slew 模式无法防止 ntp 设置内核标记:这个问题的具体信息包括在 In Red Hat Enterprise Linux 4, slew mode does not prevent ntp from setting the kernel flag。
- 对于没有通过 ntpd 或 ptp 进行同步的系统,需要一个更新的
tzdata
软件包(包含 12 月 31 日的闰秒)。 这个更新的tzdata
软件包作为 RHEA-2016-1982 的一部分发布,任何没有使用 ntpd 或 ptp 同步的 RHEL 4 系统都应该更新至tzdata-2016g-2.el4
或更新的版本,以接收此修复程序。
RHEL 5
- 打印此消息可能会导致 Red Hat Enterprise Linux 5 内核崩溃。这个问题的具体信息包括在System hangs on printing the leap second insertion message。
- 当在 slew 模式下运行
ntp
时,系统时间没有正确地调整闰秒。这个问题的具体信息包括在 Time is not adjusted by a leap second when ntpd runs with -x option。 - 对于没有通过 ntpd 或 ptp 进行同步的系统,需要一个更新的
tzdata
软件包(包含 12 月 31 日的闰秒)。 这个更新的tzdata
软件包作为 RHEA-2016-1982 的一部分发布,任何没有使用 ntpd 或 ptp 同步的 RHEL 5 系统都应该更新到tzdata-2016g-2.el5
或更新的版本,以接收此修复程序。
RHEL 6
- 当系统接收到关于插入一个闰秒的通知时,可能会导致挂起。这个问题的具体信息包括在 Systems hang due to leap-second livelock。
- 插入闰秒后,大量使用 futex 系统调用的应用程序会开始消耗大量 CPU 资源。这个问题的具体信息包括在 Why is there high CPU usage after inserting the leap second?。
- 在闰秒情况下,TAI 偏移没有被正确更新。这个问题的具体信息包括在 TAI offset is incorrect during the leap second。
- 当
-x
与 ntp 一起使用时,在出现闰秒时时钟仍然会马上改变。这个问题的具体信息包括在 Does Red Hat plan to release xleap.patch with ntp?。 - 当闰秒被插入时,绝对时间可能会提早。这个问题的具体信息包括在 Absolute Timers that Expire at Midnight UTC May Fire Early When the Leap Second is Inserted。
- 对于没有通过 ntpd 或 ptp 进行同步的系统,需要一个更新的
tzdata
软件包(包含 12 月 31 日的闰秒)。 这个更新的tzdata
软件包作为 RHEA-2016-1982 的一部分发布,任何没有使用 ntpd 或 ptp 同步的 RHEL 6 系统都应该更新到tzdata-2016g-2.el6
或更新的版本,以接收此修复程序。 - 当对闰秒进行 smear 处理时,chronyd 可能会崩溃。这个问题记录在 Chronyd crashes when performing server leap smear。
- 某些版本的 NTP 在已插入闰秒后仍会继续宣布闰秒。这个问题的具体信息包括在 The ntpd leap status is not reset after inserting a leap second。
RHEL 7
- 当
-x
与 ntp 一起使用时,在出现闰秒时时钟仍然会马上改变。这个问题的具体信息包括在 Does Red Hat plan to release xleap.patch with ntp?。 - 当闰秒被插入时,绝对时间可能会提早。这个问题的具体信息包括在 Absolute Timers that Expire at Midnight UTC May Fire Early When the Leap Second is Inserted。
- 对于没有通过 ntpd 或 ptp 进行同步的系统,需要一个更新的
tzdata
软件包(包含 12 月 31 日的闰秒)。 这个更新的tzdata
软件包作为 RHEA-2016-1982 的一部分发布,任何没有使用 ntpd 或 ptp 同步的 RHEL 7 系统都应该更新到tzdata-2016g-2.el7
或更新的版本,以接收此修复程序。 - 当对闰秒进行 smear 处理时,chronyd 可能会崩溃。这个问题记录在 Chronyd crashes when performing server leap smear。
- 当插入闰秒时,hrtimers 可能会提早。这个问题的具体信息包括在 Hrtimers may expire early when a leap second is inserted。
- 某些版本的 NTP 在已插入闰秒后仍会继续宣布闰秒。这个问题的具体信息包括在 The ntpd leap status is not reset after inserting a leap second。
除了以上提到的问题外,如果在开发具体应用程序时没有考虑到闰秒的问题,可以还会导致出现其他的问题。 这类问题的具体信息记录在 Libraries and Applications do not account for the Leap Second。
注:红帽建议使用 PPC 和 IA64 架构的客户使用 Systems not running NTP or PTP 中介绍的方法。
实时内核
与实时内核相关的问题包括在一个单独的文章中。 如需更多信息,请参阅 Resolve Leap Second Issues in Realtime (RT) kernels。
测试
红帽会继续测试相关的问题,并根据新的测试信息更新此文档。
我们已建立了一个进行相关测试的实验室,具体信息包括在 Leap Second Issue Detector。
此外,红帽强烈建议客户测试自己的构建和环境。Are we susceptible to a leap second event? 包括了如何进行相关测试的信息。
配置示例
使用 Chrony 对闰秒进行步进处理
要对闰秒进行步进处理,将一些选项添加到 /etc/chrony.conf
:
leapsecmode step
这些选项将指示 chronyd
通过步进一秒的方式来修正系统时钟,避免任何由内核插入闰秒的问题。
使用 chrony 对闰秒进行 slew 处理
要对闰秒进行 slew 处理,把以下选项添加到 /etc/chrony.conf
:
leapsecmode slew
这些选项将指示 chronyd
对闰秒进行 slew 处理来修正系统时钟,而不是立即执行对闰秒的步进调整。
在 chrony NTP 服务器中对闰秒进行涂抹(smear)处理以为客户端提供时间
要对闰秒进行涂抹处理,把以下选项添加到 /etc/chrony.conf
:
leapsecmode slew
maxslewrate 1000
smoothtime 400 0.001 leaponly
这些选项将指示 chronyd
以涂抹的方式对闰秒进行处理以修正系统时钟,并将本地时钟的 slew 的比率限制在 1000 ppm(1000 parts per million)。
忽略 NTPD 闰秒
要忽略闰秒,而是由常规的 slew 操作来调整它,请确保 /etc/sysconfig/ntpd
中存在以下行:
OPTIONS="-g -x"
在添加了这个标志后,内核的闰秒调整会被禁用,闰秒会在一段时间后才会被调整。
其它资源
有关闰秒,以及 Linux 和 NTP 如何处理闰秒的信息,请访问以下链接:
Comments