闰秒期间还有其他人遇到过 Linux 服务器大量崩溃的情况吗?

闰秒期间还有其他人遇到过 Linux 服务器大量崩溃的情况吗?

*注意:如果您的服务器仍然因内核混乱而出现问题,并且您无法重新启动 - 在您的系统上安装 gnu date 后,最简单的解决方案是:date -s now。这将重置内核的内部“time_was_set”变量并修复 java 和其他用户空间工具中占用 CPU 的 futex 循环。我已经在自己的系统上跟踪了此命令,并确认它正在执行它所说的操作*

事后分析

令人失望的是:唯一断掉的是我的 VPN(openvpn)与集群的链接,因此在它重新建立的几秒钟里,我们兴奋不已。其他一切都很好,闰秒过去后,ntp 启动也很顺利。

我已经把我当天的经历写在http://blog.fastmail.fm/2012/07/03/a-story-of-leaping-seconds/

如果你看看 Marco 的博客http://my.opera.com/marcomarongiu/blog/2012/06/01/an-humble-attempt-to-work-around-the-leap-second- 他有一个解决方案,使用 ntpd -x 在 24 小时内逐步更改时间,以避免 1 秒的跳过。这是运行您自己的 ntp 基础设施的替代涂抹方法。


就在今天,2012 年 6 月 30 日星期六 - 格林威治标准时间刚过一天。我们位于不同数据中心的几台服务器(由不同的团队管理)全部瘫痪 - 不响应 ping,屏幕空白。

它们都运行 Debian Squeeze - 包括从库存内核到自定义 3.2.21 版本的一切。大多数是 Dell M610 刀片,但我刚刚丢失了一台 Dell R510,其他部门也丢失了其他供应商的机器。还有一台较旧的 IBM x3550 崩溃了,我以为这可能无关紧要,但现在我很怀疑。

有一次崩溃我确实得到了屏幕转储,其中显示:

[3161000.864001] BUG: spinlock lockup on CPU#1, ntpd/3358
[3161000.864001]  lock: ffff88083fc0d740, .magic: dead4ead, .owner: imapd/24737, .owner_cpu: 0

不幸的是,所有刀片服务器都配置了 kdump,但它们死机太厉害,kdump 无法触发 - 而且它们还打开了控制台消隐功能。我现在已经禁用了控制台消隐功能,所以希望下次崩溃后我能得到更多信息。

只是想知道这是普遍现象还是“只有我们”。它们位于不同数据中心的不同单元,购买时间不同,由不同的管理员运行(我运行的是 FastMail.FM 的单元),这真的很奇怪……现在甚至还有不同的供应商硬件。大多数崩溃的机器已经运行了数周/数月,并且运行的是 3.1 或 3.2 系列内核。

最近的一次崩溃是一台运行 3.2.21 的机器,它只运行了大约 6 个小时。

解决方法

好的,各位,下面是我解决这个问题的方法。

  1. 禁用ntp:/etc/init.d/ntp stop
  2. 创建http://linux.brong.fastmail.fm/2012-06-30/fixtime.pl(代码取自 Marco,请参阅评论中的博客文章)
  3. 毫无争议地跑去fixtime.pl看看有没有闰秒
  4. 提出fixtime.pl要取消闰秒

注意:取决于。我把 squeeze二进制文件adjtimex的副本放在adjtimexhttp://linux.brong.fastmail.fm/2012-06-30/adjtimex— 它可以在不依赖 squeeze 64 位系统的情况下运行。如果您将它放在与 相同的目录中fixtime.pl,则当系统版本不存在时将使用它。显然,如果您没有 squeeze 64 位……请自行寻找。

ntp明天又要重新开始。

正如一位匿名用户所建议的那样 - 运行的替代方法adjtimex是自己设置时间,这大概也会清除闰秒计数器。

答案1

这是由 ntpd 调用 adjtimex(2) 来告诉内核插入闰秒时发生的活锁引起的。请参阅 lkml 帖子http://lkml.indiana.edu/hypermail/linux/kernel/1203.1/04598.html

Red Hat 也应该更新他们的 KB 文章。https://access.redhat.com/knowledge/articles/15145

更新:Red Hat 有第二篇专门针对此问题的知识库文章:https://access.redhat.com/knowledge/solutions/154713- 上一篇文章是针对一个早期的、不相关的问题

解决方法是关闭 ntpd。如果 ntpd 已经发出 adjtimex(2) 调用,您可能需要禁用 ntpd 并重新启动才能 100% 安全。

这会影响 RHEL 6 和其他运行较新内核(约比 2.6.26 更新)的发行版,但不会影响 RHEL 5。

发生这种情况的原因闰秒实际安排发生的原因是 ntpd 让内核在午夜处理闰秒,但需要在午夜之前提醒内核插入闰秒。因此,ntpd 会在闰秒当天的某个时间调用 adjtimex(2),此时会触发此错误。

如果您安装了 adjtimex(8),则可以使用此脚本来确定是否设置了标志 16。标志 16 是“插入闰秒”:

adjtimex -p | perl -p -e 'undef $_, next unless m/status: (\d+)/; (16 & $1) && print "leap second flag is set:\n"'

更新:

Red Hat 已更新其 KB 文章,内容如下:“RHEL 6 客户可能会受到一个已知问题的影响,该问题会导致 NMI Watchdog 在收到 NTP 闰秒公告时检测到挂起。此问题正在及时解决。如果您的系统收到了闰秒公告,但没有遇到此问题,则它们不再受到影响。”

更新:上述语言已从 Red Hat 文章中删除;并添加了第二个 KB 解决方案,详细说明了 adjtimex(2) 崩溃问题:https://access.redhat.com/knowledge/solutions/154713

然而,IBM 工程师 John Stultz 在 LKML 帖子中更改的代码指出,在实际应用闰秒时也可能出现死锁,因此您可能需要在禁用 ntpd 后通过重新启动或使用 adjtimex(8) 来禁用闰秒。

最后更新:

好吧,我不是内核开发人员,但我在这里再次查看了 John Stultz 的补丁:https://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=6b43ae8a619d17c4935c3320d2ef9e92bdeed05d

如果这次我没看错的话,我之前关于应用闰秒时会出现另一个死锁的说法是错误的。根据他们的 KB 条目,这似乎也是 Red Hat 的观点。但是,如果您已禁用 ntpd,请将其再禁用 10 分钟,这样当 ntpd 调用 adjtimex(2) 时就不会遇到死锁。

我们很快就会发现是否还有更多错误:)

跃迁后第二次更新:

我花了几个小时阅读 ntpd 和修补前的(有缺陷的)内核代码,虽然我在这里可能错了,但我会尝试解释我认为发生了什么:

首先,ntpd 始终调用 adjtimex(2)。这是其“时钟环路过滤器”的一部分,在 ntp_loopfilter.c 中的 local_clock 中定义。您可以在此处看到该代码:http://www.opensource.apple.com/source/ntp/ntp-70/ntpd/ntp_loopfilter.c(来自 ntp 版本 4.2.6)。

时钟循环过滤器运行得相当频繁 —— 每次 ntpd 轮询其上游服务器时它都会运行,默认情况下每 17 分钟或更长时间运行一次。时钟循环过滤器的相关位是:

if (sys_leap == LEAP_ADDSECOND)
    ntv.status |= STA_INS;

进而:

ntp_adjtime(&ntv)

换句话说,在有闰秒的日子里,ntpd 会设置“STA_INS”标志并调用 adjtimex(2)(通过其可移植性包装器)。

该系统调用进入内核。以下是相关的内核代码:https://github.com/mirrors/linux/blob/a078c6d0e6288fad6d83fb6d5edd91ddb7b6ab33/kernel/time/ntp.c

内核代码路径大致如下:

  • 第 663 行——do_adjtimex 例程开始。
  • 第 691 行-取消任何现有的闰秒计时器。
  • 第 709 行 - 抓住 ntp_lock 自旋锁(此锁与可能的活锁崩溃有关)
  • 第 724 行——调用 process_adjtimex_modes。
  • 第 616 行——调用 process_adj_status。
  • 第 590 行 - 根据 adjtimex(2) 调用中设置的标志,设置 time_status 全局变量
  • 第 592 行 - 检查 time_state 全局变量。在大多数情况下,调用 ntp_start_leap_timer。
  • 第 554 行 - 检查 time_status 全局变量。STA_INS 将被设置,因此将 time_state 设置为 TIME_INS 并调用 hrtimer_start(另一个内核函数)来启动闰秒计时器。在创建计时器的过程中,此代码会获取 xtime_lock。如果发生这种情况,而另一个 CPU 已经获取了 xtime_lockntp_lock,然后是内核活锁。这就是 John Stultz 编写补丁以避免使用 hrtimers 的原因。这就是今天给大家带来麻烦的原因。
  • 第 598 行 - 如果 ntp_start_leap_timer 实际上没有启动跳跃计时器,则将 time_state 设置为 TIME_OK
  • 第 751 行 - 假设内核没有活锁,则堆栈被解开并且 ntp_lock 自旋锁被释放。

这里有一些有趣的事情。

首先,每次调用 adjtimex(2) 时,第 691 行都会取消现有计时器。然后,第 554 行会重新创建该计时器。这意味着每次 ntpd 运行其时钟循环过滤器时,都会调用有缺陷的代码。

因此,我认为 Red Hat 的说法是错误的,他们说一旦 ntpd 设置了闰秒标志,系统就不会崩溃。我相信每个运行 ntpd 的系统都有可能在闰秒之前的 24 小时内每 17 分钟(或更长时间)发生一次活锁。我相信这也可以解释为什么这么多系统崩溃;与每小时 3 次相比,一次崩溃的可能性要小得多。

更新:在 Red Hat 的知识库解决方案中https://access.redhat.com/knowledge/solutions/154713,Red Hat 工程师确实得出了同样的结论(运行 ntpd 会不断遇到错误代码)。而且他们确实比我早几个小时就得出了结论。此解决方案未链接到主要文章https://access.redhat.com/knowledge/articles/15145,所以直到现在我才注意到。

其次,这也解释了为什么加载的系统更容易崩溃。加载的系统将处理更多中断,从而导致“do_tick”内核函数被更频繁地调用,从而为该代码在创建计时器时运行和获取 ntp_lock 提供了更多机会。

第三,当闰秒真正发生时,系统是否有可能崩溃?我不确定,但有可能,因为触发并实际执行闰秒调整的计时器(ntp_leap_second,第 388 行)也会获取 ntp_lock 自旋锁,并调用 hrtimer_add_expires_ns。我不知道该调用是否也可能导致活锁,但这似乎并非不可能。

最后,是什么原因导致闰秒标志在闰秒运行后被禁用?答案是 ntpd 在午夜后调用 adjtimex(2) 时停止设置闰秒标志。由于未设置标志,第 554 行上的检查将不为真,并且不会创建任何计时器,第 598 行将把 time_state 全局变量重置为 TIME_OK。这解释了为什么如果您在闰秒后立即使用 adjtimex(8) 检查标志,您仍然会看到闰秒标志被设置。

简而言之,今天最好的建议似乎毕竟是我给出的第一个建议:禁用 ntpd,并禁用闰秒标志。

最后还有一些想法:

  • 没有一家 Linux 供应商注意到 John Stultz 的补丁并将其应用到他们的内核中 :(
  • 为什么 John Stultz 没有提醒一些供应商这是必要的?也许活锁的可能性看起来很低,发出噪音是没有必要的。
  • 我听说过,在应用闰秒时,Java 进程会锁定或旋转。也许我们应该效仿 Google,重新思考如何将闰秒应用于我们的系统:http://googleblog.blogspot.com/2011/09/time-technology-and-leaping-seconds.html

06/02 John Stultz 的更新:

https://lkml.org/lkml/2012/7/1/203

该帖子逐步介绍了闰秒为何会导致 futex 计时器过早并持续到期,从而导致 CPU 负载激增。

答案2

这给我们带来了沉重的打击。在重启了许多主机后,下面的操作非常简单,而且完全有效,无需重启主机:

/etc/init.d/ntp stop
ntpdate 0.us.pool.ntp.org
/etc/init.d/ntp start

只需重置系统时钟即可。天哪。我六个小时前就知道了。

答案3

一个简单的 C 程序,用于清除内核时间状态字段中的闰秒位:

#include <sys/timex.h>
#include <string.h>
#include <stdio.h>

int main(int argc, char **argv) {
    struct timex txc;
    int ret;

    (void) argc;
    (void) argv;

    bzero(&txc, sizeof(txc));
    txc.modes = 0;  /* fetch */
    ret = adjtimex(&txc);
    if (ret < 0) {
        perror("adjtimex (get)");
        return 1;
    }

    txc.modes = ADJ_STATUS;
    txc.status &= ~16;
    ret = adjtimex(&txc);
    if (ret < 0) {
        perror("adjtimex (set)");
        return 1;
    }

    return 0;
}

另存为,用root 身份lsec.c编译并运行。gcc -Wall -Wextra -o lsec lsec.c

您可能希望在运行 ntpd 之前先将其停止,然后在闰秒之后重新启动 ntpd。

答案4

http://my.opera.com/marcomarongiu/blog/2012/03/12/no-step-back似乎表明 Debian squeeze 内核无法处理闰秒。

关于 comp.protocols.tim.ntp 的这个线程也很有趣:https://groups.google.com/forum/?fromgroups#!topic/comp.protocols.time.ntp/KSflIgjUdPE

也就是说,闰秒还没有发生:23:59:60 UTC

最后,https://access.redhat.com/knowledge/articles/15145有以下内容:“当闰秒发生时,内核会将一条消息打印到系统日志中。打印此消息有可能会导致 Red Hat Enterprise Linux 中的内核崩溃。”

相关内容