1. 程式人生 > >Spring Cloud技術分析(1)——服務治理

Spring Cloud技術分析(1)——服務治理

地址:http://tech.lede.com/

    本文作為系列的第一篇正文,從Spring Cloud中的核心專案Spring Cloud Netflix入手,闡述了Spring Cloud Netflix的優勢,介紹了Spring Cloud Netflix進行服務治理的技術原理。

1. Spring Cloud Netflix的優勢

對於微服務的治理而言,核心就是服務的註冊和發現。所以選擇哪個元件,很大程度上要看它對於服務註冊與發現的解決方案。在這個領域,開源架構很多,最常見的是Zookeeper,但這並不是一個最佳選擇。

在分散式系統領域有個著名的CAP定理:C——資料一致性,A——服務可用性,P——服務對網路分割槽故障的容錯性

。這三個特性在任何分散式系統中不能同時滿足,最多同時滿足兩個。

Zookeeper是著名Hadoop的一個子專案,很多場景下Zookeeper也作為Service發現服務解決方案。Zookeeper保證的是CP,即任何時刻對Zookeeper的訪問請求能得到一致的資料結果,同時系統對網路分割具備容錯性,但是它不能保證每次服務請求的可用性。從實際情況來分析,在使用Zookeeper獲取服務列表時,如果zookeeper正在選主,或者Zookeeper叢集中半數以上機器不可用,那麼將就無法獲得資料了。所以說,Zookeeper不能保證服務可用性。

誠然,對於大多數分散式環境,尤其是涉及到資料儲存的場景,資料一致性應該是首先被保證的,這也是zookeeper設計成CP的原因。但是對於服務發現場景來說,情況就不太一樣了:針對同一個服務,即使註冊中心的不同節點儲存的服務提供者資訊不盡相同,也並不會造成災難性的後果。因為對於服務消費者來說,能消費才是最重要的——拿到可能不正確的服務例項資訊後嘗試消費一下,也好過因為無法獲取例項資訊而不去消費。所以,對於服務發現而言,可用性比資料一致性更加重要——AP勝過CP

。而Spring Cloud Netflix在設計Eureka時遵守的就是AP原則。

Eureka本身是Netflix開源的一款提供服務註冊和發現的產品,並且提供了相應的Java封裝。在它的實現中,節點之間是相互平等的,部分註冊中心的節點掛掉也不會對叢集造成影響,即使叢集只剩一個節點存活,也可以正常提供發現服務。哪怕是所有的服務註冊節點都掛了,Eureka Clients上也會快取服務呼叫的資訊。這就保證了我們微服務之間的互相呼叫是足夠健壯的。

除此之外,Spring Cloud Netflix背後強大的開源力量,也促使我們選擇了Spring Cloud Netflix:

  • 前文提到過,Spring Cloud的社群十分活躍,其在業界的應用也十分廣泛(尤其是國外),而且整個框架也經受住了Netflix嚴酷生產環境的考驗。
  • 除了服務註冊和發現,Spring Cloud Netflix的其他功能也十分強大,包括Ribbon,hystrix,Feign,Zuul等元件,結合到一起,讓服務的呼叫、路由也變得異常容易。
  • Spring Cloud Netflix作為Spring的重量級整合框架,使用它也意味著我們能從Spring獲取到巨大的便利。Spring Cloud的其他子專案,比如Spring Cloud Stream、Spring Cloud Config等等,都為微服務的各種需求提供了一站式的解決方案。

Netflix和Spring Cloud是什麼關係呢?Netflix是一家成功實踐微服務架構的網際網路公司,幾年前,Netflix就把它的幾乎整個微服務框架棧開源貢獻給了社群。Spring背後的Pivotal在2015年推出的Spring Cloud開源產品,主要對Netflix開源元件的進一步封裝,方便Spring開發人員構建微服務基礎框架。

2. Spring Cloud Netflix主要元件介紹

Spring Cloud Netflix的核心是用於服務註冊與發現的Eureka,接下來我們將以Eureka為線索,介紹Eureka、Ribbon、Hystrix、Feign這些Spring Cloud Netflix主要元件。

2.1 服務註冊與發現——Eureka

Eureka這個詞來源於古希臘語,意為“我找到了!我發現了!”,據傳,阿基米德在洗澡時發現浮力原理,高興得來不及穿上褲子,跑到街上大喊:“Eureka(我找到了)!”。

Eureka由多個instance(服務例項)組成,這些服務例項可以分為兩種:Eureka Server和Eureka Client。為了便於理解,我們將Eureka client再分為Service Provider和Service Consumer。如下圖所示:

1-1
  • Eureka Server:服務的註冊中心,負責維護註冊的服務列表。
  • Service Provider:服務提供方,作為一個Eureka Client,向Eureka Server做服務註冊、續約和下線等操作,註冊的主要資料包括服務名、機器ip、埠號、域名等等。
  • Service Consumer:服務消費方,作為一個Eureka Client,向Eureka Server獲取Service Provider的註冊資訊,並通過遠端呼叫與Service Provider進行通訊。

Service Provider和Service Consumer不是嚴格的概念,Service Consumer也可以隨時向Eureka Server註冊,來讓自己變成一個Service Provider。

Spring Cloud針對服務註冊與發現,進行了一層抽象,並提供了三種實現:Eureka、Consul、Zookeeper。目前支援得最好的就是Eureka,其次是Consul,最後是Zookeeper。

2.1.1 Eureka Server

Eureka Server作為一個獨立的部署單元,以REST API的形式為服務例項提供了註冊、管理和查詢等操作。同時,Eureka Server也為我們提供了視覺化的監控頁面,可以直觀地看到各個Eureka Server當前的執行狀態和所有已註冊服務的情況。

2.1.1.1 Eureka Server的高可用叢集

Eureka Server可以執行多個例項來構建叢集,解決單點問題,但不同於ZooKeeper的選舉leader的過程,Eureka Server採用的是Peer to Peer對等通訊。這是一種去中心化的架構,無master/slave區分,每一個Peer都是對等的。在這種架構中,節點通過彼此互相註冊來提高可用性,每個節點需要新增一個或多個有效的serviceUrl指向其他節點。每個節點都可被視為其他節點的副本。

如果某臺Eureka Server宕機,Eureka Client的請求會自動切換到新的Eureka Server節點,當宕機的伺服器重新恢復後,Eureka會再次將其納入到伺服器叢集管理之中。當節點開始接受客戶端請求時,所有的操作都會進行replicateToPeer(節點間複製)操作,將請求複製到其他Eureka Server當前所知的所有節點中。

一個新的Eureka Server節點啟動後,會首先嚐試從鄰近節點獲取所有例項登錄檔資訊,完成初始化。Eureka Server通過getEurekaServiceUrls()方法獲取所有的節點,並且會通過心跳續約的方式定期更新。預設配置下,如果Eureka Server在一定時間內沒有接收到某個服務例項的心跳,Eureka Server將會登出該例項(預設為90秒,通過eureka.instance.lease-expiration-duration-in-seconds配置)。當Eureka Server節點在短時間內丟失過多的心跳時(比如發生了網路分割槽故障),那麼這個節點就會進入自我保護模式。下圖為Eureka官網的架構圖

什麼是自我保護模式?預設配置下,如果Eureka Server每分鐘收到心跳續約的數量低於一個閾值(instance的數量*(60/每個instance的心跳間隔秒數)*自我保護係數),並且持續15分鐘,就會觸發自我保護。在自我保護模式中,Eureka Server會保護服務登錄檔中的資訊,不再登出任何服務例項。當它收到的心跳數重新恢復到閾值以上時,該Eureka Server節點就會自動退出自我保護模式。它的設計哲學前面提到過,那就是寧可保留錯誤的服務註冊資訊,也不盲目登出任何可能健康的服務例項。該模式可以通過eureka.server.enable-self-preservation = false來禁用,同時eureka.instance.lease-renewal-interval-in-seconds可以用來更改心跳間隔,eureka.server.renewal-percent-threshold可以用來修改自我保護係數(預設0.85)。

image

2.1.1.2 Eureka Server的Region、Zone

Eureka的官方文件對Regin、Zone幾乎沒有提及,由於概念抽象,新手很難理解。因此,我們先來了解一下Region、Zone、Eureka叢集三者的關係,如下圖所示:

image

region和zone(或者Availability Zone)均是AWS的概念。在非AWS環境下,我們可以先簡單地將region理解為Eureka叢集,zone理解成機房。上圖就可以理解為一個Eureka叢集被部署在了zone1機房和zone2機房中。

2.1.2 Service Provider

2.1.2.1 服務註冊

Service Provider本質上是一個Eureka Client。它啟動時,會呼叫服務註冊方法,向Eureka Server註冊自己的資訊。Eureka Server會維護一個已註冊服務的列表,這個列表為一個巢狀的hash map:

  • 第一層,application name和對應的服務例項。
  • 第二層,服務例項及其對應的註冊資訊,包括IP,埠號等。

當例項狀態發生變化時(如自身檢測認為Down的時候),也會向Eureka Server更新自己的服務狀態,同時用replicateToPeers()向其它Eureka Server節點做狀態同步。

image

2.1.2.2 續約與剔除

前面提到過,服務例項啟動後,會週期性地向Eureka Server傳送心跳以續約自己的資訊,避免自己的註冊資訊被剔除。續約的方式與服務註冊基本一致:首先更新自身狀態,再同步到其它Peer。

如果Eureka Server在一段時間內沒有接收到某個微服務節點的心跳,Eureka Server將會登出該微服務節點(自我保護模式除外)。

image

2.1.3 Service Consumer

Service Consumer本質上也是一個Eureka Client(它也會向Eureka Server註冊,只是這個註冊資訊無關緊要罷了)。它啟動後,會從Eureka Server上獲取所有例項的註冊資訊,包括IP地址、埠等,並快取到本地。這些資訊預設每30秒更新一次。前文提到過,如果與Eureka Server通訊中斷,Service Consumer仍然可以通過本地快取與Service Provider通訊。

實際開發Eureka的過程中,有時會遇見Service Consumer獲取到Server Provider的資訊有延遲,在Eureka Wiki中有這麼一段話:

All operations from Eureka client may take some time to reflect in the Eureka servers and subsequently in other Eureka clients. This is because of the caching of the payload on the eureka server which is refreshed periodically to reflect new information. Eureka clients also fetch deltas periodically. Hence, it may take up to 2 mins for changes to propagate to all Eureka clients.

最後一句話提到,服務端的更改可能需要2分鐘才能傳播到所有客戶端,至於原因並沒有介紹。這是因為Eureka有三處快取和一處延遲造成的。

  • Eureka Server對註冊列表進行快取,預設時間為30s。
  • Eureka Client對獲取到的註冊資訊進行快取,預設時間為30s。
  • Ribbon會從上面提到的Eureka Client獲取服務列表,將負載均衡後的結果快取30s。
  • 如果不是在Spring Cloud環境下使用這些元件(Eureka, Ribbon),服務啟動後並不會馬上向Eureka註冊,而是需要等到第一次傳送心跳請求時才會註冊。心跳請求的傳送間隔預設是30s。Spring Cloud對此做了修改,服務啟動後會馬上註冊。

基於Service Consumer獲取到的服務例項資訊,我們就可以進行服務呼叫了。而Spring Cloud也為Service Consumer提供了豐富的服務呼叫工具:

  • Ribbon,實現客戶端的負載均衡。
  • Hystrix,斷路器。
  • Feign,RESTful Web Service客戶端,整合了Ribbon和Hystrix。

接下來我們就一一介紹。

2.2 服務呼叫端負載均衡——Ribbon

Ribbon是Netflix釋出的開源專案,主要功能是為REST客戶端實現負載均衡。它主要包括六個元件:

  • ServerList,負載均衡使用的伺服器列表。這個列表會快取在負載均衡器中,並定期更新。當Ribbon與Eureka結合使用時,ServerList的實現類就是DiscoveryEnabledNIWSServerList,它會儲存Eureka Server中註冊的服務例項表。
  • ServerListFilter,伺服器列表過濾器。這是一個介面,主要用於對Service Consumer獲取到的伺服器列表進行預過濾,過濾的結果也是ServerList。Ribbon提供了多種過濾器的實現。
  • IPing,探測服務例項是否存活的策略。
  • IRule,負載均衡策略,其實現類表述的策略包括:輪詢、隨機、根據響應時間加權等,其類結構如下圖所示。

    !image

    我們也可以自己定義負載均衡策略,比如我們就利用自己實現的策略,實現了服務的版本控制和直連配置。實現好之後,將實現類重新注入到Ribbon中即可。

  • ILoadBalancer,負載均衡器。這也是一個介面,Ribbon為其提供了多個實現,比如ZoneAwareLoadBalancer。而上層程式碼通過呼叫其API進行服務呼叫的負載均衡選擇。一般ILoadBalancer的實現類中會引用一個IRule。

  • RestClient,服務呼叫器。顧名思義,這就是負載均衡後,Ribbon向Service Provider發起REST請求的工具。

Ribbon工作時會做四件事情:

  1. 優先選擇在同一個Zone且負載較少的Eureka Server;
  2. 定期從Eureka更新並過濾服務例項列表;
  3. 根據使用者指定的策略,在從Server取到的服務註冊列表中選擇一個例項的地址;
  4. 通過RestClient進行服務呼叫。

2.3 服務呼叫端熔斷——Hystrix

Netflix建立了一個名為Hystrix的庫,實現了斷路器的模式。“斷路器”本身是一種開關裝置,當某個服務單元發生故障之後,通過斷路器的故障監控(類似熔斷保險絲),向呼叫方返回一個符合預期的、可處理的備選響應(FallBack),而不是長時間的等待或者丟擲呼叫方無法處理的異常,這樣就保證了服務呼叫方的執行緒不會被長時間、不必要地佔用,從而避免了故障在分散式系統中的蔓延,乃至雪崩。

image

當然,在請求失敗頻率較低的情況下,Hystrix還是會直接把故障返回給客戶端。只有當失敗次數達到閾值(預設在20秒內失敗5次)時,斷路器開啟並且不進行後續通訊,而是直接返回備選響應。當然,Hystrix的備選響應也是可以由開發者定製的。

image

除了隔離依賴服務的呼叫以外,Hystrix還提供了準實時的呼叫監控(Hystrix Dashboard),Hystrix會持續地記錄所有通過Hystrix發起的請求的執行資訊,並以統計報表和圖形的形式展示給使用者,包括每秒執行多少請求多少成功,多少失敗等。Netflix通過hystrix-metrics-event-stream專案實現了對以上指標的監控。Spring Cloud也提供了Hystrix Dashboard的整合,對監控內容轉化成視覺化介面,Hystrix Dashboard Wiki上詳細說明了圖上每個指標的含義。

image

2.4 服務呼叫端程式碼抽象和封裝——Feign

Feign是一個宣告式的Web Service客戶端,它的目的就是讓Web Service呼叫更加簡單。它整合了Ribbon和Hystrix,從而讓我們不再需要顯式地使用這兩個元件。Feign還提供了HTTP請求的模板,通過編寫簡單的介面和插入註解,我們就可以定義好HTTP請求的引數、格式、地址等資訊。接下來,Feign會完全代理HTTP的請求,我們只需要像呼叫方法一樣呼叫它就可以完成服務請求。

Feign具有如下特性:

  • 可插拔的註解支援,包括Feign註解和JAX-RS註解
  • 支援可插拔的HTTP編碼器和解碼器
  • 支援Hystrix和它的Fallback
  • 支援Ribbon的負載均衡
  • 支援HTTP請求和響應的壓縮

以下是一個Feign的簡單示例:

@SpringBootApplication
@EnableDiscoveryClient //啟用Feign
@EnableFeignClients
public class Application
{
    public static void main(String[] args)
    {
        SpringApplication.run(Application.class, args);
    }
}

@FeignClient(name = "elements", fallback = ElementsFallback.class) //指定feign呼叫的服務和Hystrix Fallback(name即eureka的application name)
public interface Elements
{
    @RequestMapping(value = "/index")
    String index();
}

//Hystrix Fallback    
@Component
public class ElementsFallback implements Elements
{
    @Override
    public String index()
    {
        return "**************";
    }
}

//測試類
@Component    
public class TestController {
    @Autowired
    Elements elements;

    @RequestMapping(value = "/testEureka", method = RequestMethod.GET)
    public String testeureka()
    {
         return elements.index();
    }
}

3. 參考文獻

相關推薦

Spring Cloud技術分析1——服務治理

地址:http://tech.lede.com/    本文作為系列的第一篇正文,從Spring Cloud中的核心專案Spring Cloud Netflix入手,闡述了Spring Cloud Netflix的優勢,介紹了Spring Cloud Netflix進行服務治

Spring Cloud技術分析3- spring cloud sleuth

地址:http://tech.lede.com/1. 目的提供鏈路追蹤。通過sleuth可以很清楚的看出一個請求都經過了哪些服務。可以很方便的理清服務間的呼叫關係。視覺化錯誤。對於程式未捕捉的異常,可以在zipkin介面上看到。分析耗時。通過sleuth可以很方便的看出每個取

Spring Cloud技術分析4- spring cloud zuul

地址:http://tech.lede.com/    spring cloud zuul是netflix提供的一個元件,功能類似於nginx,用於反向代理,可以提供動態路由、監控、授權、安全、排程等邊緣服務。1. zuul是什麼微服務場景下,每一個微服務對外暴露了一組細粒度

Spring Cloud》學習 服務治理

  前言:之前網上學習過Spring Cloud,對於工作上需要是足夠了,總歸對於一些方面一知半解,最近難得有些閒暇時間,有幸讀了崔永超先生的《Spring Cloud 微服務實戰》,一方面記錄下自己的學習歷程和讀後感,一方面分享下自己對Spring Cloud微服務的一些見解,寫下此文。  注意:本文著重於

spring-cloud-starter-hystrix斷路器服務不通或者調用失敗後的錯誤處理和回調

系統 comm cli 處理 參考 quest 微服務架構 ron 100% 雪崩效應 在微服務架構中通常會有多個服務層調用,大量的微服務通過網絡進行通信,從而支撐起整個系統。各個微服務之間也難免存在大量的依賴關系。然而任何服務都不是100%可用的,網絡往往也是脆弱的,所

Spring Cloud Eureka 入門 服務消費者詳解

摘要: 原創出處:www.bysocket.com 泥瓦匠BYSocket 希望轉載,保留摘要,謝謝! “真正的進步,不在於學習,而在於反思”  「Spring Cloud Eureka 入門系列」本文提綱 1.  springcloud-eureka-sample 工程介紹 2. 執行 spring

spring IOC原始碼分析1

1.何謂Spring IOC         何謂Spring IOC?書上謂之“依賴注入”,那何謂“依賴注入”?         作為一個Java程式猿,應該遇到過這樣的問題,當你在程式碼中需要使用某個類提供的功能時,你首先需要new一個物件,給它傳遞必要的引數,然後才

Spring cloud入門教程1

       看到網上關於Spring cloud的入門教程基本是基於Eclipse的,因為我用的是IDEA,所以打算寫一份IDEA使用Spring cloud的入門教程。        廢話不多說,直接來幹。        Spring cloud是一個分散式架構的服務

Spring Cloud Eureka 入門 服務提供者詳解

2017-07-10 16:03:15.075 INFO 11020 --- [ main] o.s.c.n.e.s.EurekaServiceRegistry : Registering application provider-service with eureka

Spring Session 原始碼分析1——springSessionRepositoryFilter

#Tomcat Session 對於session 是一個老生暢談的話題了,Session管理是JavaEE容器比較重要的一部分, Tomcat中主要由每個context容器內的一個Manager物件來管理session。對於這個manager物件的實現,可以

服務治理深入淺出1- 服務治理出現的必要性探索

更多詳情請看直播 揭開她的神祕面紗 - 零基礎構建自己的服務治理框架 https://segmentfault.com/l/15... 很久之前聽別人分享他們的架構,總會說,因為某某原因,我們進行服務化,我們公司開發了一套服務治理框架。 當時虎軀為之一震,趕緊在手機上記下關鍵詞

Spring源代碼分析1---LocalSessionFactoryBean(工廠的工廠)

self action interface 開始 environ mac hbm upd put LocalSessionFacotoryBean其實就是適配了Configuration對象,或者說是一個工廠的工廠,他是Configuration的工廠,生成了Configu

spring cloud系列教程4--eureka註冊中心叢集配置,微服務註冊資訊完善

給大家推薦個靠譜的公眾號程式設計師探索之路,大家一起加油 ​   1.Eureka是什麼 Eureka是Netflix的一個子模組之一,AP設計原則。Eureka是一個以及Rest的服務,用於定位服務,以實現雲端中間層服務發現和故障轉移。服務註冊與發現對於微服務架構來

Spring Cloud從0開始服務治理Spring Clound Eureka

一 . 完成一個Eureka(服務端)專案 1.登入網址 https://start.spring.io/ 選擇需要的依賴 -> Eureka Server 解壓至本地 2.通過IDEA 以Maven專案匯入。 (1)添加註解@EnableEurekaS

【原創】Spring-Cloud快速入門服務入門--轉載請註明出處

一、什麼是微服務? 有時候,會有的人存在誤解,所謂微服務就是SpringCloud。這種思想本身是不正確的,微服務是一種系統架構上面的設計風格,而SpringCloud則是一種較為適用於微服務架構的框架。 在java體系中,我們通常需要將一個大的類,拆分成若干個的小的類,每個類都具有自己獨立

Spring Cloud 元件搭建Eureka服務發現

Spring Cloud生態圈目前有21個子專案來共同構建,解決了目前微服務系統的很多問題,廢話不多說,直接上其最普通簡單的Eureka服務發現與註冊中心搭建過程。本系列教材依照1.3.5.RELEASE版本,該版本比較穩定,JDK要求1.7以上。 1、mic

Android系統原理與原始碼分析1:利用Java反射技術阻止通過按鈕關閉對話方塊

本文為原創,如需轉載,請註明作者和出處,謝謝!     眾所周知,AlertDialog類用於顯示對話方塊。關於AlertDialog的基本用法在這裡就不詳細介紹了,網上有很多,讀者可以自己搜尋。那

Spring Cloud微學習Eureka應用——服務間通訊

微服務可以在“自己的程式”中執行,並通過“輕量級裝置與HTTP型API進行溝通”。這裡的溝通就是本節要說的服務間通訊。即各個微服務註冊到Eureka服務註冊中心,這些微服務之間的通訊 建立服務提供者 啟動上一節 Eureka入門——叢集的服務內容

Spring初始化過程原始碼分析1

本文主要詳細分析Spring初始化過程的原始碼分析,目的是理解Spring具體是如何工作的。部分內容查閱於網路,有不妥之處望指正。 1、web專案中伺服器一啟動就開始載入web.xml,Spring的啟動是從web.xml中的org.springframewo

【原創】Spring-Cloud快速入門服務入門

一、什麼是微服務? 有時候,會有的人存在誤解,所謂微服務就是SpringCloud。這種思想本身是不正確的,微服務是一種系統架構上面的設計風格,而SpringCloud則是一種較為適用於微服務架構的框