如何利用Spring Cloud構建起自我修復型分佈式系統

利用Netflix所打造的組件及各種你們熟知的工具,咱們徹底能夠順利應對由微服務以及分佈式計算所帶來的技術挑戰。算法

在過去一年當中,微服務已經成爲軟件架構領域一個煊赫一時的新名詞,並且咱們也能輕鬆舉出由其帶來的諸多比較優點。然而,咱們必須清醒意識到的是,一旦開始遵循微服務思路而對現有架構體系進行拆分,就意味着咱們將不可避免地進入分佈式系統領域。在以前的文章中咱們曾經探討過度布式計算的八大認識誤區*,因而可知此類系統自己充滿着風險,並且一旦犯下這八種錯誤中的任何一種、咱們都將面對災難性的後果。spring

在我我的看來,若是要將這些誤區總結成一句觀點,那就是:對於一套分佈式系統來講,任何關於一致性或者可靠性的表達都毫無保障可言。咱們須要假定系統當中的各類行爲以及組件位置始終處於不斷變化狀態。由此產生的後果主要有兩點:組件有時候會致使糟糕的服務質量甚至令服務直接離線,咱們則只能將其統稱爲「故障」、而很難具體闡明究竟是哪裏出了問題。一旦沒能獲得妥善處理,此類故障將引中斷與停機,這意味着系統將沒法按照既定設計方案爲用戶提供服務項目。編程

有鑑於此,爲了享受微服務所帶來的諸多優點(包括鬆散耦合、自治服務、分散化治理以及易於持續交付等等),咱們必須避免由單一故障依次遞進而最終致使系統崩潰的恐怖情況。關於這一點,Erlang語言之父Joe Armstrong曾經在題爲《如何構建永遠運行、自我修復且可擴展的系統》一文中做出過透徹的表述。在他看來,此類系統看起來與咱們所說的微服務架構很是相近,但其着重強調的是其做爲自我修復系統的容錯能力。那麼對咱們來講,如何才能創建起這樣一套堅實可靠的系統方案?後端

Netflix公司在微服務架構的實施與推進方面一直扮演着先行者的角色。做爲其業務構建的原則性方針之一,Netflix公司認爲系統方案必需要可以承受任意組件的突發性故障,而總體系統仍能繼續正常運轉(這意味着咱們仍然可以在該平臺上觀看電影,而Netflix也能夠繼續記錄用戶的觀看喜愛)。在嘗試創建這樣一套系統時,咱們遭遇到如下這些常見的技術挑戰:跨域

  • 因爲須要將系統拆分紅多個分佈式進程,咱們要如何在保證一致性與可靠性的前提下將這些配置分發至這些進程當中?
  • 當這些配置方案須要加以修改時,咱們該如何在無需從新部署所有進程的前提下對配置內容進行更新?
  • 在這樣一套系統當中,特別是對於部署於雲環境內的系統,各個進程不只內容常常變更、所在位置亦會不斷轉換(特別是在進行故障轉移的狀況下)。咱們要如何準確判斷那些須要進行協同的進程的具體位置?
  • 一旦咱們檢測到了當前進程關聯性的幾種可能位置,咱們該如何選擇接下來要進行通訊的進程實例?
  • 假設在選定一個進程實例並與該實例進行通訊的過程中該實例出現了故障,咱們該如何防止由此引起的連鎖故障?
  • 在系統綜合運做行爲不斷給自治服務帶來演進拓撲結構的狀況下,咱們要如何對其狀態保持可視化監控、從而做出有針對性的準確調整?

事實上,你們能夠部署多種樣板模式及開源工具來解決上述技術挑戰。Netflix公司就構建出多種組件且加以開源,並在生產環境中進行了一系列測試。從理論角度講,咱們可以利用這些工具來創建起有能力「永遠運行、自我修復且實現規模化擴展」的系統。對剛剛着手創建分佈式系統的朋友們來講,咱們目前的第一要務在於理解這些實現模式、掌握Netflix組件並加以應用,然後將這些組件部署、管理並集成至本身的系統當中。因爲採起任何新的技術依賴關係都會給軟件工程方案帶來前所未見的複雜性元素,所以咱們建議你們最好直接採用Netflix的堆棧來儘量減小此類潛在摩擦。安全

Spring工程技術團隊從創建之初至今一直在努力打造出足以應對Java複雜性的強大武器。咱們的早期關注重點在於消除J2EE給企業級應用程序開發者帶來的生產效率影響。而着眼於最近一段時間,咱們的主要精力則轉移到了實現雲-本地應用程序構建身上,並且這方面的大部分工做成果都被歸入或者圍繞着Spring Cloud項目所展開。bash

Spring Cloud項目的既定目標在於爲Spring開發人員提供一整套易於使用的工具集,從而保證其輕鬆構建起本身須要的分佈式系統方案。爲了實現這一目標,Spring Cloud以Netflix OSS堆棧爲基礎將大量實現堆棧加以整合並打包。這些堆棧然後能夠經過你們所熟知的各種基於註釋的配置工具、Java配置工具以及基於模板的編程工具實現交付。下面就讓咱們一塊兒瞭解Spring Cloud當中的幾類常見組件。服務器

Spring Cloud Config Server網絡

Spring Cloud Config Server可以提供一項具有橫向擴展能力的集中式配置服務。它所使用的數據被保存在一套可插拔庫層當中,後者目前可以支持本地存儲、Git以及Subversion。經過利用一套版本控制系統做爲配置存儲方案,開發人員可以輕鬆實現版本與審計配置的內容調整。架構

如何利用Spring Cloud構建起自我修復型分佈式系統

圖一:Spring Cloud Config Server

配置內容會以Java屬性或者YAML文件的形式體現。該Config Server會將這些文件合併爲環境對象,其中包含易於理解的Spring屬性模型以及做爲REST API存在的配置文件。任何應用程序都可以直接調用該REST API當中所包含的配置數據,但咱們也能夠將智能客戶端綁定方案添加到Spring Boot應用程序當中,並由後者自動將接收自Config Server的配置信息分配至任意本地配置當中。

Spring Cloud Bus

Spring Cloud Config Server是一套強大的配置分發機制,可以在保障一致性的前提下將配置內容分發到多個應用程序實例當中。然而根據其設計思路的限定,咱們目前只能在應用程序啓動時對其配置進行更新。在向Git中的某一屬性發送新值時,咱們須要以手動方式重啓每一個應用程序進程,從而保證該值被切實歸入應用當中。很明顯,你們須要可以在無需重啓的前提下完成對應用程序配置內容的更新工做。

如何利用Spring Cloud構建起自我修復型分佈式系統

圖二: 配備Spring Cloud Bus的Spring Cloud Config Server

Spring Cloud Bus的任務正是爲應用程序實例添加一套管理背板。它目前依靠將一套客戶端綁定至一組AMQP交換與隊列當中來實現,但這一後端在設計上也實現了可插拔特性。Spring Cloud Bus爲咱們的應用程序帶來了更多管理端點。在圖二中,咱們能夠看到一個面向greeting屬性的值被髮送至Git當中,然後一條請求被髮送至應用A中的/bus/refresh端點。該請求會觸發如下三個事件:

  1. 應用A從Config Server處請求獲取最新版本的配置內容。任意註明了@RefreshScope的Spring Bean都會被從新初始化並載入新的配置內容。
  2. 應用A向AMQP交換機制發送一條消息,代表其已經收到更新指示。
  3. 經過監聽AMQP隊列而被歸入Cloud Bus的應用B與應用C會獲取到上述消息,並以與應用A一樣的方式實現配置更新。

如今咱們已經有能力在無需重啓的狀況下對應用程序配置進行更新了。

Spring Cloud Netflix

Spring Cloud Netflix針對多種Netflix組件提供打包方案,其中包括Eureka、Ribbon、Hystrix以及Zuul。接下來我將分別對它們做出講解。

Eureka是一套彈性服務註冊實現方案。其中服務註冊屬於服務發現模式的一種實現機制(如圖三所示)。

如何利用Spring Cloud構建起自我修復型分佈式系統

圖三:利用服務註冊實現服務發現

Spring Cloud Netflix經過直接將spring-cloud-starter-eureka-server關聯性添加到Spring Boot應用程序、隨後將該應用程序的配置類與@EnableEurekaServer相整合的方式病嵌入式Eureka服務器的部署工做。

應用程序可以經過添加spring-cloud-starter-eureka關聯性並將其配置類與@EnableDiscoveryClient相整合的方式加入到服務發現流程當中。經過整合,咱們可以將通過配置的適合DiscoveryClient實例注入至任意Spring Bean內。在咱們所列舉的實例中,DiscoveryClient做爲服務發現的一種抽象機制剛好能夠經過Eureka實現,不過你們也能夠將其與Consul等其它備選堆棧相集成。DiscoveryClient可以經過服務的邏輯標識符提供位置信息(例如網絡地址)以及其它與已註冊至Eureka的服務實例相關的元數據。

Eureka提供的負載均衡機制僅支持單循環條件。而Ribbon提供的客戶端IPC庫則更爲精巧,其同時具有可配置負載均衡機制與故障容錯能力。Ribbon可以經過獲取自Eureka服務器的動態服務器列表進行內容填充。Spring Cloud Netflix經過將spring-cloud-starter-ribbon關聯性添加至Spring Boot應用程序的方式實現與Ribbon的集成。這套額外庫容許用戶將通過適當配置的LoadBalancerClient實例注入至Spring Bean當中,從而實現客戶端負載均衡(如圖四所示)。

如何利用Spring Cloud構建起自我修復型分佈式系統

圖四:使用客戶端負載均衡機制

在此類任務當中,咱們能夠利用Ribbon實現額外負載均衡算法,包括可用性過濾、加權響應時間以及可用域親和等。

Spring Cloud Netflix還經過自動建立可以被注入至任意Spring Bean的Ribbon強化型RestTemplate實例的方式進一步改進了Spring開發者的Ribbon使用方式。在此以後,開發人員可以輕鬆將URL所提供的邏輯服務名稱遞交至RestTemplate:

@Autowired
@LoadBalanced
private RestTemplate restTemplate;
@RequestMapping(「/」)
public String consume() {
ProducerResponse response = restTemplate.getForObject(「http://producer」, ProducerResponse.class);
return String.format(「{\」value\」: %s}」, response.getValue());
}複製代碼

Hystrix可以爲斷路器以及密閉閘門等分佈式系統提供一套通用型故障容錯實現模式。斷路器一般會被做爲一臺狀態機使用,具體如圖五所示。

如何利用Spring Cloud構建起自我修復型分佈式系統

圖五:斷路器狀態機

斷路器可以介於服務及其遠程關聯性之間。若是該電路處於閉合狀態,則全部指向該關聯性的調用一般將直接經過。若是某一調用失敗,則故障將被計入計數。而一旦失敗次數達到可配置時間區間內的閾值,該電路將被跳閘至斷開。在處於斷開狀態時,調用將再也不被髮往該關聯,而由此產生的結果將可自行定製(包括報告異常、返回虛假數據或者調用其它關聯等等)。

該狀態機會按期進入所謂「半開」狀態,旨在檢測關聯性是否處於健康運做狀態。在這種狀態下,請求通常仍將繼續得以經過。當請求成功經過時,該設備會從新迴歸閉合狀態。而若是請求失敗,則該設備會從新迴歸斷開狀態。

Spring Cloud應用程序可以經過添加spring-cloud-starter-hystrix關聯性並將其配置類與@EnableCircuitBreaker相整合的方式利用Hystrix。在此以後,你們能夠經過與@HystrixCommand整合的方式將斷路器機制歸入到任意Spring Bean方法內:

@HystrixCommand(fallbackMethod = 「getProducerFallback」)
public ProducerResponse getValue() {
return restTemplate.getForObject(「http://producer」, ProducerResponse.class);
}
複製代碼

以上實例中指定了一個名爲getProducerFallback的備用方法。當該斷路器處於斷開狀態時,此方法將替代getValue接受調用:

private ProducerResponse getProducerFallback() {
return new ProducerResponse(42);
}複製代碼

除了實現狀態機機制以外,Hystrix還可以提供來自各斷路機制的重要遙測指標流,具體包括請求計量、響應時間直方圖以及成功、失敗與短路請求數量等(如圖六所示)。

如何利用Spring Cloud構建起自我修復型分佈式系統

圖六:Hystrix儀表板

Zuul可以處理所有指向Netflix邊緣服務的輸入請求。它可以與Ribbon以及Hystrix等其它Netflix組件相結合,從而提供一個靈活且具備彈性的Netflix服務路由層。

Netflix公司在Zuul當中加載動態過濾機制,從而實現如下各項功能:

  • 驗證與安全保障: 識別面向各種資源的驗證要求並拒絕那些與要求不符的請求。
  • 審查與監控: 在邊緣位置追蹤有意義數據及統計結果,從而爲咱們帶來準確的生產狀態結論。
  • 動態路由: 以動態方式根據須要將請求路由至不一樣後端集羣處。
  • 壓力測試: 逐漸增長指向集羣的負載流量,從而計算性能水平。
  • 負載分配: 爲每一種負載類型分配對應容量,並棄用超出限定值的請求。
  • 靜態響應處理: 在邊緣位置直接創建部分響應,從而避免其流入內部集羣。
  • 多區域彈性: 跨越AWS區域進行請求路由,旨在實現ELB使用多樣化並保證邊緣位置與使用者儘量接近。

除此以外,Netflix公司還利用Zuul的功能經過金絲雀版本實現精確路由與壓力測試。

Spring Cloud已經創建起一套嵌入式Zuul代理機制,從而簡化常見用例當中UI應用須要將調用代理至一項或者多項後端服務處的對應開發流程。這項功能對於要求將用戶界面代理至後端服務的用例而言極爲便捷,其避免了管理CORS(即跨域資源共享)以及爲所有後端進行獨立驗證等複雜流程。Zuul代理機制的一類重要應用在於實現API網關模式(如圖七所示)。

如何利用Spring Cloud構建起自我修復型分佈式系統

圖七:API網關模式

Spring Cloud對嵌入式Zuul代理進行了強化,從而使其可以自動實現文件上傳處理。而與Spring Cloud Security配合以後,其可以輕鬆實現OAuth2 SSO以及將令牌傳遞至下游服務等工做。Zuul利用Ribbon做爲其客戶端與所有出站請求的負載均衡機制。Ribbon的動態服務器列表內容一般由Eureka負責填充,但Spring Cloud也可以經過其它來源填充該列表。Spring Cloud Lattice項目就已經可以經過輪詢Cloud Foundry Diego的Receptor API填充Ribbon的服務器列表。

跨入微服務領域的決定意味着咱們將正式迎接分佈式系統所帶來的諸多挑戰,而分佈式系統毫不是那種可以「湊合使用」的方案。所以,咱們必須假設系統內各組件的行爲及位置始終處於不斷變化當中,甚至常常表現出不可預知狀態。在今天的文章中,咱們已經談到了幾種可以幫助你們解決此類挑戰的現成模式,並且這些模式已經在Netflix OSS與Spring Cloud獲得切實驗證。我我的建議你們在着手創建理想中的「永遠運行、自我修復且具有可擴展能力」的系統方案以前,首先對它們進行一番嘗試與體驗。

*備註:這八大誤區分別爲:

1.網絡環境是可靠的

2.延遲水平爲零

3.傳輸帶寬是無限的

4.網絡環境是安全的

5.拓撲結構不會變化

6.總會有管理員幫助解決問題

7.流量成本爲零

8.網絡內各組成部分擁有同質性

原文標題:Build self-healing distributed systems with Spring Cloud

相關文章
相關標籤/搜索