面對大規模系統工程,看Facebook如何處理故障排查(一)

做者介紹:Ben Maurer是Facebook的網絡基礎團隊的技術領先者,主要負責整個Facebook面向用戶產品的性能和可靠性。Ben於2010年正式加入Facebook,基礎設施團隊的成員。在加入Facebook以前,他與Luis von Ahn共同創立的驗證碼。最近,本與美國數字服務公司合做,以改進在聯邦政府的技術使用。算法

數人云今天爲你們帶來一篇Ben Maurer分享的「Facebook面對大規模系統工程故障排查實踐」,因爲內容較多,因此數人云今天只爲你們帶來上半部分,後續內容會在明天發佈!api

故障是任何大規模工程系統的一部分。Facebook的文化價值之一就是擁抱失敗。這能夠從掛在門洛帕克總部牆上的海報上獲得體現:「若是你無所畏懼,你會怎樣?」「天佑勇者。」緩存

爲了使Facebook的系統在快速變化的狀況下保持可靠,專門爲其研究了常見的故障模式,並創建抽象理念來解決這些問題。這些理念確保最佳實踐應用於的整個基礎設施。經過創建工具來診斷問題,並建立一種覆盤事故的文化來推進並做出改進,防止將來發生故障。服務器

爲何會發生故障?

雖然每個故障都有一個獨特的故事,可是多數故障均可以歸結爲少數的緣由。網絡

個別機器故障

單個機器一般會遇到一個孤立的故障,不會影響基礎設施的其他部分。例如,可能一臺機器的硬盤驅動器發生了故障,或者某臺機器上的服務遇到了代碼中的錯誤,內存損壞或等。併發

避免單個機器故障的關鍵是自動化,自動化工做最好結合已知的故障模式(如硬盤驅動器的S.M.A.R.T.錯誤)與未知問題的搜索(例如,經過交換服務器異常緩慢的響應時間)。當自動化發現一個未知問題,手工調查能夠幫助開發更好的工具來檢測和修復問題。框架

合理工做負荷的變化

遇到突發情況,Facebook會改變平常的行爲習慣,爲基礎設施帶來挑戰。例如,在重要的全球事件中,獨特的工做負載可能會以不尋常的方式來考驗其中的基礎設施。當奧巴馬贏得2008美國總統大選時,Facebook頁面活躍度刷新了記錄。如超級盃或者世界盃這樣重大的體育賽事也會引起其發帖數量大大增長。負載測試,包括「灰度發佈」即有新功能發佈,可是對於使用者不可見,有助於確保新功能可以處理負載。工具

在這些事件中收集的統計數據經常爲系統的設計提供一個獨特的視角。一般狀況下,重大事件致使用戶行爲的變化(例如,經過圍繞一個特定的對象建立主題活動)。有關這些更改的數據一般指向設計決策,以便在後續事件中容許更平滑的操做。性能

人爲失誤

鑑於Facebook鼓勵工程師「快速行動,打破常規」-如同裝飾辦公室的另外一個海報所示,也許有人會認爲,不少錯誤都是人爲形成的。根據數據代表,人爲失誤是失敗的一個因素。圖1涵蓋了嚴重到足以被認爲違反了SLA(服務水平協議)的事件的時間節點數據。因爲目標是很嚴格的,因此對網站用戶而言大多數事件是輕微的,不明顯的。圖1a顯示事件在星期六和星期日發生的機率大幅減小,然而也不會影響網站流量。圖1b顯示6個月的時間只有兩週沒有事件:包括聖誕節的一週和員工寫互評的一週。測試

這兩個數據彷佛代表,當Facebook的員工由於忙於其它事情(如週末、節假日以及員工考覈等)而沒有積極去改變基礎設施的時候,網站的可靠性反而處於一個比較高的水平。致使咱們相信這不是由於Facebook員工過於粗心,而是證實了基礎設施在很大程度上是對非人爲的錯誤進行自我修復,如機器故障。

三種容易致使事故的緣由

雖然事故有不一樣的產生緣由,可是經過總結髮現,有三種常見的緣由會使故障擴大併成爲大規模的問題。對於每個成因,都應制定相應的預防措施,以減輕大規模事故。

快速部署配置更改

配置系統每每被設計爲能在全球範圍內迅速複製更改。Rapid配置更改是一個功能強大的工具,可讓工程師快速管理新產品的推出或調整設置。然而,快速配置也意味着當配置不當時會快速引起故障。咱們採起了一些方法來防止配置更改致使故障。

  • 讓每一個人都使用一個通用的配置系統

使用通用配置系統能夠確保程序和工具適用於全部類型的配置。在Facebook,咱們發現團隊有時會試圖以一次性的方式來進行配置。避免使用這種方式而採用一種統一的方式來進行配置,從而使配置系統成爲一種提升站點可靠性的衡量方法。

  • 靜態驗證配置更改

許多配置系統容許鬆散類型的配置,如JSON結構。這些類型的配置很容易使工程師犯一些低級錯誤,例如敲錯字段,若是這個字段是必須使用整數的字符串。對於這種類型的錯誤最好的辦法就是使用靜態驗證。一個結構化的格式(例如,在Facebook使用的Thrift)能夠提供最基本的驗證。然而,編寫驗證程序來驗證更詳細的要求也是合理的。

  • 運行一個Canary

首先將配置部署到服務的小範圍,能夠防止災難性的更改。一個Canary能夠採起多種形式。最明顯的是A / B測試,如只對百分之一的用戶推出一個新的配置。多個A / B測試能夠同時運行,而且可使用數據隨時間進度來跟蹤度量。

然而,對於可靠性的目的,A / B測試不知足咱們的全部需求。一個更改部署給少數用戶,但致使了服務器崩潰或內存耗盡的變化,顯然會產生超出測試的有限用戶的影響。A / B測試也費時。工程師們經常但願在沒有使用A / B測試的狀況下推出一些微小的變化。爲此,Facebook基礎設施自動測試新配置的一小部分服務器。例如,若是咱們但願部署一個新的A / B測試給百分之一的用戶,首先部署測試在僅影響不多量服務器的那部分用戶,在一個很短的時間內監測這些服務器,以確保他們不會崩潰或有其餘很明顯的問題。這種機制提供了一個適用於全部變動的基本的「健全檢查」以確保它們不會形成大面積的故障。

  • 保持良好的配置

Facebook的配置系統的設計是儘可能確保當更新帶來故障時保持良好的配置。開發人員但願建立的配置系統當接收到無效的更新配置時會崩潰。喜歡在這些類型的狀況下保留舊的配置,並向系統操做員發出警報,說明該配置沒法更新。繼續運行舊有的配置一般優於將錯誤返回給用戶。

  • 使它容易恢復

有時,儘管盡了最大努力,部署的配置依然有問題,快速查找和恢復是解決這類問題的關鍵,配置系統是由版本控制,這使得系統很容易恢復。

核心服務的硬依賴

開發者一般默認配置管理,服務發現,存儲系統等核心業務永遠不會發生故障。但是,這些核心業務的輕微故障都會引發大面積的事故發生。

  • 核心服務的緩存數據

依賴於這些類型的服務一般是沒必要要的,能夠經過緩存數據的方式,以此保證其中一個系統短暫性中斷,而其它服務依舊繼續運行。

  • 提供硬化的API使用核心服務

核心服務是最好的補充公共庫,遵循最佳實踐來使用這些核心服務。例如,庫能夠提供良好的api來管理緩存或處理故障。

  • 運行的消防演習

你可能認爲可以在覈心服務中斷中生存下來,在嘗試以前,你永遠不會知道。對於這些類型的中斷,咱們不得不開發系統的消防演習,從故障注入系統應用到單個服務器中,以此手動觸發整個數據中心的中斷。

增長延遲和資源耗盡

一些故障致使服務的延遲增長到客戶端。這種增長的延遲可能不多(例如,考慮到一我的的配置錯誤,可是依舊服務的能力致使CPU使用量增長),還有就是,它多是無限的(一個服務線程服務響應陷入癱瘓)。而少許的延遲能夠很容易地解決由Facebook的基礎設施、大量的延遲會致使全面故障。幾乎全部的服務對未完成請求的數量都有限制,這個限制多是因爲每一個請求服務線程數量有限,也多是因爲基於故障服務中的內存有限。若是一個服務面臨大量的延遲,那麼調用它的服務將耗盡他們的資源。這種故障會經過許多層面進入系統服務中,致使系統故障的發生。

資源枯竭是一個極具破壞性的故障模式,因爲它容許服務請求的子集用於致使失敗的全部請求失敗。例如,一個服務調用只推出 1%的用戶對新的實驗服務,一般要求這個實驗服務須要1毫秒,但因爲在新的服務失敗的請求須要1秒,因此1%的用戶使用這項新服務請求可能會消耗太多的線程,其餘99%用戶就不能運行此線程。
現在,咱們已經發現了一些技術,能夠避免這種類型的積累與較低的誤報率。

  • 控制延遲

在分析以往的事故延遲中,咱們發現許多最糟糕的故障涉及大量隊列等待處理的請求。有問題的服務有一個資源限制(如活動線程或內存的數量)和將緩衝請求以保持低於限制使用的請求。因爲服務沒法跟上傳入請求的速度,隊列會變得愈來愈大,直到它突破了應用程序定義的限制。爲了解決這種狀況,咱們但願在不影響正常操做和保證可靠性的狀況下,來限制隊列的大小。咱們研究了一個很類似的bufferbloat,在保證可靠性的同時,使用隊列從而不會形成過分延遲。嘗試了一種codel1(延時)控制算法:

onNewRequest(req, queue):

if(queue.lastEmptyTime() < (now - N seconds)) {

timeout = M ms

} else {

timeout = N seconds;

}

queue.enqueue(req, timeout)

在該算法中,若是服務不能在最後N毫秒內清空隊列,則隊列中花費的時間僅限於M毫秒。若是服務可以在最後N毫秒內完成清空隊列,則隊列中所花費的時間僅限於N毫秒。該算法避免站在隊列(因爲lastEmptyTime將在遙遠的過去,致使anM-ms排隊超時),一次達到短期的排隊對於可靠性的目的。雖然它彷佛有悖常理,請求時間較短,這個過程容許的迅速丟棄服務,而不是創建在系統沒法跟上傳入請求的服務。短的超時可確保服務器老是處在工做的狀態,而不是空閒。

該算法的一個吸引人的特性是,M和N的值每每不須要調整。解決排隊問題的其餘方法,如在隊列中設置項目的數量或設置隊列的超時時間的限制,須要在每一個服務基礎上進行調整。咱們已經發現,M和100毫秒的值是5毫秒,它能夠很好的用於N中。Facebook的開源碼library5提供的算法是由thrift4框架實現。

  • 自適應後進先出(後進先出)

大多數服務進程隊列FIFO(先進先出)。當處於高額度處理進程中時,先進命令明顯已經運行了很長時間,以致於用戶可能已經停止了生成請求的操做。當處理先進申請命令時,相比之下這種剛剛抵達的請求命令,首先會消耗少量可能益於用戶的請求命令,服務進程請求程序使用的是應後進先出的方式。在正常工做條件下,要求按照先進先出的順序進行處理,可是當一個隊列正要開始成形時,服務器會切換爲LIFO模式,這時,LIFO和CoDel就能夠很好的結合在一塊兒,如圖2所示。CoDel超時設置時,阻止長的計算機程序隊列增加,而後具備適應性的先出後進命令在計算機程序隊列設置新的請求模式,而後在數字信號編碼器的做用下,他們兩個可以發揮最大化的做用。HHVM3,Facebook的PHP運行時,自適應後進先出法的算法得以實現。

  • 併發控制

不管是編碼和自適應的後進先出法都在服務器端運行。服務器一般是執行延遲的最好的措施——服務器更傾向於大量的客戶同時可以擁有更多的客戶信息。然而,有些故障是如此嚴重,以致於服務器端控件沒法啓動。爲此,咱們在客戶端實施一種權宜之計。每一個客戶端會跟蹤每一個服務器所未完成的出站請求數量。當發送新請求時,若是對該服務的未執行請求的數目超過可配置的數字,則該請求將當即標記爲錯誤。這種機制可防止單個服務壟斷其客戶端的資源。

以上內容是數人云今天爲你們帶來的「Facebook面對大規模系統工程故障排查實踐」的上半部分,其中主要涵蓋致使故障的緣由、以及可使用一個通用的系統等相關內容,但願能夠對你們有所幫助~明天還會爲你們帶來最終的解決方案喲,敬請期待~

做者:Ben Maurer

原文:Fail at Scale Reliability in the face of rapid change

http://queue.acm.org/detail.c...

相關文章
相關標籤/搜索