基於Spring Cloud的微服務落地

clipboard.png

微服務架構模式的核心在於如何識別服務的邊界,設計出合理的微服務。但若是要將微服務架構運用到生產項目上,而且可以發揮該架構模式的重要做用,則須要微服務框架的支持。前端

在Java生態圈,目前使用較多的微服務框架就是集成了包括Netfilix OSS以及Spring的Spring Cloud。它包括:git

Spring Cloud Config:配置管理工具,支持使用Git存儲配置內容,能夠實現應用配置的外部化存儲,支持客戶端配置信息刷新、加密/解密配置內容等。
Spring Cloud Netflix:對Netflix OSS進行了整合。其中又包括:算法

  • Eureka:服務治理組件,包含服務註冊中心、服務註冊與發現。
  • Hystrix:容器管理組件,實現斷路器模式,假若依賴的服務出現延遲或故障,則提供強大的容錯功能。
  • Ribbon:客戶端負載均衡的服務調用組件。
  • Feign:基於Ribbon和Hystrix的聲明式服務調用組件。
  • Zuul:網關組件,提供智能路由、訪問過濾等功能。
  • Archaius:外部化配置組件。
  • Spring Cloud Bus:事件、消息總線。
  • Spring Cloud Cluster:針對ZooKeeper、Redis、Hazelcast、Consul的選舉算法和通用狀態模式的實現。
  • Spring Cloud Cloudfoundry:與Pivotal Cloudfoundry的整合支持。
  • Spring Cloud Consul:服務發現與配置管理工具。
  • Spring Cloud Stream:經過Redis、Rabbit或者Kafka實現的消息驅動的微服務。
  • Spirng Cloud AWS:簡化和整合Amazon Web Service。
  • Spring Cloud Security:安全工具包,提供Zuul代理中對OAuth2客戶端請求的中繼器。
  • Spring Cloud Sleuth:Spring Cloud應用的分佈式跟蹤實現,能夠整合Zipkin。
  • Spring Cloud ZooKeeper:基於ZooKeeper的服務發現與配置管理組件。
  • Spring Cloud Starters:Spring Cloud的基礎組件,是基於Spring Boot風格項目的基礎依賴模塊。
  • Spring Cloud CLI:用於在Groovy中快速建立Spring Cloud應用的Spring Boot CLI插件。

服務治理

當一個系統的微服務數量愈來愈多的時候,咱們就須要對服務進行治理,提供統一的服務註冊中心,而後在其框架下提供發現服務的功能。這樣就避免了對多個微服務的配置,以及微服務之間以及與客戶端之間的耦合。spring

Spring Cloud Eureka是對Netflix Eureka的包裝,用以實現服務註冊與發現。Eureka服務端即服務註冊中心,支持高可用配置。它依託於強一致性提供良好的服務實例可用性,並支持集羣模式部署。Eureka客戶端則負責處理服務的註冊與發現。客戶端服務經過annotation與參數配置的方式,嵌入在客戶端應用程序代碼中。在運行應用程序時,Eureka客戶端向註冊中心註冊自身提供的服務,並週期性地發送心跳更新它的服務租約。json

搭建服務註冊中心bootstrap

服務註冊中心是一個獨立部署的服務(你能夠認爲它也是一個微服務),因此須要單獨爲它建立一個項目,並在pom.xml中添加Eureka的依賴:後端

clipboard.png

建立Spring Boot Application:緩存

clipboard.png

註冊服務提供者安全

要讓本身編寫的微服務可以註冊到Eureka服務器中,須要在服務的Spring Boot Application中添加 @EnableDiscoveryClient 註解,如此才能讓Eureka服務器發現該服務。固然,pom.xml文件中也須要添加相關依賴:性能優化

clipboard.png

同時,咱們還須要爲服務命名,並指定地址。這些信息均可以在application.properties配置文件中配置:

clipboard.png

說明:Spring更推薦使用yml文件來維護系統的配置,yml文件能夠體現出配置節的層次關係,表現力比單純的key-value形式更好。若是結合使用後面講到的Spring Cloud Config,則客戶端的配置文件必須命名爲bootstrap.properties或者bootstrap.yml。與上述配置相同的yml文件配置爲:

clipboard.png

服務發現與消費

在微服務架構下,許多微服務可能會扮演雙重身份。一方面它是服務的提供者,另外一方面它又多是服務的消費者。註冊在Eureka Server中的微服務可能會被別的服務消費。此時,就至關於在服務中建立另外一個服務的客戶端,並經過RestTemplate發起對服務的調用。爲了更好地提升性能,能夠在服務的客戶端引入Ribbon,做爲客戶端負載均衡。

如今假定咱們要爲demo-service建立一個服務消費者demo-consumer。該消費者自身也是一個Spring Boot微服務,同時也可以被Eureka服務器註冊。這時,就須要在該服務的pom.xml中添加eureka與ribbon的依賴:

clipboard.png

而後在主應用類 ConosumerApplication 中注入 RestTemplate ,並引入 @LoadBalanced 註解開啓客戶端負載均衡:

clipboard.png

假設消費demo-service的客戶端代碼寫在demo-consumer服務的其中一個Controller中:

clipboard.png

經過 RestTemplate 就能夠發起對demo-service的消費調用。

聲明式服務調用

經過Ribbon和Hystrix能夠實現對微服務的調用以及容錯保護,但Spring Cloud還提供了另外一種更簡單的聲明式服務調用方式,即Spring Cloud Feign。Feign實際上就是對Ribbon與Hystrix的進一步封裝。經過Feign,咱們只需建立一個接口並用annotation的方式配置,就能夠完成對服務供應方的接口(REST API)綁定。

假設咱們有三個服務:

  • Notification Service
  • Account Service
  • Statistics Service

服務之間的依賴關係以下圖所示:

clipboard.png

要使用Feign來完成聲明式的服務調用,須要在做爲調用者的服務中建立Client。Client經過Eureka Server調用註冊的對應服務,這樣能夠解除服務之間的耦合。結構以下圖所示:

clipboard.png

爲了使用Feign,須要對應微服務的pom.xml文件中添加以下依賴:

clipboard.png

同時,還須要在被消費的微服務Application中添加 @EnableFeignClients 註解。例如在Statistics服務的應用程序類中:

clipboard.png

因爲Account服務須要調用Statistics服務,所以須要在Account服務項目中增長對應的client接口:

clipboard.png

StatisticsServiceClient接口的 updateStatistics() 方法會調用URI爲 /statistics/{accountName} 的REST服務,且HTTP動詞爲put。這個服務其實對應就是Statistics Service中StatisticsController類中的 saveStatistics() 方法:

clipboard.png

在Account服務中,若是要調用Statistics服務,都應該經過StatisticsServiceClient接口進行調用。例如,Account服務中的AccountServiceImpl要調用 updateStatistics() 方法,就能夠在該類的實現中經過 @autowired 注入StatisticsServiceClient接口:

clipboard.png

Notification服務對Account服務的調用如法炮製。

服務容錯保護

在微服務架構中,微服務之間可能存在依賴關係,例如Notification Service會調用Account Service,Account Service調用Statistics Service。真實產品中,微服務之間的調用會更加尋常。假若上游服務出現了故障,就可能會由於依賴關係而致使故障的蔓延,最終致使整個系統的癱瘓。

Spring Cloud Hystrix經過實現斷路器(Circuit Breaker)模式以及線程隔離等功能,實現服務的容錯保護。

仍然參考前面的例子。如今系統的微服務包括:

  • 上游服務:demo-service
  • 下游服務:demo-consumer
  • Eureka服務器:eureka-server

假設上游服務可能會出現故障,爲保證系統的健壯性,須要在下游服務中加入容錯包含功能。首先須要在demo-consumer服務中添加對hystrix的依賴:

clipboard.png

而後在demo-consumer的應用程序類中加入 @EnableCircuitBreaker 開啓斷路器功能:

clipboard.png

注意:Spring Cloud提供了 @SpringCloudApplication 註解簡化如上代碼。該註解事實上已經包含了前面所述的三個註解。 @SpringCloudApplication 註解的定義以下所示:

clipboard.png

接下來,須要引入一個新的服務類來封裝hystrix提供的斷路器保護功能,主要是定義當故障發生時須要執行的回調邏輯,即代碼中指定的fallbackMethod:

clipboard.png

服務監控

微服務架構將服務的粒度分解的足夠細,這使得它在保證服務足夠靈活、足夠獨立的優點下,也帶來了管理和監控上的挑戰,服務與服務之間的依賴也變得愈來愈複雜。所以,對服務健康度和運行指標的監控就變得很是重要。

Hystrix提供了Dashboard用以監控Hystrix的各項指標信息。爲了監控整個系統的微服務,咱們須要爲Hystrix Dashboard創建一個Spring Boot微服務。在該服務項目的pom文件中,添加以下依賴:

clipboard.png

服務的Application類須要添加 @EnableHystrixDashboard ,以啓用Hystrix Dashboard功能。同時,可能須要根據實際狀況修改application.properties配置文件,例如選擇可用的端口號等。

若是要實現對集羣的監控,則須要加入Turbine。

API網關

理論上,客戶端能夠直接向每一個微服務直接發送請求。可是這種方式是存在挑戰和限制的,調用者須要知道全部端點的地址,分別對每一段信息執行http請求,而後將結果合併到客戶端。

通常而言,針對微服務架構模式的系統,採用的都是 先後端分離 的架構。爲了明顯地隔離開前端與後端的邊界,咱們一般能夠專門爲前端的消費者定義更加粗粒度的Open Service。這些Open Service是對外的RESTful API服務,能夠經過F五、Nginx等網絡設備或工具軟件實現對各個微服務的路由與負載均衡,並公開給外部的客戶端調用(注意,內部微服務之間的調用並不須要經過Open Service)。這種對外公開的Open Service一般又被稱爲邊緣服務(edge service)。

若是這些Open Service須要咱們本身去開發實現並進行服務的運維,在系統規模不斷增大的狀況下,會變得愈來愈困難。例如,當增長了新的微服務又或者IP地址發生變更時,都須要運維人員手工維護這些路由規則與服務實例列表。又例如針對全部垂直分隔的微服務,不可避免存在重用的橫切關注點,例如用戶身份認證、受權或簽名校驗等機制。咱們不能在全部微服務中都去添加這些相同的功能,由於這會形成橫切關注點的冗餘。

解決的辦法是引入API網關(API Gateway)。它是系統的單個入口點,用於經過將請求路由到適當的後端服務或者經過調用多個後端服務並聚合結果來處理請求。此外,它還能夠用於認證、insights、壓力測試、金絲雀測試(canary testing)、服務遷移、靜態響應處理和主動變換管理。Spring Cloud爲API網關提供的解決方案就是Spring Cloud Zuul,它是對Netflix Zuul的包裝。

在此我向你們推薦一個架構學習交流羣。交流學習羣號:575745314 裏面會分享一些資深架構師錄製的視頻錄像:有Spring,MyBatis,Netty源碼分析,高併發、高性能、分佈式、微服務架構的原理,JVM性能優化、分佈式架構等這些成爲架構師必備的知識體系。還能領取免費的學習資源,目前受益良多

路由規則與服務實例維護

Zuul解決路由規則與服務實例維護的方法是經過Spring Cloud Eureka。API Gateway自身就是一個Spring Boot服務,該服務自身被註冊爲Eureka服務治理下的應用,同時它會從Eureka中得到全部其餘微服務的實例信息。這樣的設計符合DRY原則,由於Eureka已經維護了一套服務實例信息,Zuul直接重用了這些信息,無需人工介入。

對於路由規則,Zuul默認會將服務名做爲ContextPath建立路由映射,基本上這種路由映射機制就能夠知足微服務架構的路由需求。假若須要一些特殊的配置,Zuul也容許咱們自定義路由規則,能夠經過在API網關的Application類中建立PatternServiceRouteMapper來定義本身的規則。

橫切關注點

諸如受權認證、簽名校驗等業務邏輯自己與微服務應用所要處理的業務邏輯沒有直接關係,咱們將這些可能橫跨多個微服務的功能稱爲「橫切關注點」。這些橫切關注點每每會做爲「裝飾」功能在服務方法的先後被調用。Spring Cloud Zuul提供了一套 過濾器機制 ,容許開發者建立各類過濾器,並指定哪些規則的請求須要執行哪一個過濾器。

自定義的過濾器繼承自ZuulFilter類。例如咱們要求客戶端發過來的請求在路由以前須要先驗證請求中是否包含accessToken參數,若是有就進行路由,不然就拒絕,並返回401 Unauthorized錯誤,則能夠定義AccessFilter類:

clipboard.png

要讓該自定義過濾器生效,還須要在Zuul服務的Application中建立具體的Bean:

clipboard.png

Zuul一共提供了四種過濾器:

  • pre filter
  • routing filter
  • post filter
  • error filter

下圖來自官網,它展示了客戶端請求到達Zuul API網關的生命週期與過濾過程:

clipboard.png

經過starter添加Zuul的依賴時,自身包含了spring-cloud-starter-hystrix與spring-cloud-starter-ribbon模塊的依賴,所以Zuul自身就擁有線程隔離與斷路器的服務容錯功能,以及客戶端負載均衡。可是,假若咱們使用path與url的映射關係來配置路由規則,則路由轉發的請求並不會採用HystrixCommand來包裝,於是這類路由是沒有服務容錯與客戶端負載均衡做用的。因此在使用Zuul時,應儘可能使用path和serviceId的組合對路由進行配置。

分佈式配置中心

爲何要引入一個分佈式配置中心?一個微服務就須要至少一個配置文件,怎麼管理分散在各個微服務中的配置文件呢?若是微服務採用的是不一樣的技術棧,如何來統一微服務的配置呢?微服務是部署在不一樣的節點中,顯然咱們沒法在單機中實現對分佈式節點的配置管理。這就是引入Spring Cloud Config的目的。

Spring Cloud Config提供了服務端和客戶端支持。服務端是一個獨立的微服務,一樣能夠註冊到Eureka服務器中。每一個須要使用分佈式配置中心的微服務都是Spring Cloud Config的客戶端。Spring Cloud Config默認實現基於Git倉庫,既能夠進行版本管理,還能夠經過本地Git庫起到緩存做用。Spring Cloud Config不限於基於Spring Cloud開發的系統,而是能夠用於任何語言開發的程序,並支持自定義實現。

配置中心服務端

Spring Cloud Config Server做爲配置中心服務端,提供以下功能:

  • 拉取配置時更新git倉庫副本,保證是最新結果
  • 支持數據結構豐富,yml, json, properties等
  • 配合Eureke可實現服務發現,配合cloud bus可實現配置推送更新
  • 配置存儲基於git倉庫,可進行版本管理
  • 簡單可靠,有豐富的配套方案

創建一個Config服務,須要添加以下依賴:

clipboard.png

服務的Application類須要添加 @EnableConfigServer 註解:

clipboard.png

配置服務的基本信息和Git倉庫的信息放在application.yml文件中:

clipboard.png

Git庫與配置服務

在Config服務中配置了Git服務器以及Git庫的信息後,咱們就能夠在git庫中提交配置文件。存儲在git庫中配置文件的名字以及分支名(默認爲master分支)會組成訪問Config服務的URI。假設有一個服務爲Notification服務,則它在配置中心服務端的配置文件爲notification-dev.yml,內容以下:

clipboard.png

配置中心客戶端

須要讀取配置中心服務端信息的微服務都是配置中心的客戶端,爲了可以讀取配置服務端的信息,這些微服務須要:

  • 在pom中添加對spring-cloud-starter-config的依賴
  • 在bootstrap.properties或者bootstrap.yml中配置獲取配置的config-server位置

例如,Account服務的配置是由Spring Cloud Config進行管理的。在它的資源目錄下,提供了bootstrap.yml配置文件,內容以下所示:

clipboard.png

注意,該配置文件除了配置了該Account服務應用的name以外,主要是支持該應用得到配置服務端的信息。微服務自身的配置信息則統一放到配置中心服務端的文件中,並由Git庫進行管理。例如,Account服務的詳細配置在配置中心服務端的account-dev.yml文件中:

clipboard.png

Spring Cloud Config經過Git實現分佈式的配置管理。當配置中心服務端的配置信息發生變動時,各個做爲配置客戶端的微服務會向Git庫提交pull更新,得到最新的配置信息。

固然,Spring Cloud Config還可使用SVN庫進行配置管理,也支持簡單的本地文件系統的存儲方式。此時須要將 spring.profiles.active 設置爲native,並設置搜索配置文件的路徑。若是不配置路徑,默認在 src/main/resources 目錄下搜索。以下配置文件:

clipboard.png

搜索路徑放在classpath下的shared目錄下,那麼在代碼中,目錄就是 resources/shared 。若是使用本地文件系統管理配置文件,則沒法支持分佈式配置管理以及版本管理,所以在生產系統下,仍是推薦使用Git庫的方式。

在此我向你們推薦一個架構學習交流羣。交流學習羣號:575745314 裏面會分享一些資深架構師錄製的視頻錄像:有Spring,MyBatis,Netty源碼分析,高併發、高性能、分佈式、微服務架構的原理,JVM性能優化、分佈式架構等這些成爲架構師必備的知識體系。還能領取免費的學習資源,目前受益良多

總結

在實施微服務時,咱們能夠將微服務視爲兩個不一樣的邊界。一個是與前端UI的通訊,稱爲Open Service(Edge Service),經過引入API Gateway來實現與前端UI的通訊。另外一個是在邊界內業務微服務之間的通訊,經過Feign實現微服務之間的協做。全部的微服務都會經過Eureka來完成微服務的註冊與發現。一個典型的基於Spring Cloud的微服務架構以下所示:

clipboard.png

微服務的集成能夠經過Feign+Ribbon以RESTful方式實現通訊,也能夠基於RPC方式(能夠結合Protocol Buffer)完成服務之間的通訊,甚至能夠經過發佈事件與訂閱事件的機制。事件機制可使微服務之間更加鬆散耦合。這時,咱們能夠引入RabbitMQ或Kafka來作到服務與服務之間的解耦。事件機制是異步和非阻塞的,在某些業務場景下,它的性能會更加的好。Spring Cloud也提供了相關的組件Spring Cloud Stream來支持這種事件機制。

對於微服務之間的協做,到底選擇Feign這種REST方式、事件機制或者RPC方式,取決於業務場景是否須要同步方式,仍是異步方式;是高性能高併發,仍是普通方式;是要求完全解耦,仍是作到通常的鬆散耦合。咱們須要針對實際狀況做出實際的判斷,做出正確的選擇。沒有誰壞誰好之分,而是看誰更加的適合。

相關文章
相關標籤/搜索