跟我學Spring Cloud(Finchley版)-16-Zuul

至此,已實現基於Eureka的服務發現,基於Ribbon的負載均衡,Feign也為我們提供了很不錯的遠程調用能力,使用Hystrix後,高併發場景下應用也不會被別人拖死——咱們的微服務架構已經日趨完善!

然而,迄今為止,只討論了微服務之間的調用,尚沒討論如何應對外部請求。應對外部請求時,就會發現,我們的架構依然存在一些問題——

為什麼要使用網關

不同的微服務一般會有不同的網絡地址,而外部客戶端(例如手機APP)可能需要調用多個服務的接口才能完成一個業務需求。例如一個電影購票的手機APP,可能會調用多個微服務的接口,才能完成一次購票的業務流程,如下圖所示。

跟我學Spring Cloud(Finchley版)-16-Zuul

如果讓客戶端直接與各個微服務通信,會有以下的問題:

  • 客戶端會多次請求不同的微服務,增加了客戶端的複雜性。
  • 存在跨域請求,在一定場景下處理相對複雜。
  • 認證複雜,每個服務都需要獨立認證。
  • 難以重構,隨著項目的迭代,可能需要重新劃分微服務。例如,可能將多個服務合併成一個或者將一個服務拆分成多個。如果客戶端直接與微服務通信,那麼重構將會很難實施。
  • 某些微服務可能使用了防火牆/瀏覽器不友好的協議,直接訪問會有一定的困難。

以上問題可藉助微服務網關解決。微服務網關是介於客戶端和服務器端之間的中間層,所有的外部請求都會先經過微服務網關。使用微服務網關後,架構如下所示。

跟我學Spring Cloud(Finchley版)-16-Zuul

此時,微服務網關封裝了應用程序的內部結構,客戶端只須跟網關交互,而無須直接調用特定微服務的接口。這樣,開發就可以得到簡化。不僅如此,使用微服務網關還有以下優點:

  • 易於監控。可在微服務網關收集監控數據並將其推送到外部系統進行分析。
  • 易於認證。可在微服務網關上進行認證,然後再將請求轉發到後端的微服務,而無須在每個微服務中進行認證。
  • 減少了客戶端與各個微服務之間的交互次數。

Zuul簡介

Zuul是Netflix開源的微服務網關,它可以和Eureka、Ribbon、Hystrix等組件配合使用。Zuul的核心是一系列的過濾器,這些過濾器幫助我們完成以下功能:

  • 身份認證與安全:識別每個資源的驗證要求,並拒絕那些與要求不符的請求;
  • 審查與監控:在邊緣位置追蹤有意義的數據和統計結果,從而為我們帶來精確的生產視圖;
  • 動態路由:動態地將請求路由到不同的後端集群;
  • 壓力測試:逐漸增加指向集群的流量,以瞭解性能;
  • 負載分配:為每一種負載類型分配對應容量,並棄用超出限定值的請求;
  • 靜態響應處理:在邊緣位置直接建立部分響應,從而避免其轉發到內部集群;
  • 多區域彈性:跨越AWS Region進行請求路由,旨在實現ELB(Elastic Load Balancing)使用的多樣化;以及讓系統的邊緣更貼近系統的使用者。

注1:以上介紹來自Zuul官方文檔,但其實開源版本的Zuul以上功能一個都沒有——開源的Zuul只是幾個Jar包而已,以上能力指的應該是Netflix官方自用的Zuul的能力。

注2:Netflix自用的Zuul能力是比較強大的,可使用Groovy編寫過濾器,並且可動態加載/卸載、修改規則,而且使用Cassandra作為數據庫,然而開源版本這些一個都沒有。

注3:Spring Cloud中,Zuul絕大部分功能都是Spring Cloud團隊為Zuul開發的。

注4:所以Zuul 2.x的開源進度延後一年,Spring Cloud團隊開發了自己的Spring Cloud Gateway,並宣佈Spring Cloud不打算支持Zuul 2.x,你還覺得意外嗎?

注5:看到這裡,很多人可能沒有動力學習Zuul了,個人認為還是可以瞭解一下的,後面講到Spring Cloud Gateway時,你會發現很多設計理念是相通的。

Spring Cloud對Zuul進行了整合與增強。目前,Zuul使用的默認HTTP客戶端是Apache HTTP Client,也可以使用RestClient或者okhttp3.OkHttpClient 。 如果想要使用RestClient,可以設置ribbon.restclient.enabled=true ;想要使用okhttp3.OkHttpClient ,可以設置ribbon.okhttp.enabled=true 。

TIPS

Zuul的GitHub:https://github.com/Netflix/zuul

入門

下面通過一個簡單的例子幫助大家快速入門Zuul。

編碼

  • 加依賴
<dependency>
<groupid>org.springframework.cloud/<groupid>
<artifactid>spring-cloud-starter-netflix-zuul/<artifactid>
/<dependency>
<dependency>
<groupid>org.springframework.cloud/<groupid>
<artifactid>spring-cloud-starter-netflix-eureka-client/<artifactid>
/<dependency>
  • 加註解:@EnableZuulProxy
  • 寫配置:
server:
port: 8040
spring:
application:
name: microservice-gateway-zuul
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/

由代碼可知,我們編寫了一個Zuul,並將其註冊到了Eureka上。

測試

準備工作

啟動多個應用,Eureka Server上展示如下:

跟我學Spring Cloud(Finchley版)-16-Zuul

反向代理測試

  • 訪問http://127.0.0.1:8040/microservice-provider-user/users/1 ,會發現請求被轉發到了microservice-provider-user 服務的/users/1 端點;
  • 訪問http://127.0.0.1:8040/microservice-consumer-movie/movies/users/1 ,發現請求被轉發到了microservice-consumer-movie 服務的/movies/users/1 端點;

負載均衡測試

多次訪問訪問http://127.0.0.1:8040/microservice-provider-user/users/1 ,會發現兩個microservice-provider-user 都會打印類似如下的日誌:

Hibernate: select user0_.id as id1_0_0_, user0_.age as age2_0_0_, user0_.balance as balance3_0_0_, user0_.name as name4_0_0_, user0_.username as username5_0_0_ from user user0_ where user0_.id=?
...

斷路器測試

在application.yml 中添加如下配置後,並重啟Zuul:

management:
endpoints:
web:
exposure:
include: '*'
endpoint:
health:
show-details: always

此時,此時訪問http://localhost:8040/actuator/health ,可看到類似如下結果:

{
...
"hystrix":{"status":"UP"}
}

並且,當Zuul轉發API後,訪問http://localhost:8040/actuator/hystrix.stream 可看到類似如下的信息:

data: {"type":"HystrixCommand","name":"microservice-provider-user",.....}

說明Zuul整合了Hystrix。

配套代碼

  • GitHub:https://github.com/eacdy/spring-cloud-study/tree/master/2018-Finchley/microservice-gateway-zuul
  • Gitee:https://gitee.com/itmuch/spring-cloud-study/tree/master/2018-Finchley/microservice-gateway-zuul


分享到:


相關文章: