深入理解SpringCloud與微服務構建

一、SpringCloud微服務技術簡介

Spring Cloud 作為Java 語言的微服務框架,它依賴于Spring Boot,有快速開發、持續交付和

容易部署等特點。Spring Cloud 的組件非常多,涉及微服務的方方面面,井在開源社區Spring 和

Netflix 、Pivotal 兩大公司的推動下越來越完善。

1.1 微服務的功能主要體現在以下兒個方面。

口服務的注冊和發現。

口服務的負載均衡。

口服務的容錯。

口服務網關。

口服務配置的統一管理。

口鏈路追蹤。

口實時日志。

1.2 微服務具有以下的特點。

口按照業務來劃分服務,單個服務代碼量小,業務單一,易于維護。

口每個微服務都有自己獨立的基礎組件,例如數據庫、緩存等,且運行在獨立的進程中。

口微服務之間的通信是通過HTTP 協議或者消息組件,且具有容錯能力。

口微服務有一套服務治理的解決方案,服務之間不相合,可以隨時加入和剔除服務。

口單個微服務能夠集群化部署,并且有負載均衡的能力。

口整個微服務系統應該有一個完整的安全機制,包括用戶驗證、權限驗證、資源保護等。

口整個微服務系統有鏈路追蹤的能力。

口有一套完整的實時日志系統。

二、開發框架SpringBoot

三、服務注冊和發現Ereka

3.1 什么是Eureka

和Consul 、Zookeeper 類似, Eureka 是一個用于服務注冊和發現的組件,最開始主要應用

于亞馬遜公司旗下的云計算服務平臺AWS o Eureka 分為Eureka Server 和Eureka Client, Eureka

Server 為Eureka 服務注冊中心, Eureka Client 為Eureka 客戶端。

3.2 Ereka優勢

Eureka 和其他組件,比如負載均衡組件Ribbon 、熔斷器組件Hys往以、熔斷器監控組

件Hystrix Dashboard 組件、熔斷器聚合監控Turbine 組件,以及網關Zuul 組件相互配合, 能夠

很容易實現服務注冊、負載均衡、熔斷和智能路由等功能。這些組件都是由Netflix 公司開源的,

一起被稱為Netflix OSS 組件。Netflix OSS 組件由Spring Cloud 整合為Spring Cloud Netflix 組件,

Eureka 的基本架構如|到2-1 所示,其中主要包括以下3 種角色。

口Register Service :服務注冊中心,它是一個Eureka Server ,提供服務注冊和發現的功能。

口Provider Service :服務提供者,它是一個Eureka Client ,提供服務。

口Consumer Service :服務消費者,它是一個Eureka Cient ,消費服務。

服務消費的基本過程如下:首先前要一個服務注冊中心Eureka Server ,服務提供者Eureka

Client 向服務注冊中心Eureka Server 注冊,將自己的信息(比如服務名和服務的IP 地址等)

通過阻ST A 凹的形式提交給服務注冊中心Eureka Server 。同樣,服務消費者Eureka Client 也

向服務注冊1j1,L,, Eureka Server 注冊,同時服務消費者獲取一份服務注冊列表的信息, 該列表

包含了所有向脫務注冊中心Eureka Server 注冊的服務信息。獲取服務注冊列表信息之后,服

務消費者就知道服務提供者的IP 地址,可以通過Htφ 遠程調度來消費服務提供者的服務。

( l ) Registe 「一一服務注冊

? 當E ureka Client 向Eureka Server 注冊時, Eureka Client 提供自身的元數據,比如IP 地址、

端口、運行狀況H1 標的Uri 、主頁地址等信息。

(2) Renew一一服務續約

Eureka C li ent 在默認的情況下會每隔30 秒發送一次心跳來進行服務續約。通過服務續約

來告知E ureka Server 該Eureka Client 仍然可用,沒有出現故障。正常情況下,如果E ureka Server

在90 秒內沒有收到Eureka Client 的心跳, Eureka Server 會將Eureka Client 實例從注冊列表中

刪除。注意:’盯網建議不要更t& 服務續約的間隔時間。

(3) Fetch Registries一一獲取服務注冊列表信息

Eureka Client 從Eureka Server 獲取服務注冊表信息,井將其緩存在本地。Eureka Client 會

使用服務注冊列表信息查找其他服務的信息,從而進行遠程調用。該注冊列表信息定時(每

30 秒) 更新一次,每次返回注冊列表信息可能與Eureka Client 的緩存信息不同, Eureka Client

會自己處理這些信息。如呆由于某種原因導致注冊列表信息不能及時匹配, Eureka Client 會重

新獲取整個注冊表信息。Eureka Server 緩存了所有的服務注冊列表信息,并將整個注冊列表以

及每個應用程序的信息進行了壓縮,壓縮內容和沒有壓縮的內容完全相同。Eureka Client 和

Eureka Server 可以使用JSON 和XML 數據格式進行通信。在默認的情況下, Eureka Client 使

用JSON 格式的方式來獲取服務注冊列表的信息。

( 4) Cancel -一服務下線

Eureka Client 在程序關閉時可以向Eureka Server 發送下線請求。發送請求后,該客戶端的

實例信息將從E ureka Server 的服務注冊列表中刪除。該下線請求不會自動完成,需要在程序

關閉時調用以下代碼:

DiscoveryManager . getinstance() .shutdownComponent();

( 5 ) Eviction一一服務剔除

在默認情況下,當Eureka Client 連續90 秒沒有向Eureka Server 發送服務續約(即心跳〉

時, Eureka Server 會將該服務實例從服務注冊列表刪除,即服務剔除。

四、負載均衡

五、申明式調用

5.1 申明式Feign的簡介

@Feign Client 注解用于創建聲明式API 接口,該接口是阻STful 風格的。Feign 被設計成

插拔式的,可以注入其他組件和Feign 一起使用。最典型的是如果Ribbon 可用, Feign 會和

Ribbon 相結合進行負載均衡。

在代碼中, value()和name()一樣,是被調用的服務的Serviceld 。url ()直接填寫硬編碼的

Uri 地址。decode404()即404 是被解碼,還是拋異常。configuration ()指明FeignClient 的配置類,

默認的配置類為FeignClientsConfiguration 類, 在缺省的情況下, 這個類注入了默認的Decoder 、

Encoder 和Contract 等配置的Bean 。fallback()為配置熔斷器的處理類。

配置如下:

spring :

application :

name : eureka-feign-client

server:

port : 8765

eureka :

client :

serv 工ceUrl :

defaultZone: http://localhost:8761/eureka/

在程序的啟動類EurekaFeignClientApplication 加上注解@E nableEurekaCJ ient 開啟Eureka

Client 的功能,通過注解@EnableFeignClients 開啟Feign Client 的功能。代碼如下:

@SpringBootApplication

@EnableEurekaClient

@EnableFeignClients

public class EurekaFeignClientApplication {

public static void main (String [] args) {

SpririgApplication . run(EurekaFeignClientApplication.class , args) ;

5.2?Feign簡單構建

通過以上3 個步驟,該程序就具備了Feign 的功能,現在來實現一個簡單的Feign Client o

新建一個EurekaClientFeign 的接口,在接口上加@FeignClient 注解來聲明一個Fe ign Client,

其中value 為遠程調用其他服務的服務名, FeignConfig.class 為Feign Client 的配置類。在

EurekaClientFeign 接口內部有一個sayHiFromClientEureka()方法,該方法通過Feign 來調用

eureka-client 服務的“ 曠的API 接口

六、熔斷器

6.1? 什么是Hystrix

在分布式系統中,服務與服務之間的依賴錯綜復雜, 一種不可避免的情況就是某些服務會

出現故障,導致依賴于它們的其他服務出現遠程調度的線程阻塞。Hystrix 是Netflix 公司開

源的一個項目,它提供了熔斷器功能,能夠阻止分布式系統中出現聯動故障。Hystrix 是通過

隔離服務的訪問點阻止聯動故障的,并提供了故障的解決方案,從而提高了整個分布式系統

的彈性。

6.2 Hystrix的作用

在復雜的分布式系統中,可能有幾十個服務相互依賴,這些服務由于某些原因,例如機房

的不可靠性、網絡服務商的不可靠性等,導致某個服務不可用。如果系統不隔離該不可用的服務,可能會導致整個系統不可用。

例如,對于依賴30 個服務的應用程序,每個服務的正常運行時間為99.99% ,對于單個服務來說, 99.99% 的可用是非常完美的。有99.9930 = 99.7% 的可正常運行時間和0.3% 的不可用時間,那么10 億次請求中有3000000次失敗,實際的情況可能比這更糟糕。如果不設計整個系統的韌性,即使所有依賴關系表現良好,單個服務只有0.01% 的不可用,由于整個系統的服務相互依賴,最終對整個系統的影響是非常大的。在微服務系統中, 一個用戶請求可能需要調用幾個服務才能完成。如圖8-1 所示,在所有的服務都處于可用狀態時, 一個用戶請求需要調用A 、H 、I 和P 服務。

6.3 Hystrix的場景

當某一個服務,例如服務I,出現網絡延遲或者故障時,即使服務A 、H 和P 可用,由于

服務I 的不可用,整個用戶請求會處于阻塞狀態,并等待服務I 的響應,如圖8-2 所示。

在高并發的情況下,單個服務的延遲會導致整個請求都處于延遲狀態,可能在幾秒鐘就使

整個服務處于線程負載飽和的狀態。

某個服務的單個點的請求故障會導致用戶的請求處于阻塞狀態,最終的結果就是整個服務

的線程資源消耗殆盡。由于服務的依賴性,會導致依賴于該故障服務的其他服務也處于線程阻

塞狀態,最終導致這些服務的線程資源消耗殆盡, 直到不可用,從而導致整個問服務系統都不

可用,即雪崩效應。

為了防止雪崩效應,因而產生了熔斷器模型。Hystrix 是在業界表現非常好的一個熔斷器

模型實現的開源組件,它是Spring Cloud 組件不可缺少的一部分。

6.4 Hystrix設計原則

Hystrix 的設計原則如下。

口防止單個服務的故障耗盡整個服務的Servlet 容器(例如Tomcat )的線程資源。

口快速失敗機制,如果某個服務出現了故障,則調用該服務的請求快速失敗,而不是線

程等待。

口提供回退( fallback )方案,在請求發生故障時,提供設定好的回退方案。

口使用熔斷機制,防止故障擴散到其他服務。

口提供熔斷器的監控組件Hystrix Dashboard,可以實時監控熔斷器的狀態。

6.5 Hystrix 的工作機制

當服務的某個API 接口的失敗次數

在一定時間內小于設定的閥值時,熔斷器處于關閉狀態,該API 接口正常提供服務。當該

API 接口處理請求的失敗次數大于設定的閥值時, Hystrix 判定該API 接口出現了故障,打開

熔斷器,這時請求該API 接口會執行快速失敗的邏輯(即fallback 回退的邏輯),不執行業

務邏輯,請求的線程不會處于阻塞狀態。處于打開狀態的熔斷器, 一段時間后會處于半打開

狀態,并將一定數量的請求執行正常邏輯。剩余的請求會執行快速失敗,若執行正常邏輯的

請求失敗了,則熔斷器繼續打開: 若成功了,則將熔斷器關閉。這樣熔斷器就具有了自我修

復的能力。

6.6 Hystrix Dashboard 是監控Hystrix 的熔斷器狀態

在微服務架構中,為了保證服務實例的可用性,防止服務實例出現故障導致線程阻塞,而

出現了熔斷器模型。烙斷器的狀況反映了一個程序的可用性和健壯性,它是一個重要指標。

Hystrix Dashboard 是監控Hystrix 的熔斷器狀況的一個組件,提供了數據監控和l 友好的圖形化

展示界面。本節在上一節的基礎上,以案例的形式講述如何使用Hystrix Dashboard 監控熔斷

器的狀態。

七、路由網關

智能路由網關組件Zuul:Zuul 作為微服務系統的網關組件,用于構建邊界服務( Edge

Service ),致力于動態路由、過濾、監控、彈性伸縮和安全。

7.1 Zuul的作用

Zuul 作為路由網關組件,在微服務架構中有著非常重要的作用,主要體現在以下6 個方面。

D Zuul 、Ribbon 以及Eureka 相結合,可以實現智能路由和負載均衡的功能, Zuul 能夠

將請求流量按某種策略分發到集群狀態的多個服務實例。

口網關將所有服務的API 接口統一聚合,并統一對外暴露。外界系統調用API 接口時,

都是由網關對外暴露的API 接口,外界系統不需要知道微服務系統中各服務相互調

用的復雜性。微服務系統也保護了其內部微服務單元的API 接口, 防止其被外界直

接調用,導致服務的敏感信息對外暴露。

口網關服務可以做用戶身份認證和權限認證,防止非法請求操作API 接口,對服務器

起到保護作用。

口網關可以實現監控功能,實時日志輸出,對請求進行記錄。

口網關可以用來實現流量監控, 在高流量的情況下,對服務進行降級。

口API 接口從內部服務分離出來, 方便做測試。

7.2 Zuul的工作原理

Zuul 是通過Servlet 來實現的, Zuul 通過自定義的Zuu!Servlet (類似于Spring MVC 的

DispatcServlet〕來對請求進行控制。Zuul 的核心是一系列過濾器,可以在Http 請求的發起和

響應返回期間執行一系列的過濾器。Zuul 包括以下4 種過濾器。

口PRE 過濾器: 它是在請求路由到具體的服務之前執行的,這種類型的過濾器可以做

安全驗證,例如身份驗證、參數驗證等。

口ROUTING 過濾器: 它用于將請求路由到具體的微服務實例。在默認情況下,它使用

Http Client 進行網絡請求。

口POST 過濾器:它是在請求己被路由到微服務后執行的。一般情況下,用作收集統計

信息、指標,以及將響應傳輸到客戶端。

口ERROR 過濾器:它是在其他過濾器發生錯誤時執行的。

Zuul 采取了動態讀取、編譯和運行這些過濾器。過濾器之間不能直接相互通信,而是通

過RequestContext 對象來共享數據, 每個請求都會創建一個RequestContext 對象。Zuul 過濾器

具有以下關鍵特性。

口Type (類型) : Zuul 過濾器的類型,這個類型決定了過濾器在請求的哪個階段起作用,

例如Pre 、Post 階段等。

口Execution Order (執行順序) :規定了過濾器的執行順序, Order 的值越小,越先執行。

口Criteria (標準) : Filter 執行所需的條件。

口Action (行動〉: 如果符合執行條件,則執行Action (即邏輯代碼)。

Zuul 請求的生命周期如圖9-1 所示,該圖來自Zuul 的官方文檔。

當一個客戶端Request 請求進入Zuul 網關服務時,網關先進入“pre filter飛進行一系列

的驗證、操作或者判斷。然后交給“routing filter ”進行路由轉發,轉發到具體的服務實例進

行邏輯處理、返回數據。當具體的服務處理完后,最后由“post filter ,,進行處理, 該類型的處

理器處理完之后,將Response 信息返回給客戶端。

7.3 在Zuul 上配置熔斷器

Zuul 作為Netflix 組件,可以與Ribbon 、Eureka 和Hystrix 等組件相結合,實現負載均衡、

熔斷器的功能。在默認情況下, Zuul 和Ribbon 相結合, 實現了負載均衡的功能。下面來講解

如何在Zuul 上實現熔斷功能。

在Zuul 中實現熔斷功能需要實現ZuulFallbackProvider 的接口。實現該接口有兩個方法, 一個

是getRouteO方法,用于指定熔斷功能應用于哪些路由的服務; 另一個方法fallbackResponseO為進

入熔斷功能時執行的邏輯

7.4 在Zuul 中使用過濾器

在前面的章節講述了過濾器的作用和種類,下面來講解如何實現一個自定義的過濾器。

實現過濾器很簡單, 只需要繼承ZuulFilter ,井實現Zuu!Filter 中的抽象方法,包括filterType()

和filterOrder(),以及IZuulFilter 的shouldFilter()和0均ect run()的兩個方法。其中, filterType()

即過濾器的類型,在前文已經講解過了,它有4 種類型,分別是“ pre '’“ post ”“ routing ”和

“ error ” 。白lterOrder()是過濾順序,它為一個Int 類型的值,值越小,越早執行該過濾器。

shouldFilter()表示該過濾器是否過濾邏輯,如果為true ,則執行run()方法:如果為false ,則

不執行run ()方法。run ()方法寫具體的過濾的邏輯。

5.Zuul 的常見使用方式

Zuul 是采用了類似于Spring MVC 的DispatchServlet 來實現的,采用的是異步阻塞模型,

所以性能比Ngnix 差。由于Zuul 和其他Netflix 組件可以相互配合、無縫集成, Zuul 很容易

就能實現負載均衡、智能路由和熔斷器等功能。在大多數情況下, Zuul 都是以集群的形式存

在的。由于Z u川的橫向擴展能力非常好,所以當負載過高時,可以通過添加實例來解決性

能瓶頸。

一種常見的使用方式是對不同的渠道使用不同的Zuul 來進行路由,例如移動端共用一個

Zuul 網關實例, Web 端用另一個Zuul 網關實例,其他的客戶端用另外一個Zuul 實例進行路由。

這種不同的渠邊用不同Zuul 實例的架構如圖9-3 所示。

另外一種常見的集群是通過Ngnix 和Zuul 相互結合來做負載均衡。暴露在最外面的是

Ngnix 主從雙熱備進行Keepalive, Ngnix 經過某種路由策略,將請求路由轉發到Zuul 集群上,

Zuul 最終將請求分發到具體的服務上,架構圖如圖9-4 所示。

八、配置中心

8.1 分布式配置中心Spring Cloud Config

口Config Server 從本地讀取配置文件。

Config Server 可以從本地倉庫讀取配置文件,也可以從遠處Git 倉庫讀取。本地倉庫是指

將所有的配置文件統一寫在Config Server 工程目錄下。Config Sever 暴露HttpAPI 接口, Config

Client 通過調用Config Sever 的H即API 接口來讀取配置文件。

spring:

cloud :

config :

server :

native :

search-locations: classpath : /shared

profiles :

active : native

application :

name : config- server

server :

port : 8769

在工程的Resources 目錄下建一個shared 文件夾,用于存放本地配置文件。在shared 目錄

下,新建一個config-client-dev. ym l 文件,用作eureka-client 工程的dev (開發環境〉的配置文

件。在config-client-dev.yml 配置文件中,指定程序的端口號為8762 , 并定義一個變fil foo , 該

變量的值為foo version l。

口Config Server 從遠程Git 倉庫讀取配置文件。

Spring Cloud Config 支持從遠程Git 倉庫讀取配置文件,即Config Server 可以不從本地的

倉庫讀取,而是從遠程Git 倉庫讀取。這樣做的好處就是將配置統一管理,并且可以通過Spring

Cloud Bus 在不人工啟動程序的情況下對Config Client 的配置進行刷新。

server:

port :8769

spring :

cloud :

config :

server:

git:

uri: https://github.com/forezp/SpringcloudConfig

searchPaths: respo

username: miles02 @163.com

password :

label : master

application:

name : config-server

其中, uri 為遠程Git 倉庫的地址, serachPaths 為搜索遠程倉庫的文件夾地址, usemame和passwor d 為Git 倉庫的登錄名和密碼。如果是私人Git 倉庫,登錄名和密碼是必須的;如果是公開的Git 倉庫,可以不需要。label 為git 倉庫的分支名。

口搭建高可用Co nfig Server 集群。

當服務實例很多時,所有的服務實例需要同時從配置中心

Config Server 讀取配置文件,這時可以考慮將配置中心Config Server 做成一個微服務,并且將

其集群化,從而達到高可用。

口使用Spring Cloud Bus 刷新配置。

Spring Cloud Bus 是用輕量的消息代理將分布式的節點連接起來,可以用于廣播配置文件

的更改或者服務的監控管理。)個關鍵的思想就是,消息總線可以為微服務做監控,也可以實

現應用程序之間相I T-L 通信。S pring Cloud Bus 可選的消息代理組建包括RabbitMQ 、AMQP 和

Kafka 等。本節講述的是用RabbitMQ 作為Spring Cloud 的消息組件去刷新更改微服務的配置

文件。

九、服務鏈路追蹤

分布式配置中心S pring Cloud Config

口Config Server 從本地讀取配置文件。

spring:

cloud :

config :

server :

native :

search-locations: classpath : /shared

profiles :

active : native

application :

name : config- server

server :

port : 8769

Config Server 可以從本地倉庫讀取配置文件,也可以從遠處Git 倉庫讀取。本地倉庫是指

將所有的配置文件統一寫在Config Server 工程目錄下。Config Sever 暴露HttpAPI 接口, Config

Client 通過調用Config Sever 的H即API 接口來讀取配置文件。

為了講解得更清楚,本章將不在之前章節的工程的基礎上改造,而是重新建工程。和之前的工程一樣,采用多Mo dule 形式。

口Config Server 從遠程Git 倉庫讀取配置文件。

spring :

application :

name : config-client

cloud :

config :

uri: http : //localhost : 8769

fail-fast : true

profi les :

active : dev

Spring Cloud Config 支持從遠程Git 倉庫讀取配置文件,即Config Server 可以不從本地的

倉庫讀取,而是從遠程Git 倉庫讀取。這樣做的好處就是將配置統一管理,并且可以通過Spring

Cloud Bus 在不人工啟動程序的情況下對Config Client 的配置進行刷新。本例采用GitHub 作為

遠程Git 倉庫。

口搭建高可用Config Server 集群。

當服務實例很多時,所有的服務實例需要同時從配置中心

Config Server 讀取配置文件,這時可以考慮將配置中心Config Server 做成一個微服務,并且將

其集群化,從而達到高可用。配置中心C onfig Server 高可用的架構圖如圖10-1 所示。C onfig

Server 和Config Client 向Eureka Server 注冊,且將Config Server 多實例集群部署。

口使用Spring Cloud Bus 刷新配置。

Spring Cloud Bus 是用輕量的消息代理將分布式的節點連接起來,可以用于廣播配置文件

的更改或者服務的監控管理。)個關鍵的思想就是,消息總線可以為微服務做監控,也可以實現應用程序之間相I T-L 通信。S pring Cloud Bus 可選的消息代理組建包括RabbitMQ 、AMQP 和

Kafka 等。本節講述的是用RabbitMQ 作為Spring Cloud 的消息組件去刷新更改微服務的配置

文件。

如果有幾十個微服務,而每一個服務又是多實例,當更改配置時,需要重新啟動多個微服

務實例,會非常麻煩。Spring Cloud Bus 的一個功能就是讓這個過程變得簡單,當遠程Git 倉

庫的配置更改后,只需要向某一個微服務實例發送一個Post 請求,通過消息組件通知其他微

服務實例重新拉取配置文件。如圖10-3 所示,當遠程Git 倉庫的配置更改后,通過發送

“ /bus/refresh ” Post 請求給某一個微服務實例,通過消息組件,通知其他微服務實例,更新配

置文件。

十、微服務監控

十一、SpringSecurity


關注個人技術公眾號:nick_coding1024

不定期分享最新前沿技術框架和bat大廠常用技術等,加群不定期分享行業內大牛直播講課以及獲得內退一線互聯網公司機會。

---------------------CSDN技術博客

原文:https://blog.csdn.net/xuri24/article/details/81742534

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容