標籤:

Linux RAS特性分析

(如果你看到這一行,說明本文仍處於修改狀態,內容正在進行邏輯整理和信息確認,非常不可靠)

[介紹]

RAS,是Reliabilty,Availability,Serviceability的縮寫,是對一台伺服器可以被可靠使用的要求。這個是個相當粗糙的定義。如果深入一點理解,所謂R,表示伺服器提供正確輸出的能力,比如我要求你給我計算1+1,你給我回應了,但你說等於3,這R就有問題了。A表示能提供輸出的能力,比如我讓你給我計算1+1,你確實不說這等於3,但你什麼都不說,那這個A就有問題了(總算是比說等於3好一點)。而S是說,如果你發現這個設備不能提供服務了(A出了問題),你把壞掉的部分換掉或者修好的能力。

但這仍是個非常粗糙,指向不明的定義。但RAS確實就是這麼個不清不楚的定義。

或者我們可以換個角度,整個RAS的最終評價標準,常常是MTBF,Mean Time Between Failure,也就是你的伺服器有多長時間能「正確提供所需功能」。我們經常說某個系統是4個9還是6個9,說的就是MTBF這個指標。

但MTBF是個綜合指標,和你的硬體,軟體,使用方法(使用時的規章制度)統統有關,設計上是沒有那麼容易說清楚的。作者曾經參與過一個火車調度系統的設計,這種系統的每個輸出,都是三套獨立的高可靠系統用不同演算法進行運算的結果,然後再從這三個結果中投票決定實際的輸出。從這類的設計就可以看出,系統一級的MTBF保障手段,通常不相信決策系統的任何一環的。

但我們一般做單機的時候考慮不到這麼高的高度,我們只能保證硬體基本上是可靠的。軟體本身有沒有問題,這個就要另外找方法來保證了。所以,這裡談Linux RAS特性,更多的是談Linux如何處理硬體不可靠導致的問題,而不是如何保證全系統如何達到更高的MTBF。

基於PC的Linux和基於工作站的Unix不同,它一開始根本就是個玩具,就不是個高可靠的系統。所以Linux在架構上就不具有一般比如Solari或者AIX那種完整的RAS管理系統。所以,Linux就沒有一套邏輯完整的RAS機制。甚至現在你看Linux內核中的Documentations/admin-guide/ras.rst,它也僅僅介紹了EDAC子系統,而說不清楚整個RAS到底在Linux中的邏輯是怎麼樣的。

但正如我在這個專欄(包括那個道德經的專欄)中說的,這個世界不是基於邏輯的,它是基於「度」的(更微小邏輯的組合,這些組合超過你理智思維可以容納幅度)。不是你有RAS或者沒有RAS,或者提供什麼特定的RAS功能就可以判斷這個系統是否成功的。當雲計算興起,中規中矩的Unix RAS設計顯得成本高昻而沒有意義,反而Linux加上一些半吊子的RAS設計,取得更好的競爭優勢。

半吊子設計的結果就是一般沒有人知道這整個設計的設計邏輯是什麼。所以本文嘗試基於4.13-rc7內核,提取一下Linux內核對RAS的認知模型和支持情況。

[硬體抽象]

RAS特性,首先保證的是R。系統掛了,可以重啟,但明明應該給我一個2的,你給我一個3,這就不可救藥了。所以在硬體設計上,優先保護的是這個R。而R的保護方法是就是在整個系統的傳輸系統(DDRC,Cache控制器,匯流排控制器等)加入各種完整性校驗,比如內存的ECC,IO的CRC,其他協議棧的各種Checksum等。當硬體系統發現這些錯誤後,它會嘗試修正它,或者告知系統發生了這個錯誤。

硬體設計者在做這種判斷的時候,非常關注錯誤的傳播問題。你在一個匯流排的節點上發現了一個錯誤,然後你把這個錯誤通過中斷報告給CPU,中斷是要經過中斷子系統上報的,在這個上報沒有生效前,這個錯誤的結果可能已經發給了CPU,然後CPU可能用這個結果計算出另一個結果,那個結果還被寫到另一個變數中,然後寫回到內存上,甚至保存到磁碟上。然後這個時候你才上來個中斷,告訴我剛才那個結果是錯的……我找誰說理去?所以硬體根據錯誤上報的傳播範圍,錯誤的分類會非常複雜(比如,在硬體標準的概念空間中會有「Deferred Error」這種改變表示錯誤已經被傳播出去了。而Linux則簡單得多,Linux在大部分應用中,只分辨兩種錯誤:CE的和UE的,前者是可以修正的(或者已經修正的),後者是不能修正的。所以,一定程度上,我們可以把各種硬體的錯誤,都歸結為這兩種類型中的一種),在Linux下,再複雜的報告,暫時可以理解為是這兩種中的一種。

當硬體偵測到一個錯誤,它有兩種方法報告CPU,一種方法是中斷。這是個非同步的過程,很容易造成傳播範圍不可控。如果這是CE的,錯誤已經被硬體主動修復,或者可以有手段修復(比如通過產生同步異常)。要不是UE的,這基本上就要導致停機乃至整體隔離了。

第二種錯誤的報告方法是把錯誤隨著CPU核的讀寫響應(消息)返回給CPU,讓CPU產生一個同步異常,CPU就有辦法修復這樣的錯誤,這種異常體現在CPU核上,就是一個page_fault中斷,只是不同的類型,CPU可以通過給對應的進程發SIGBUS一類的信號來控制這個錯誤。

這兩種方法可以配合起來同時使用,前者用於記錄錯誤,後者用來避免錯誤被傳播。

[EDAC]

Linux最早處理非同步中斷錯誤的框架叫EDAC,Error Detection And Correction。它包括兩個子系統,一個稱為edac_mc,另一個稱為edac_device。前者負責收集內存控制器報告的錯誤,後者負責其他控制器(比如L3 Cache控制器)報告的錯誤。通常是把控制器的驅動寫成一個平台設備,然後在probe的時候註冊為edac_mc或者edac_device。控制器驅動ioremap設備的IO空間,註冊處理中斷,在收到中斷以後,從IO空間中讀到參數,再調用edac的框架報告函數,報告相關的錯誤:

edac_mc_handle_error()nedac_raw_mc_handle_error()nedac_device_handle_ce()nedac_device_handle_ue()n

這些報告函數主要干這些事:

  1. printk:把錯誤列印到print ring buffer裡面
  2. trace_mc_event:把錯誤寫到ftrace的一個跟蹤項中
  3. 統計:把這個錯誤報告到根據DIMM條,Rank,Row的分類進行統計,為後續進行硬體替換提供參考
  4. 如果硬體報這是個UE,而且這個控制器要求UE即停機,則複位系統

我說Linux的RAS不成系統,這裡可見一斑:printk是個參考,是不適合正式處理的,trace_xxx是個跟蹤,不開跟蹤就不能工作,統計不能用於單個處理。說到底,EDAC被看作一個可有可無的特性了。

所以,當我們給Linux實現RAS特性的(硬體的)時候,必須有意識地用page_fault一類的異常來控制傳播範圍,只把中斷的報告看作是統計上的補充。

[ACPI APEI表]

EDAC是比較原始的實現,需要為每個平台的控制器寫獨立的驅動。ACPI標準的APEI表從BIOS層提供了標準的報告形式。APEI是ACPI Platform Error Interface的縮寫,它包括多張表:

  1. BERT: Boot Error Record Table,這個用於記錄前一次複位前BIOS記下來的錯誤,Linux讀到這個記錄會列印出來,以便知道比如上次因為UE而服務的原因
  2. EINJ:Error INJection,BIOS提供的硬體故障注入的介面,Linux把這個封裝成debugfs的屬性了,可以通過這個注入需要的硬體錯誤
  3. ERST:Error Record Serialization Table,這個表用於配合BERT,從OS側輔助BIOS把臨時前的錯誤信息保存到持久設備中。做硬體的同學要考慮適配這套框架,保證錯誤可以被固化到持久的存儲中
  4. HEST: Hardware Error Source Table,這個描述系統有多少個錯誤檢測設備,Linux中這個被實現為多個(每條記錄一個)平台設備
  5. GHES:General Hardware Error Source,這是硬體報錯的介面。Linux中,這個被實現為HEST定義的設備的驅動,每個那樣的平台設備,Probe到這個驅動上後,再註冊為一個edac_mc設備,這樣就和EDAC框架結合起來了

從這裡可以看到,APEI一定程度上是基於EDAC框架的,但它同時也提供獨立於EDAC之外的功能。所以,高級的標準的伺服器,更應該選擇的是走APEI路線,而不是EDAC的路線。

只要硬體提供APEI介面,Linux上就不需要額外的驅動了。

[MCE]

Linux還有一個傳統的報告系統,這個是硬體的概念,所謂Machine Check Exception,也是用於報告EDAC類似的錯誤的,但現在這個主要是比如PowerPC用得比較多,在x86上,現在這個系統還在,但RAS有關的報告已經大部分被APEI取代了,所以我們基本上現在可以忽略它,而聚焦到APEI支持上。

[異常內存頁隔離]

如果我們發現uc的內存問題,一種辦法當然可以立即停機。但其實還有一種方法是隔離掉這片內存。這個功能依然做在GHES上,ghes_handle_memory_failure()調用mm/mm-failure.c中的異常函數,Linux會把這個page標記為HWPOISON的,之後相關的頁,VM或者進程就會被隔離掉。

這個功能對比AIX這樣的高級貨,實在拿不出手,因為這並不能避免錯誤被傳播出去。但對一般數據中心來說,可能也夠了。對大部分數據中心來說,你能說你這個節點不可信就夠了,本來也不指望你還能提供內存雙備這種不計成本的高級特性來。

[PCIE匯流排錯誤]

PCIE匯流排有自己的錯誤報告標準,叫AER。實現為PIC配置空間的一個capability。和其他EDAC的控制器一樣,也實現為IO和中斷的形式。我覺得如果做得好的話,它應該被註冊為一個edac_device。但實際情況是,它直接通過printk和trace_aer_event()完成錯誤報告了。

AER和EDAC的處理策略幾乎和EDAC一樣,不同的是,當它發現錯誤的時候,會根據錯誤的類型,對鏈路,埠等硬體進行獨立的複位,嘗試修復系統。

AER錯誤現在通過APEI的GHES表收集的,PCIE匯流排驅動僅僅提供處理的手段。所以,要支持PCIE的錯誤,也需要實現APEI。

[其他硬體驅動的故障]

其他非規整的硬體,現在基本上都是通過trace_xxxx()這樣的方式記錄的。比如ARM就使用了自己的trace_arm_event()和trace_non_standard_event(),所以,綜合起來,全面收集所有RAS數據的方法,主要是ftrace介面。也就是說,在伺服器上,無論你是否要跟蹤,ftrace是必開的功能,否則RAS收集程序將無法工作。

[rasdaemon]

RAS是Linux下一個常用的ras收集器,很多高級伺服器當然會提供自己的收集daemon,但原理基本上也和rasdaemon差不多。它就是等在ftrace上,創建一個獨立的ftrace instance,收集需要的ftrace事件,然後記錄到sqlite3資料庫中。

現在rasdaemon收集的事件包括:

  1. EDAC_MC
  2. AER
  3. non_standard_event
  4. mce
  5. extlog_mem_event(這是x86 MCE特有的信息)

[故障注入]

Linux的故障注入做得很分散,每個獨立的功能有自己獨立的故障注入方式,AER有AER自己的,APEI有APEI自己的,memory的同步故障則通過HWPOISON_INJECT來注入。

[小結]

總結起來,Linux現在提供了基本的RAS功能(重點是保證R),足以支撐「有錯必須要知道」這樣的需要。主線方案應該是APEI+ftrace+rasdaemon。支持好這個,就提供了Linux最基本的RAS功能了。

推薦閱讀:

偽造掌閱ireader plus升級的伺服器
深入實時 Linux
Linux 包管理基礎:apt、yum、dnf 和 pkg
Bash判斷、循環、控制語句常用用法歸納
Linux文件亂碼

TAG:Linux内核 | Linux |