官术网_书友最值得收藏!

3.1 對失敗友好的架構與環境

我們在討論“Spotify團隊如何面對失敗”時就提到過對失敗友好的環境,這既是目標也是基礎。在進行敏捷實踐的時候,經常會提倡快速失敗,但是不是更應認真思考它的前提和基礎呢?對失敗友好的環境就是提倡快速失敗的前提和基礎,作為推行 DevOps 企業文化的支撐之一,對失敗友好的架構與環境就像汽車安全帶一樣重要,它是推行高度信任及免責的企業文化的重要支撐,因為它能在很多方面將損失降至最小。

3.1.1 對失敗友好的架構與環境的特點

對失敗友好的架構與環境在應用出現故障或者超出設計容納的限度時,依然能夠保證彈性并對服務進行優雅地降級,這里我們通過借鑒Netflix在這方面的做法來了解對失敗友好的架構與環境的特點。

2011年4月21日,整個Amazon的AWS云服務系統發生故障,導致很多運行在其上的客戶(諸如Reddit和Quora)的服務中斷,但是Netflix卻基本沒有受到影響。AWS并沒有對Netflix進行特殊對待,Netflix能夠繼續為客戶提供服務的原因在于,其在2009年對自身的架構進行了優化。

2008年,Netflix的在線視頻服務還是一個巨大的、運行在數據中心上的J2EE應用。而在2009年,為了保證該服務在Amazon AWS上具有更好的容錯性,Netflix對其進行了重構,類似Amazon服務的影響也被考慮在內,具體的舉措有3條。

● 舉措1:采用松耦合的架構,某個組件出現問題不會使得整個系統無法運行。

● 舉措2:在不同的場合提供不同的服務,如表3-1所示。

表3-1 Netflix服務場合說明

● 舉措3:為了保證發生故障的時候服務能夠自動恢復,最好的方式就是進行測試。而相較于其他測試內容,模擬生產環境服務器故障往往是非常困難的。為了進行改進,可以使用工具來模擬 AWS 出現的故障,比如可以使用工具隨機地停止生產環境的服務器,這樣做的目的是使開發團隊能夠習慣云端故障的發生,并能保證在故障發生時,服務不需要任何手工干預即可自動恢復。

彈性容錯的系統、故障發生時的降級服務等都是對失敗友好的架構與環境所具有的特點。在這樣的系統中,進行持續試驗的開發團隊自然更有自信。

3.1.2 對失敗友好的架構與環境的設計原則

通過Netflix的實踐,我們可以發現對失敗友好的架構與環境的特點及在對其進行實現過程中需要注意的一些事項,從而得到一些啟發。而構建和設計這樣的環境,則是一個長期的過程,需要考慮很多要素,如圖3-2所示。

圖3-2 設計對失敗友好的架構與環境時所需的要素

1.設計中考慮非功能性需求

在開發和設計中,那些非功能性的需求同樣非常重要。在一定程度上,后續的很多問題都是由于對這些非功能性需求的設計不夠重視而導致的。例如,架構、性能、穩定性、可偵測性、配置、安全要素等。

在開發中如果考慮到一系列的非功能性需求,則能很容易地對服務進行部署,更快地偵測到問題的發生,更重要的是能保證服務的可用性和可靠性。這些非功能性需求有:

● 彈性服務能力;

● 問題和故障發生時的服務可用性保證;

● 在應用和環境中有足夠的監控;

● 能夠精確跟蹤依賴的能力;

● 前向和后向的版本兼容性;

● 能夠檢索各個服務的日志信息的能力;

● 在多個服務中跟蹤用戶請求的能力。

正是因為 Netflix 在系統的設計上保證了彈性服務能力,考慮到了意外情況下的服務降級,才做到了在問題出現的時候從容不迫。

2.工具上使用諸如猿猴軍團(Simian Army)進行輔助

Netflix 使用了猿猴軍團工具模擬 AWS 出現的故障,這使得開發團隊習慣了云端故障的發生,并將這種故障發生的應對策略融入架構,從而營造出了對失敗友好的架構與環境,保證了在故障發生時,服務不需要任何手工干預即可自動恢復。讓我們來看一下猿猴軍團工具都能模擬哪些故障,如圖3-3所示。

圖3-3 猿猴軍團工具

● 混沌大猩猩:模擬AWS可用區的故障。

● 混沌金剛:模擬整個AWS區域(例如北美或歐洲)的故障。

● 一致性猴子:查找并關閉不符合最佳實踐的AWS實例。例如,不屬于自動擴展組的實例或沒有列出相關工程師電子郵件地址的目錄。

● 醫生猴子:對每個實例進行健康檢查,一旦發現不健康且未被及時修復的實例,就主動將其關閉。

● 看門猴子:確保云環境沒有混亂和浪費;搜索未使用的資源并顯示它們。

● 延遲猴子:在其 RESTful 客戶端/服務器的通信層中引入人為延遲或停機時間,以模擬服務降級的情況,并確保相關服務能適當地做出響應。

● 安全猴子:一致性猴子的延伸,它查找并終止具有安全違規或安全漏洞的實例。例如,未正確配置的AWS安全組。

Netflix 引入了猿猴軍團工具,使系統對于失敗更加友好,當不同級別的問題發生時,都能對服務進行優雅地降級。在這個過程中能夠模擬實際故障的猿猴軍團工具功不可沒,當然還有其他類似的工具。另外通過紅藍對戰的方式,或者使用后文(3.3.2 節)會介紹的游戲日(Game Days)都可以輔助發現并修復現行系統中的潛在問題,從而使得環境對失敗更加友好。

3.開發中通過自動化和標準化來提高效率并保證輸出

要盡可能地引入自動化操作來提升效率,避免手工作業導致的服務不穩定。當運行和維護的工作不能夠完全自動化時,目標就變成了使工作盡可能地可重復和標準化。盡可能清楚地定義手工作業以減少交付時間和錯誤,借助諸如Rundeck這樣的工具進行自動化操作,同時使用JIRA或者ServiceNow等工具管理問題和事件,可以達到更好的效果。

當我們清楚需要做什么樣的工作,由誰去執行,以及需要什么樣的步驟后,我們就可以通過在開發中創建定義清晰的運維用戶故事,更好地進行規劃以保證輸出是穩定可重復的。而只有當這些輸出穩定可重復時,整體環境的可靠性才能得到進一步的保障。

3.1.3 當失敗遇見復雜系統

復雜系統往往具有高度耦合的功能組件,難以簡單解釋的各種系統行為,以及與無數外接系統千絲萬縷的關聯,導致很難對其可能面臨的失敗進行精確的預測。而一旦發生故障(失敗),其影響往往非常大。比如,核電站就是這樣復雜的系統,當復雜系統發生故障(失敗)時,保證對失敗友好顯然不是一件容易的事情。核電站故障事件及其影響如表3-2所示。

表3-2 核電站故障事件及其影響

而在科技領域,工作依賴由多個超級復雜的系統,同樣也可能遭遇極高的風險。例如,2015年紐約證券交易所的系統曾經暫停交易218分鐘,如表3-3所示。

表3-3 2015年紐約證券交易所交易系統故障

對于紐約證券交易所的交易系統停止的218分鐘,損失巨大。其實,類似的情況并不罕見,巨型系統的復雜性已經遠遠超出了我們的想象,而且一旦發生問題,將會是災難性的。

像核反應堆這樣復雜的系統,其可能出現的故障難道不能被準確預測嗎?Charles Perrow博士通過對三里島危機進行研究發現,準確預測在各種情況下核反應堆可能的反應,以及何時發生故障近乎不可能。當某一個部分的問題正在發生的時候,很難將其和其他部分分開,快速的變化使得結果變得異常復雜,而預測也近乎不可能。Sidney Dekker博士通過研究發現,復雜系統的另外一個特性,兩次同樣的執行并不一定導致相同的結果。這顯然是幾乎令人絕望的特性和結論。對于復雜系統的安全,需要引入監控來予以保障。

3.1.4 保障復雜系統的安全

在復雜系統中,問題(失敗,下同)的發生是不可避免的,同時又是無法準確預測的。在這種情況下,我們所能做的是創建一種安全的機制,使問題能夠快速被檢測到,從而在出現災難性后果之前開始著手應對。這樣的機制使得我們對失敗不再畏懼,同時有可能改變文化的土壤。

而在制造業領域,嚴重問題剛發生時,很多現象都會被檢測到。更早發現,更早應對,成本更低,速度更快,代價更低,這是我們從制造業經驗中學到的。我們也會將其應用到DevOps的實踐當中,發現和反饋問題的回路非常重要,在發現和反饋的實踐中,更重要的是將每次問題發生都視作一次學習的機會,而不是責備和懲罰。當然,這是需要前提的,我們需要確保我們的系統運作是安全的,這些問題的發生不會導致災難性的后果。

在制造業中,缺少有效的反饋經常會導致出現質量和安全問題。在制造業的價值鏈中,快速、高頻度、高質量的信息流動隨處可見,每個工序都需要被測量和監控,任何故障或可能引起偏離的問題都會很快地被發現和糾正,正是這些奠定了創建高質量安全系統的基礎。

而在軟件開發領域,這種在制造業中習以為常的反饋并不易得。例如,在傳統的“瀑布型軟件開發”中,往往在設計和編碼工作基本完成之后,才能從測試階段得到關于質量的反饋,甚至有一部分只有在發布之后才能得到反饋,而這一切都已經太晚,并且往往已經產生了非常嚴重的影響。我們所期待的是,在軟件開發領域也能創建出制造業中的機制為我們保駕護航。

當然,僅僅通過反饋回路檢測到預期外的問題發生還遠遠不夠,我們還需要解決這些問題。讓我們再次將目光投向制造業,當問題發生的時候,團隊負責人會立即被通知到并開始著手去解決問題。若這個問題在一定的時間內(如55秒內)沒有得到解決,整條生產線會停下來去協同解決,直到問題得到解決。這就是2.4.5小節所提到的安燈拉繩的實踐活動。

雖然看起來很簡單,但是往往在最初的階段需要決心和勇氣。《鳳凰項目》一書中所提到的部署凍結,其實就是學習制造業的做法,不讓問題繼續擴散,在問題的初期進行應對效果更好。發現核反應堆已經開始熔化再去應對明顯為時已晚。所以只有在整個流動的過程中盡可能早地發現小的問題,并立即解決,我們才有可能創建一種安全的機制,保證在災難性的后果發生之前有足夠時間去應對。

主站蜘蛛池模板: 贵阳市| 确山县| 法库县| 海伦市| 衡山县| 阿图什市| 云和县| 兴业县| 祁连县| 东台市| 青浦区| 滨海县| 伊金霍洛旗| 洛浦县| 蒲城县| 常宁市| 阳春市| 长沙县| 永春县| 怀远县| 奈曼旗| 裕民县| 县级市| 金阳县| 上饶县| 定安县| 涿州市| 扶风县| 马关县| 界首市| 运城市| 资兴市| 城步| 句容市| 榆林市| 兴安盟| 沅江市| 儋州市| 台湾省| 祥云县| 蕉岭县|