Spring Cloud Netflix 是 Spring Cloud 中的一套框架,由 Netflix 開發後來又併入 Spring Cloud 你們庭,它主要提供的模塊包括:服務發現、斷路器和監控、智能路由、客戶端負載均衡等。git
本文從 Spring Cloud 中的核心項目 Spring Cloud Netflix 入手,闡述了 Spring Cloud Netflix 的優點,介紹了 Spring Cloud Netflix 進行服務治理的技術原理。github
Spring Cloud Netflix 的優點
對於微服務的治理而言,核心就是服務的註冊和發現。因此選擇哪一個組件,很大程度上要看它對於服務註冊與發現的解決方案。在這個領域,開源架構不少,最多見的是 Zookeeper,但這並非一個最佳選擇。spring
在分佈式系統領域有個著名的 CAP 定理:C——數據一致性,A——服務可用性,P——服務對網絡分區故障的容錯性。這三個特性在任何分佈式系統中不能同時知足,最多同時知足兩個。segmentfault
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 開始把總體的系統往微服務上遷移。
他家的微服務作的不是最先的,可是倒是最大規模的在生產級別微服務的嘗試。幾年前,Netflix 就把它的幾乎整個微服務框架棧開源貢獻給了社區,叫作 Netflix OSS。
Spring 背後的 Pivotal 在 2015 年推出的 Spring Cloud 開源產品,主要對 Netflix 開源組件的進一步封裝,方便 Spring 開發人員構建微服務基礎框架。(雖然 Spring Cloud 到如今爲止不僅有 Netflix 提供的方案能夠集成,還有不少方案,但 Netflix 是最成熟的。)app
Spring Cloud Netflix 主要組件
Spring Cloud Netflix 的核心是用於服務註冊與發現的 Eureka,接下來咱們將以 Eureka 爲線索,介紹 Eureka、Ribbon、Hystrix、Feign 這些 Spring Cloud Netflix 主要組件。負載均衡
服務註冊與發現——Eureka
Eureka 這個詞來源於古希臘語,意爲 「我找到了!我發現了!」,據傳,阿基米德在洗澡時發現浮力原理,高興得來不及穿上褲子,跑到街上大喊:「Eureka(我找到了)!」。
Spring Cloud Eureka 是 Spring Cloud Netflix 微服務套件的一部分,基於 Netflix Eureka 作了二次封裝,主要負責完成微服務架構中的服務治理功能,服務治理能夠說是微服務架構中最爲核心和基礎的模塊,他主要用來實現各個微服務實例的自動化註冊與發現。
- 服務註冊:在服務治理框架中,一般都會構建一個註冊中心,每一個服務單元向註冊中心登記本身提供的服務,將主機與端口號、版本號、通訊協議等一些附加信息告知註冊中心,註冊中心按照服務名分類組織服務清單,服務註冊中心還須要以心跳的方式去監控清單中的服務是否可用,若不可用須要從服務清單中剔除,達到排除故障服務的效果。
- 服務發現:因爲在服務治理框架下運行,服務間的調用再也不經過指定具體的實例地址來實現,而是經過向服務名發起請求調用實現。
Spring Cloud Eureka 使用 Netflix Eureka 來實現服務註冊與發現,即包括了服務端組件,也包含了客戶端組件,而且服務端和客戶端均採用 Java 編寫,因此 Eureka 主要適用與經過 Java 實現的分佈式系統,或是與 JVM 兼容語言構建的系統,可是,因爲 Eureka 服務端的服務治理機制提供了完備的 RESTful API,因此他也支持將非 Java 語言構建的微服務歸入 Eureka 的服務治理體系中來。
Eureka 由多個 instance(服務實例) 組成,這些服務實例能夠分爲兩種:Eureka Server 和 Eureka Client。爲了便於理解,咱們將 Eureka client 再分爲 Service Provider 和 Service Consumer。以下圖所示:
- 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。在層抽象的做用下,咱們能夠無縫地切換服務治理實現,而且不影響任何其餘的服務註冊、服務發現、服務調用等邏輯。
Eureka Server
Eureka Server 做爲一個獨立的部署單元,以 REST API 的形式爲服務實例提供了註冊、管理和查詢等操做。同時,Eureka Server 也爲咱們提供了可視化的監控頁面,能夠直觀地看到各個 Eureka Server 當前的運行狀態和全部已註冊服務的狀況。
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 的首頁看到如下這段提示,則說明 Eureka 已經進入了保護模式。
EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY’RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.
默認配置下,若是 Eureka Server 每分鐘收到心跳續約的數量低於一個閾值,而且持續 15 分鐘,就會觸發自我保護。
1 |
閾值 = instance的數量 × (60 / instance的心跳間隔秒數) × 自我保護係數 |
在自我保護模式中,Eureka Server 會保護服務註冊表中的信息,再也不註銷任何服務實例。當它收到的心跳數從新恢復到閾值以上時,該 Eureka Server 節點就會自動退出自我保護模式。它的設計哲學前面提到過,那就是寧肯保留錯誤的服務註冊信息,也不盲目註銷任何可能健康的服務實例。這樣作會使客戶端很容易拿到實際已經不存在的服務實例,會出現調用失敗的狀況。所以客戶端要有容錯機制,好比請求重試、斷路器。該模式能夠經過eureka.server.enable-self-preservation = false
來禁用,同時eureka.instance.lease-renewal-interval-in-seconds
能夠用來更改心跳間隔(默認 30s),eureka.server.renewal-percent-threshold
能夠用來修改自我保護係數(默認 0.85)。
特別注意
上邊的那個閾值理論上是那麼計算的,可是在實際中,並非!!!並非!!!並非!!!
由於實際代碼中是硬編碼了,每一個註冊的實例都是直接 + 2,看下邊eureka-core-1.8.7.jar!com.netflix.eureka.registry.AbstractInstanceRegistry#register
中的這段代碼就明白了
1 |
// The lease does not exist and hence it is a new registration |
這個等有時間再仔細研究一下這個自我保護模式。
Eureka Server 的 Region、Zone
Region、Zone、Eureka 集羣三者的關係,以下圖所示:
region 和 zone(或者 Availability Zone)均是亞馬遜網絡服務 (AWS) 的概念。在非 AWS 環境下,咱們能夠先簡單地將 region 理解爲 Eureka 集羣,zone 理解成機房。上圖就能夠理解爲一個 Eureka 集羣被部署在了 zone1 機房和 zone2 機房中。
爲何對 AWS 有如此完善的支持?
由於 Netflix 在服務器運維上依託 AWS 雲,而上邊說到 Spring Cloud Netflix 是 Spring 在 Netflix 的開源組件 Netflix OSS 上封裝的。
Service Provider
服務註冊
Service Provider 本質上是一個 Eureka Client。它啓動時,會調用服務註冊方法,向 Eureka Server 註冊本身的信息。Eureka Server 會維護一個已註冊服務的列表,這個列表爲一個嵌套的 HashMap:
1 |
private final ConcurrentHashMap<String, Map<String, Lease<InstanceInfo>>> registry |
- 第一層,application name 和對應的服務實例。
- 第二層,服務實例及其對應的註冊信息,包括 IP,端口號等。
當實例狀態發生變化時(如自身檢測認爲 Down 的時候),也會向 Eureka Server 更新本身的服務狀態,同時用replicateToPeers()
向其它 Eureka Server 節點作狀態同步。
續約與剔除
前面提到過,服務實例啓動後,會週期性地向 Eureka Server 發送心跳以續約本身的信息,避免本身的註冊信息被剔除。續約的方式與服務註冊基本一致:首先更新自身狀態,再同步到其它 Peer。
若是 Eureka Server 在一段時間內沒有接收到某個微服務節點的心跳,Eureka Server 將會註銷該微服務節點(自我保護模式除外)。
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。
接下來咱們就一一介紹。
服務調用端負載均衡——Ribbon
Ribbon 是 Netflix 發佈的開源項目,主要功能是爲 REST 客戶端實現負載均衡。它主要包括六個組件:
- ServerList,負載均衡使用的服務器列表。這個列表會緩存在負載均衡器中,並按期更新。當 Ribbon 與 Eureka 結合使用時,ServerList 的實現類就是 DiscoveryEnabledNIWSServerList,它會保存 Eureka Server 中註冊的服務實例表。
- ServerListFilter,服務器列表過濾器。這是一個接口,主要用於對 Service Consumer 獲取到的服務器列表進行預過濾,過濾的結果也是 ServerList。Ribbon 提供了多種過濾器的實現。
- IPing,探測服務實例是否存活的策略。
- IRule,負載均衡策略,其實現類表述的策略包括:輪詢、隨機、根據響應時間加權等,其類結構以下圖所示。
咱們也能夠本身定義負載均衡策略,好比咱們就利用本身實現的策略,實現了服務的版本控制和直連配置。實現好以後,將實現類從新注入到 Ribbon 中便可。
- ILoadBalancer,負載均衡器。這也是一個接口,Ribbon 爲其提供了多個實現,好比 ZoneAwareLoadBalancer。而上層代碼經過調用其 API 進行服務調用的負載均衡選擇。通常 ILoadBalancer 的實現類中會引用一個 IRule。
- RestClient,服務調用器。顧名思義,這就是負載均衡後,Ribbon 向 Service Provider 發起 REST 請求的工具。
Ribbon 工做時會作四件事情:
- 優先選擇在同一個 Zone 且負載較少的 Eureka Server;
- 按期從 Eureka 更新並過濾服務實例列表;
- 根據用戶指定的策略,在從 Server 取到的服務註冊列表中選擇一個實例的地址;
- 經過 RestClient 進行服務調用。
服務調用端熔斷——Hystrix
雪崩效應
在微服務架構中一般會有多個服務層調用,基礎服務的故障可能會致使級聯故障,進而形成整個系統不可用的狀況,這種現象被稱爲服務雪崩效應。服務雪崩效應是一種因 「服務提供者」 的不可用致使 「服務消費者」 的不可用, 並將不可用逐漸放大的過程。
若是下圖所示:A 做爲服務提供者,B 爲 A 的服務消費者,C 和 D 是 B 的服務消費者。A 不可用引發了 B 的不可用,並將不可用像滾雪球同樣放大到 C 和 D 時,雪崩效應就造成了。
斷路器
Netflix 建立了一個名爲 Hystrix 的庫, 實現了斷路器的模式。「斷路器」 自己是一種開關裝置,當某個服務單元發生故障以後,經過斷路器的故障監控(相似熔斷保險絲),向調用方返回一個符合預期的、可處理的備選響應(FallBack),而不是長時間的等待或者拋出調用方沒法處理的異常,這樣就保證了服務調用方的線程不會被長時間、沒必要要地佔用,從而避免了故障在分佈式系統中的蔓延,乃至雪崩。
固然,在請求失敗頻率較低的狀況下,Hystrix 仍是會直接把故障返回給客戶端。只有當失敗次數達到閾值時,斷路器打開而且不進行後續通訊,而是直接返回備選響應。固然,Hystrix 的備選響應也是能夠由開發者定製的。
監控
除了隔離依賴服務的調用之外,Hystrix 還提供了準實時的調用監控(Hystrix Dashboard),Hystrix 會持續地記錄全部經過 Hystrix 發起的請求的執行信息,並以統計報表和圖形的形式展現給用戶,包括每秒執行多少請求多少成功,多少失敗等。Netflix 經過 hystrix-metrics-event-stream 項目實現了對以上指標的監控。Spring Cloud 也提供了 Hystrix Dashboard 的整合,對監控內容轉化成可視化界面,Hystrix Dashboard Wiki 上詳細說明了圖上每一個指標的含義。
服務調用端代碼抽象和封裝——Feign
Feign 是一個聲明式的 Web Service 客戶端,它的目的就是讓 Web Service 調用更加簡單。它整合了 Ribbon 和 Hystrix,從而讓咱們再也不須要顯式地使用這兩個組件。Feign 還提供了 HTTP 請求的模板,經過編寫簡單的接口和插入註解,咱們就能夠定義好 HTTP 請求的參數、格式、地址等信息。接下來,Feign 會徹底代理 HTTP 的請求,咱們只須要像調用方法同樣調用它就能夠完成服務請求。
Feign 具備以下特性:
- 可插拔的註解支持,包括 Feign 註解和 JAX-RS 註解
- 支持可插拔的 HTTP 編碼器和解碼器
- 支持 Hystrix 和它的 Fallback
- 支持 Ribbon 的負載均衡
- 支持 HTTP 請求和響應的壓縮
相關閱讀
Spring Cloud(一):服務治理技術概覽
Spring Cloud(二):服務註冊與發現 Eureka
Spring Cloud(三):服務提供與調用 Eureka
Spring Cloud(四):服務容錯保護 Hystrix
Spring Cloud(五):Hystrix 監控面板
Spring Cloud(六):Hystrix 監控數據聚合 Turbine
Spring Cloud(七):配置中心(Git 版與動態刷新)
Spring Cloud(八):配置中心(服務化與高可用)
Spring Cloud(九):配置中心(消息總線)
Spring Cloud(十):服務網關 Zuul(路由)
Spring Cloud(十一):服務網關 Zuul(過濾器)
Spring Cloud(十二):分佈式鏈路跟蹤(Sleuth 與 Zipkin)
示例代碼:GitHub
參考
spring-cloud
Spring Cloud 技術分析(1)——服務治理
Netflix/eureka Wiki
Spring Cloud 中,Eureka 常見問題總結
Dive into Eureka
Spring Cloud Netflix Eureka 源碼導讀與原理分析
理解 eureka 的自我保護機制
eureka 的驚羣效應
Understanding Spring Cloud Eureka Server self preservation and renew threshold
The Mystery of Eureka Self-Preservation
Hystrix 使用與分析