您好,歡迎來(lái)電子發(fā)燒友網(wǎng)! ,新用戶?[免費(fèi)注冊(cè)]

您的位置:電子發(fā)燒友網(wǎng)>源碼下載>數(shù)值算法/人工智能>

服務(wù)器架構(gòu)設(shè)計(jì)如何規(guī)避故障

大小:0.4 MB 人氣: 2017-09-27 需要積分:1

  微服務(wù)架構(gòu)通過(guò)定義明確的服務(wù)邊界,能有效地隔離故障。 和其他分布式系統(tǒng)一樣,微服務(wù)在網(wǎng)絡(luò)、硬件和應(yīng)用層上都會(huì)存在更多的問(wèn)題。*由于服務(wù)之間是互相依賴,因此任何組件都可能出錯(cuò)導(dǎo)致用戶不能訪問(wèn)。為盡可能減少部分中斷帶來(lái)的影響,我們需要構(gòu)建容錯(cuò)能力強(qiáng)的服務(wù),以從容*應(yīng)對(duì)發(fā)生的某些中斷。

  本文在RisingStack’s Node.js Consulting & Development experience一文基礎(chǔ)上,介紹了構(gòu)建和運(yùn)維高可用的微服務(wù)架構(gòu)系統(tǒng)中最常用的技術(shù)和架構(gòu)模式。

  如果讀者不熟悉上文中的模式,那并沒(méi)什么大礙。構(gòu)建可靠的系統(tǒng)不是一踞而就的。

  微服務(wù)架構(gòu)的風(fēng)險(xiǎn)

  微服務(wù)架構(gòu)將應(yīng)用邏輯拆分成服務(wù),服務(wù)之間通過(guò)網(wǎng)絡(luò)交互。由于是通過(guò)網(wǎng)絡(luò)調(diào)用,而不是在進(jìn)程中調(diào)用,因此這給需要在多個(gè)物理和邏輯組件間進(jìn)行協(xié)作的系統(tǒng)帶來(lái)了潛在的問(wèn)題和復(fù)雜性。分布式系統(tǒng)變得越來(lái)越復(fù)雜,也導(dǎo)致網(wǎng)絡(luò)特定故障發(fā)生的可能性增大。

  相比傳統(tǒng)應(yīng)用龐大的結(jié)構(gòu),微服務(wù)架構(gòu)最大的一個(gè)優(yōu)點(diǎn)是團(tuán)隊(duì)能獨(dú)立地設(shè)計(jì)、開(kāi)發(fā)和部署各自的服務(wù)。團(tuán)隊(duì)能掌控各自服務(wù)的整個(gè)生命周期。這也意味者團(tuán)隊(duì)無(wú)法控制服務(wù)的依賴關(guān)系,因?yàn)檫@些依賴的服務(wù)可能是由其他團(tuán)隊(duì)管理。在微服務(wù)架構(gòu)體系下,我們要牢記提供的服務(wù)由于是其他人控制,因此可能會(huì)由于發(fā)布、配置、和其他變更等原因,從而導(dǎo)致服務(wù)暫時(shí)不可用,而且組件之間互相獨(dú)立。

  優(yōu)雅的服務(wù)降級(jí)

  微服務(wù)架構(gòu)最大的優(yōu)點(diǎn)之一就是當(dāng)組件出現(xiàn)故障時(shí),能隔離這些故障并且能做到優(yōu)雅地服務(wù)降級(jí)。比如,在圖片分享應(yīng)用中,當(dāng)出現(xiàn)故障時(shí),用戶可能無(wú)法上傳圖片,但他們依然能瀏覽、編輯和分享已上傳的圖片。

  服務(wù)器架構(gòu)設(shè)計(jì)如何規(guī)避故障

  微服務(wù)故障獨(dú)立(理論上)

  在大多數(shù)情況下,是很難實(shí)現(xiàn)上圖這種優(yōu)雅地服務(wù)降級(jí)的,因?yàn)樵诜植际江h(huán)境下,應(yīng)用都是互相依賴的,開(kāi)發(fā)者需要實(shí)現(xiàn)若干錯(cuò)誤處理的邏輯(該部分在本文稍后部分討論)去應(yīng)對(duì)短暫的故障和中斷。

  服務(wù)器架構(gòu)設(shè)計(jì)如何規(guī)避故障

  服務(wù)互相依賴,如果無(wú)故障轉(zhuǎn)移的邏輯,則會(huì)同時(shí)失效

  變更管理

  Google的網(wǎng)站可靠性團(tuán)隊(duì)發(fā)現(xiàn)大概70%的故障都是由于變更而引起的。當(dāng)對(duì)服務(wù)進(jìn)行修改時(shí)—例如發(fā)布代碼的新版本或者改變一些配置,則總會(huì)有可能引起故障或者引入新的錯(cuò)誤。

  在微服務(wù)架構(gòu)中,服務(wù)是互相依賴的。這就是為什么你需要減少故障并且盡可能降低它們的負(fù)面影響。為了應(yīng)對(duì)變更帶來(lái)的問(wèn)題,你可以實(shí)施變更策略管理并且實(shí)現(xiàn)其自動(dòng)回滾。

  比如,當(dāng)部署新的代碼或者修改配置時(shí),應(yīng)該分步將這些變更部署到服務(wù)實(shí)例群中的部分實(shí)例中,并且進(jìn)行監(jiān)控,如果發(fā)現(xiàn)關(guān)鍵指標(biāo)出現(xiàn)問(wèn)題則能自動(dòng)進(jìn)行回滾。

  服務(wù)器架構(gòu)設(shè)計(jì)如何規(guī)避故障

  變更管理-回滾部署

  另一個(gè)解決方案是運(yùn)行兩套生產(chǎn)環(huán)境。部署的時(shí)候只部署變更的應(yīng)用到其中一套環(huán)境中,并且在驗(yàn)證了新發(fā)布的版本符合預(yù)期后,才將負(fù)責(zé)均衡的流量指向新的應(yīng)用,這種方法稱為“藍(lán)-綠發(fā)布”或者“紅-黑發(fā)布”。

  回退代碼并不是壞事情。你不應(yīng)該在生產(chǎn)環(huán)境中部署有問(wèn)題的代碼,并且應(yīng)該琢磨哪里出錯(cuò)了。當(dāng)必要時(shí)候應(yīng)該果斷回退代碼,這越早越好。

  健康檢查和負(fù)載均衡

  因?yàn)楣收匣虿渴?、自?dòng)擴(kuò)展等原因,服務(wù)實(shí)例會(huì)不停啟動(dòng),重新啟動(dòng)及停止。這使得服務(wù)暫時(shí)或一直停用。為了避免發(fā)生這些問(wèn)題,在負(fù)載均衡中應(yīng)該在路由中設(shè)置忽略這些實(shí)例,因?yàn)樗鼈儫o(wú)法為子系統(tǒng)或用戶提供服務(wù)。

  我們可以通過(guò)外部觀察去判斷應(yīng)用實(shí)例是否健康。你可以多次調(diào)用

  Get /health的端點(diǎn)(endpoint)或者通過(guò)自身服務(wù)的報(bào)告獲得相關(guān)信息?,F(xiàn)在的

  服務(wù)發(fā)現(xiàn)解決方案會(huì)持續(xù)從實(shí)例中收集健康信息,并且設(shè)置負(fù)載均衡的路由,讓其只指向健康的實(shí)例組件。

  自我修復(fù)

  自我修復(fù)能幫助恢復(fù)應(yīng)用。我們討論下當(dāng)應(yīng)用遇到崩潰狀態(tài)后,如何通過(guò)相關(guān)的步驟去自我修復(fù)。在大多數(shù)情況下,是通過(guò)外部系統(tǒng)監(jiān)控實(shí)例的狀態(tài),當(dāng)服務(wù)出現(xiàn)故障一段時(shí)間后則會(huì)重啟服務(wù)。在大多數(shù)情況下,自我修復(fù)的功能是相當(dāng)有用的,然而,在某些情況下由于不斷地重啟服務(wù)會(huì)帶來(lái)相關(guān)的問(wèn)題。例如當(dāng)服務(wù)過(guò)載或者數(shù)據(jù)庫(kù)連接超時(shí),則會(huì)導(dǎo)致應(yīng)用不能反饋正確的服務(wù)健康狀態(tài)。

  對(duì)于一些場(chǎng)景-比如數(shù)據(jù)庫(kù)鏈接丟失,這個(gè)時(shí)候?qū)崿F(xiàn)高級(jí)的自我修復(fù)功能是頗為棘手的。在這種情況下,需要為應(yīng)用添加額外的邏輯去處理這些特例,并且讓外部系統(tǒng)知道服務(wù)的實(shí)例不需要立即重新啟動(dòng)。

  故障轉(zhuǎn)移緩存(Failover Caching)

  因?yàn)榫W(wǎng)絡(luò)問(wèn)題和系統(tǒng)中的變更,服務(wù)通常會(huì)出現(xiàn)故障。然而,這些故障中斷大多是暫時(shí)的,這要?dú)w功于自我修復(fù)和高級(jí)負(fù)載平衡的功能,我們應(yīng)該找到一個(gè)解決方案,能使服務(wù)即使在出現(xiàn)故障的時(shí)候也能工作。這就是故障轉(zhuǎn)移緩存(Failover Caching),它能幫助為我們的應(yīng)用提供必需的數(shù)據(jù)。

  失效轉(zhuǎn)移緩存通常使用兩個(gè)不同的過(guò)期日期:其中更短的日期指示在正常情況下能使用緩存的時(shí)間,而更長(zhǎng)的一個(gè)日期則指示在故障失效的時(shí)候,能使用緩存中的數(shù)據(jù)時(shí)長(zhǎng)。

  故障轉(zhuǎn)移緩存

  特別需要提醒的是,只有當(dāng)提供過(guò)時(shí)的數(shù)據(jù)比沒(méi)有數(shù)據(jù)更好的情況下,才能使用故障轉(zhuǎn)移緩存。

  要設(shè)置緩存和故障轉(zhuǎn)移緩存,可以在HTTP中使用標(biāo)準(zhǔn)響應(yīng)頭。

  例如,使用max-age頭可以指定某個(gè)資源為新資源的最大時(shí)間(譯者注:意即設(shè)定max-age后,瀏覽器不再發(fā)送請(qǐng)求到服務(wù)器)??梢允褂胹tale-if-error 頭去確定在出現(xiàn)故障的情況下,從緩存獲取資源的時(shí)間長(zhǎng)短。

  現(xiàn)在的CDN和負(fù)載均衡器提供了各種緩存和故障轉(zhuǎn)移的解決方案,但是你也可以在你的公司中建立一個(gè)共享庫(kù),其中包括這些標(biāo)準(zhǔn)的可靠性解決方案。

  重試邏輯(Retry Logic

  在某些情況下,我們可能無(wú)法緩存數(shù)據(jù),或者想對(duì)數(shù)據(jù)進(jìn)行變更,但是操作最終失敗了。在這種情況下,我們就可以選擇重試操作,因?yàn)槲覀兛梢灶A(yù)期資源將在一段時(shí)間后恢復(fù),或者負(fù)載均衡會(huì)將請(qǐng)求發(fā)送到健康的實(shí)例上。

  你應(yīng)該小心地為應(yīng)用程序和客戶端添加重試邏輯,因?yàn)楦罅康闹卦嚥僮骺赡軙?huì)使事情變得更糟,甚至阻止應(yīng)用程序恢復(fù)。

  在分布式系統(tǒng)中,微服務(wù)系統(tǒng)重試可能會(huì)觸發(fā)多個(gè)其他請(qǐng)求或重試操作,并導(dǎo)致級(jí)聯(lián)效應(yīng)。為減少重試帶來(lái)的影響,你應(yīng)該減少重試的數(shù)量,并使用指數(shù)退避算法(exponential backoff algorithm)來(lái)持續(xù)增加重試之間的延遲時(shí)間,直到達(dá)到最大限制。

  由于重試是由客戶端(瀏覽器,其他微服務(wù)等)發(fā)起的,并且客戶端在處理請(qǐng)求前后是不知道草走失敗的,你應(yīng)該為你的應(yīng)用程序提供冪等處理能力。例如,當(dāng)你重試購(gòu)買操作時(shí),不應(yīng)該向客戶收兩次錢。給每個(gè)事務(wù)使用唯一的冪等鍵(idempotency-key)是解決重試問(wèn)題的方法。

  限流器和負(fù)載開(kāi)關(guān)(Rate Limiters and Load Shedders)

  限流是指在一段時(shí)間內(nèi),定義某個(gè)客戶或應(yīng)用可以接收或處理多少個(gè)請(qǐng)求的技術(shù)。例如,通過(guò)限流,你可以過(guò)濾掉產(chǎn)生流量峰值的客戶和微服務(wù),或者可以確保你的應(yīng)用程序在自動(dòng)擴(kuò)展(Auto Scaling)失效前都不會(huì)出現(xiàn)過(guò)載的情況。

  你還可以阻止較低優(yōu)先級(jí)的流量,以便為關(guān)鍵事務(wù)提供足夠的資源。

  服務(wù)器架構(gòu)設(shè)計(jì)如何規(guī)避故障

  限流器可以阻止流量峰值

  另外有一種限流器,稱為 “并發(fā)請(qǐng)求限流器(concurrent request limiter)”。當(dāng)你有一些比較昂貴和重要的端點(diǎn)(endpoint),希望它不應(yīng)該被調(diào)用超過(guò)指定的次數(shù),但仍然想要提供流量服務(wù)時(shí),這個(gè)限流器就十分有用了。

  使用負(fù)載開(kāi)關(guān)可以確保對(duì)于關(guān)鍵的事務(wù)總能提供足夠的資源保障。它為高優(yōu)先級(jí)的請(qǐng)求保留一些資源,并且不允許低優(yōu)先級(jí)的事務(wù)去占用這些資源。負(fù)載開(kāi)關(guān)會(huì)根據(jù)系統(tǒng)的整體狀態(tài)做出決定,而不是基于單個(gè)用戶的請(qǐng)求桶(request bucket)大小。負(fù)載設(shè)備有助于你的系統(tǒng)恢復(fù),因?yàn)樗鼈冊(cè)诔掷m(xù)發(fā)生故障事件時(shí),依然能保持核心功能正常工作。

  關(guān)于更多限流器和負(fù)載開(kāi)關(guān)的知識(shí),建議讀者參考Stripe

  快速且單獨(dú)失效(Fail Fast and Independently)

  在微服務(wù)體系架構(gòu)中,我們希望服務(wù)可以快速、單獨(dú)地失效。為了在服務(wù)層面隔離故障,我們可以使用隔板模式(bulkhead pattern)??梢栽诒疚纳院罂吹较嚓P(guān)介紹。

  我們也希望我們的組件能夠快速失效(fail fast),因?yàn)槲覀儾幌M鹊綌嚅_(kāi)的實(shí)例直到超時(shí)。沒(méi)有什么比掛起的請(qǐng)求和無(wú)響應(yīng)的界面更令人失望。這不僅浪費(fèi)資源,而且還會(huì)讓用戶體驗(yàn)變得更差。我們的服務(wù)是互相調(diào)用的,所以在這些延遲疊加前,應(yīng)該特別注意防止那些超時(shí)的操作。

  你想到的第一個(gè)辦法,可能是對(duì)每個(gè)服務(wù)的調(diào)用都定義超時(shí)的級(jí)別。這種做法的問(wèn)題是,你不能真正知道到底什么是恰當(dāng)?shù)某瑫r(shí)值,因?yàn)楫?dāng)網(wǎng)絡(luò)故障和其他問(wèn)題發(fā)生時(shí),某些情況下只會(huì)影響一兩次操作。在這種情況下,如果只有其中一些發(fā)生超時(shí),你可能不想拒絕所有這些請(qǐng)求。

  我們可以說(shuō),通過(guò)使用超時(shí)(timeout)來(lái)實(shí)現(xiàn)微服務(wù)中的快速失敗是一種反模式,這是應(yīng)該避免的??梢允褂没诓僮鞯某晒?失敗統(tǒng)計(jì)次數(shù)的熔斷模式,而不是使用超時(shí)。

  艙壁模式(Bulkheads)

  在工業(yè)領(lǐng)域中,常使用艙壁將船劃分為幾個(gè)部分,以便在有某部分船體發(fā)生破裂時(shí),其他部分依然能密封安然無(wú)恙。

  艙壁的概念也可以在軟件開(kāi)發(fā)中用于隔離資源。

  通過(guò)使用艙壁模式,我們可以保護(hù)有限的資源不被用盡。例如,如果我們有兩種類型的操作的話,它們都是和同一個(gè)數(shù)據(jù)庫(kù)實(shí)例進(jìn)行通信,并且數(shù)據(jù)據(jù)庫(kù)限制連接數(shù),這時(shí)我們可以使用兩個(gè)連接池而不是使用一個(gè)共享的連接池。由于這種客戶端和資源分離,超時(shí)或過(guò)度使用池的操作不會(huì)令所有其他操作失效。

  泰坦尼克號(hào)沉沒(méi)的主要原因之一是其艙壁設(shè)計(jì)失敗,水可以通過(guò)上面的甲板倒在艙壁的頂部,最后整個(gè)船淹沒(méi)。

  服務(wù)器架構(gòu)設(shè)計(jì)如何規(guī)避故障

  泰坦尼克號(hào)故障的艙壁

  斷路器(Circuit Breakers)

  為了限制操作的持續(xù)時(shí)間,我們可以使用超時(shí)。超時(shí)可以防止掛起操作并保證系統(tǒng)可以響應(yīng)。然而,在微服務(wù)架構(gòu)通信中使用靜態(tài)、微調(diào)的超時(shí)是一種反模式,因?yàn)槲覀兲幱诟叨葎?dòng)態(tài)的環(huán)境中,幾乎不可能確定在每種情況下都能正常工作的準(zhǔn)確的時(shí)間限制。

  我們可以使用斷路器來(lái)處理錯(cuò)誤,而不是使用小型和特定基于事務(wù)的靜態(tài)超時(shí)機(jī)制。斷路器以現(xiàn)實(shí)世界的電子元件命名,因?yàn)樗鼈兊男袨槭嵌际窍嗤?。你可以保護(hù)資源,并通過(guò)使用斷路器協(xié)助它們進(jìn)行恢復(fù)。斷路器在分布式系統(tǒng)中非常有用,因?yàn)橹貜?fù)的故障可能會(huì)導(dǎo)致雪球效應(yīng),并使整個(gè)系統(tǒng)崩潰。

  當(dāng)在短時(shí)間內(nèi)多次發(fā)生指定類型的錯(cuò)誤時(shí),斷路器會(huì)開(kāi)啟。開(kāi)啟的斷路器可以拒絕接下來(lái)更多的請(qǐng)求 – 就像防止真實(shí)的電子流動(dòng)一樣。斷路器通常在一定時(shí)間后關(guān)閉,以便為底層服務(wù)提供足夠的空間來(lái)恢復(fù)。

  請(qǐng)記住,并不是所有的錯(cuò)誤都應(yīng)該觸發(fā)斷路器。例如,你可能希望忽略客戶端問(wèn)題,比如4xx響應(yīng)代碼的請(qǐng)求,但要包括5xx服務(wù)器端故障。一些斷路器還可以有半開(kāi)關(guān)狀態(tài)。在這種狀態(tài)下,服務(wù)發(fā)送第一個(gè)請(qǐng)求以檢查系統(tǒng)的可用性,同時(shí)讓其他請(qǐng)求失敗。如果這個(gè)第一個(gè)請(qǐng)求成功,則將斷路器恢復(fù)到關(guān)閉狀態(tài)并繼續(xù)接受流量。否則,保持打開(kāi)狀態(tài)。

  服務(wù)器架構(gòu)設(shè)計(jì)如何規(guī)避故障

  斷路器

  故障測(cè)試(Testing for Failures)

  你應(yīng)該持續(xù)地測(cè)試系統(tǒng)的常見(jiàn)問(wèn)題,以確保你的服務(wù)可在各類故障環(huán)境下運(yùn)行。你應(yīng)經(jīng)常測(cè)試故障,以讓你的團(tuán)隊(duì)對(duì)可能發(fā)生的事故有所準(zhǔn)備。

  關(guān)于測(cè)試,你可以使用外部服務(wù)來(lái)識(shí)別服務(wù)實(shí)例組,并隨機(jī)終止運(yùn)行組中的一個(gè)實(shí)例。通過(guò)使用這個(gè)方法,可以針對(duì)單個(gè)實(shí)例故障進(jìn)行測(cè)試,你甚至可以關(guān)閉整個(gè)服務(wù)組來(lái)模擬云提供商層面的故障中斷。

  最流行的測(cè)試解決方案之一是Netflix的ChaosMonkey工具。

  總結(jié) 實(shí)施和運(yùn)維可靠的服務(wù)并不容易。這需要你付出很多努力,還要花費(fèi)公司更多的成本。

  可靠性有很多層次和方面,因此針對(duì)你的團(tuán)隊(duì)找出合適的解決方案是相當(dāng)重要的。你應(yīng)該將可靠性成為業(yè)務(wù)決策流程中的一個(gè)因素,并為此分配足夠的預(yù)算和時(shí)間。

  要點(diǎn)

  動(dòng)態(tài)環(huán)境和分布式系統(tǒng)-如微服務(wù)將導(dǎo)致更高的故障機(jī)會(huì)。

  服務(wù)應(yīng)單獨(dú)失效,實(shí)現(xiàn)優(yōu)雅的服務(wù)降級(jí)以提升用戶體驗(yàn)。

  70%的問(wèn)題是由變更引起的,恢復(fù)可用代碼并不總是壞事。

  快速,單獨(dú)地失敗。團(tuán)隊(duì)無(wú)法控制其服務(wù)依賴關(guān)系。

  架構(gòu)模式和技術(shù),如緩存、隔離技術(shù)、斷路器和限流器有助于構(gòu)建可靠的微服務(wù)。

非常好我支持^.^

(0) 0%

不好我反對(duì)

(0) 0%

      發(fā)表評(píng)論

      用戶評(píng)論
      評(píng)價(jià):好評(píng)中評(píng)差評(píng)

      發(fā)表評(píng)論,獲取積分! 請(qǐng)遵守相關(guān)規(guī)定!

      ?