Linux

還有其他人在閏第二天經歷過 Linux 伺服器崩潰的高頻率嗎?

  • July 3, 2012

***注意:如果您的伺服器由於核心混淆而仍然存在問題,並且您無法重新啟動 - 建議在系統上安裝 gnu date 的最簡單解決方案是:date -s now。這將重置核心的內部“time_was_set”變數並修復 java 和其他使用者空間工具中佔用 CPU 的 futex 循環。我已經在我自己的系統上跟踪了這個命令,並確認它正在執行它在錫上所說的 ***

屍檢

Anticlimax:唯一死掉的是我的 VPN (openvpn) 到集群的連結,所以在它重新建立時有幾秒鐘令人興奮。其他一切都很好,並且在閏秒過去後啟動 ntp 乾淨利落。

我已經在http://blog.fastmail.fm/2012/07/03/a-story-of-leaping-seconds/上寫下了我當天的全部經歷

如果您在http://my.opera.com/marcomarongiu/blog/2012/06/01/an-humble-attempt-to-work-around-the-leap-second上查看 Marco 的部落格- 他有一個解決方案使用 ntpd -x 在 24 小時內分階段進行時間更改,以避免 1 秒跳過。這是執行您自己的 ntp 基礎設施的另一種塗抹方法。


就在今天,2012 年 6 月 30 日星期六 - 格林威治標準時間開始後不久。我們在由不同團隊管理的不同數據中心中的少數伺服器都變黑了 - 不響應 ping,螢幕空白。

他們都在執行 Debian Squeeze - 從股票核心到定制的 3.2.21 建構,應有盡有。大多數是戴爾 M610 刀片,但我也剛剛失去了戴爾 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參數以刪除閏秒

注意:取決於adjtimex. 我在http://linux.brong.fastmail.fm/2012-06-30/adjtimexadjtimex上放了一份壓縮二進製文件的副本——它可以在不依賴壓縮 64 位系統的情況下執行。如果將它放在與 相同的目錄中,則在系統不存在時將使用它。顯然,如果你沒有 64 位的擠壓……找到你自己的。fixtime.pl

ntp明天要重新開始。

正如一位匿名使用者所建議的那樣 - 跑步的替代方法adjtimex是自己設置時間,這可能也會清除閏秒計數器。

這是由 ntpd 呼叫 adjtimex(2) 告訴核心插入閏秒時的活鎖引起的。請參閱 lkml 發布http://lkml.indiana.edu/hypermail/linux/kernel/1203.1/04598.html

Red Hat 也應該更新他們的知識庫文章。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 更新了他們的知識庫文章,指出:“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 自旋鎖被釋放。

這裡有一些有趣的事情。

首先,第 691 行在每次呼叫 adjtimex(2) 時取消現有計時器。然後,554 重新創建該計時器。這意味著每次 ntpd 執行其時鐘循環過濾器時,都會呼叫錯誤程式碼。

因此,我認為 Red Hat 說一旦 ntpd 設置了閏秒標誌,系統就不會崩潰是錯誤的。我相信每個執行 ntpd 的系統都有可能在閏秒前的 24 小時內每 17 分鐘(或更長時間)發生一次活鎖。我相信這也可以解釋為什麼這麼多系統崩潰了;與每小時 3 次發生碰撞相比,一次發生碰撞的可能性要小得多。

更新:在https://access.redhat.com/knowledge/solutions/154713上的 Red Hat KB 解決方案中,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 負載飆升。

引用自:https://serverfault.com/questions/403732