跟我學SpringCloud | 第九篇:服務閘道器Zuul初
SpringCloud系列教程 | 第九篇:服務閘道器Zuul初探
前面的文章我們介紹了,Eureka用於服務的註冊於發現,Feign支援服務的呼叫以及均衡負載,Hystrix處理服務的熔斷防止故障擴散,Spring Cloud Config服務叢集配置中心,似乎一個微服務框架已經完成了。
我們還是少考慮了一個問題,外部的應用如何來訪問內部各種各樣的微服務呢?在微服務架構中,後端服務往往不直接開放給呼叫端,而是通過一個API閘道器根據請求的url,路由到相應的服務。當新增API閘道器後,在第三方呼叫端和服務提供方之間就建立了一面牆,這面牆直接與呼叫方通訊進行許可權控制,後將請求均衡分發給後臺服務端。
一個簡單的微服務架構已經躍然紙面:
在Spring Cloud微服務系統中,一種常見的負載均衡方式是,客戶端的請求首先經過負載均衡(zuul、Ngnix、F5),再到達服務閘道器(zuul叢集),然後再到具體的服務,服務統一註冊到高可用的服務註冊中心叢集,服務的所有的配置檔案由配置服務管理,配置服務的配置檔案放在git倉庫,方便開發人員隨時改配置。
1. 為什麼需要API Gateway?
1.1 簡化客戶端呼叫複雜度
在微服務架構模式下後端服務的例項數一般是動態的,對於客戶端而言很難發現動態改變的服務例項的訪問地址資訊。因此在基於微服務的專案中為了簡化前端的呼叫邏輯,通常會引入API Gateway作為輕量級閘道器,同時API Gateway中也會實現相關的認證邏輯從而簡化內部服務之間相互呼叫的複雜度。
1.2 資料裁剪以及聚合
通常而言不同的客戶端對於顯示時對於資料的需求是不一致的,比如手機端或者Web端又或者在低延遲的網路環境或者高延遲的網路環境。
因此為了優化客戶端的使用體驗,API Gateway可以對通用性的響應資料進行裁剪以適應不同客戶端的使用需求。同時還可以將多個API呼叫邏輯進行聚合,從而減少客戶端的請求數,優化客戶端使用者體驗
1.3 多渠道支援
當然我們還可以針對不同的渠道和客戶端提供不同的API Gateway,對於該模式的使用由另外一個大家熟知的方式叫Backend for front-end, 在Backend for front-end模式當中,我們可以針對不同的客戶端分別建立其BFF,進一步瞭解BFF可以參考這篇文章:Pattern: Backends For Frontends
1.4 遺留系統的微服務化改造
對於系統而言進行微服務改造通常是由於原有的系統存在或多或少的問題,比如技術債務,程式碼質量,可維護性,可擴充套件性等等。API Gateway的模式同樣適用於這一類遺留系統的改造,通過微服務化的改造逐步實現對原有系統中的問題的修復,從而提升對於原有業務響應力的提升。通過引入抽象層,逐步使用新的實現替換舊的實現。
在Spring Cloud體系中, Spring Cloud Zuul就是提供負載均衡、反向代理、許可權認證的一個API gateway。
在開始聊Zuul如何使用之前,先講一個比較有意思的事情,就是在springcloud元件中,服務閘道器這個元件,springcloud提供了兩種選擇,一個是netflix公司開源的Zuul,還有一個是springcloud自己開源的Spring Cloud Gateway,具體這兩個元件的恩怨情仇,在後面的Spring Cloud Gateway的文章中我們再細聊:)
2. Spring Cloud Zuul
2.1 簡單使用
Spring Cloud Zuul路由是微服務架構的不可或缺的一部分,提供動態路由,監控,彈性,安全等的邊緣服務。Zuul是Netflix出品的一個基於JVM路由和服務端的負載均衡器。
下面我們來看一下Zuul最簡單的使用方式,建立zuul-simple工程
2.1 pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.springcloud</groupId>
<artifactId>zuul-simple</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>zuul-simple</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR1</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
引入spring-cloud-starter-netflix-zuul包
2.2 配置檔案application.yml
server:
port: 8080
spring:
application:
name: spring-cloud-zuul
zuul:
routes:
baidu:
path: /baidu/**
url: https://www.baidu.com/
這裡的配置表示,訪問/baidu/** 直接重定向到https://www.baidu.com/**
如果直接訪問http://localhost:8080/baidu,則會直接跳轉到https://www.baidu.com/。
2.3 啟動類
package com.springcloud.zuulsimple;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@SpringBootApplication
@EnableZuulProxy
public class ZuulSimpleApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulSimpleApplication.class, args);
}
}
啟動類新增@EnableZuulProxy,支援閘道器路由。
史上最簡單的zuul案例就配置完了
2.4 測試
啟動專案,在瀏覽器訪問http://localhost:8080/baidu/,我們可以看到頁面已經跳轉到百度首頁。
再嘗試訪問http://localhost:8080/baidu/aa,我們可以看到頁面跳轉至:https://www.baidu.com/search/error.html, 因為https://www.baidu.com/aa 這個連結不存在, 所以百度幫我們跳轉到的error頁面。
至此,Zuul簡單使用已經介紹完畢,下面我們來聊一下服務化的方式。
2.2 服務化
通過url對映的方式來實現Zuul的轉發有侷限性,比如每增加一個服務就需要配置一條內容,另外後端的服務如果是動態來提供,就不能採用這種方案來配置了。實際上在實現微服務架構時,服務名與服務例項地址的關係在eureka server中已經存在了,所以只需要將Zuul註冊到eureka server上去發現其他服務,就可以實現對serviceId的對映。
我們結合示例來說明,在上面示例專案基礎上來進行改造
2.2.1 新增依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
增加spring-cloud-starter-netflix-eureka-client包,新增對eureka的支援。
2.2.2 配置檔案application.yml
server:
port: 8080
spring:
application:
name: spring-cloud-zuul
zuul:
routes:
api-producer:
path: /producer/**
serviceId: spring-cloud-producer
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
在這裡我們增加了對服務的支援,這裡的Zuul配置的含義為訪問/producer/**,轉向到eureka上面serviceId為spring-cloud-producer的服務。
2.2.3 測試
先從上一篇的專案中copy Eureka到本篇的資料夾中,再從第五篇的專案中copy一個producer到本篇的資料夾中。
依次啟動eureka,producer和Zuul.
我們開啟瀏覽器訪問:http://localhost:8080/producer/hello?name=spring, 可以看到頁面正常顯示producer的響應:hello spring,producer is ready。說明通過zuul成功呼叫了producer服務。
這裡producer可以啟動兩個服務,多次重新整理http://localhost:8080/producer/hello?name=spring, 可以看到Zuul對服務的呼叫是負載均衡的。
2.3 閘道器的預設路由
但是如果後端服務多達十幾個的時候,每一個都這樣配置也挺麻煩的,spring cloud zuul已經幫我們做了預設配置。預設情況下,Zuul會代理所有註冊到Eureka Server的微服務,並且Zuul的路由規則如下:http://ZUUL_HOST:ZUUL_PORT/微服務在Eureka上的serviceId/**會被轉發到serviceId對應的微服務。
我們登出掉zuul-simple配置檔案中有關路由的配置。
#zuul:
# routes:
# api-producer:
# path: /producer/**
# serviceId: spring-cloud-producer
再次啟動Zuul。
我們在瀏覽器中訪問http://localhost:8080/spring-cloud-producer/hello?name=spring,可以看到和上面一樣的返回結果,說明Spring cloud zuul預設已經提供了轉發功能。
到此zuul的基本使用我們就聊完了。關於zuul高階使用,我們下篇再來介紹。
示例程式碼-Github
參考:
http://www.ityouknow.com/springcloud/2017/06/01/gateway-service-zuul.html
https://www.fangzhipeng.com/springcloud/2018/08/05/sc-f5-zuul.html