微服務網關升級:Spring Cloud Gateway 整合 Nacos 實現服務請求自動轉發+負載均衡!
一、背景介紹
本文將繼續研究 Gateway 的更高級用法,比如整合服務注冊中心實現請求自動路由轉發、整合服務配置中心實現路由規則動態加載等。
下面我們一起來看看相關的實現思路。
二、整合注冊中心
在上篇文章中,我們介紹了在 Spring Cloud Gateway 中通過配置的方式就可實現將請求轉發到某個目標服務上。而在微服務架構中,服務中心往往注冊了很多服務,如果每個服務都進行單獨配置的話,那這份工作無疑既勞累又枯燥。
實際上,Spring Cloud Gateway 提供了一種默認轉發的能力,只要將 Spring Cloud Gateway 注冊到服務中心,Spring Cloud Gateway 默認就會自動代理服務中心的所有服務,并以服務名作為目標 URI 來自動創建動態路由。
整個服務體系的工作流程就會變成如下圖。
圖片
下面我們以 Nacos 作為服務注冊為例,通過具體的案例看看如何使用 Spring Cloud Gateway 來實現將服務請求進行轉發的效果。
在構建服務網關之前,需要先部署并啟動 Nacos,這一步比較簡單,在此就不重復介紹了。如果還不會的小伙伴,可以參考之前寫過的 Nacos 作為服務注冊中心的技術文章。
2.1、構建服務網關
使用 Spring Cloud Gateway 來構建服務網關也非常簡單,之前我們已經詳細介紹過,將之前創建的gateway-server
復制一個新服務網關工程,命名為gateway-nacos
,并在pom.xml
中引入 Nacos 注冊中心依賴包,示例如下:
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<spring-boot.version>2.2.5.RELEASE</spring-boot.version>
<spring-cloud.version>Hoxton.SR3</spring-cloud.version>
<spring-cloud-alibaba.version>2.2.3.RELEASE</spring-cloud-alibaba.version>
</properties>
<dependencies>
<!-- 引入 Spring Cloud Gateway 網關組件 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- 引入 Spring Cloud Alibaba Nacos 作為注冊中心 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<!-- 引入 springBoot 版本號 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- 引入 spring cloud 版本號 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- 引入 spring cloud alibaba 適配的版本號 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
2.2、修改配置文件
修改application.yaml
配置文件,增加 Nacos 注冊中心相關的配置項。
完整配置如下:
server:
port: 8080
spring:
application:
name: gateway-nacos
cloud:
# Spring Cloud Gateway 配置項,對應 GatewayProperties 類
gateway:
# 與 Spring Cloud 注冊中心的集成,對應 DiscoveryLocatorProperties 類
discovery:
locator:
enabled: true # 是否開啟,默認為 false 關閉
url-expression: "'lb://' + serviceId" # 路由的目標地址的表達式,默認為"'lb://' + serviceId"
nacos:
discovery:
server-addr: 127.0.0.1:8848 # Nacos 服務器地址
關鍵參數作用解讀:
nacos.discovery.server-addr
:顧名思義,使用 Nacos 作為 Spring Cloud 的服務注冊中心gateway.discovery.locator.enabled
:是否開啟與 Spring Cloud 注冊中心的集成功能,默認false
,這里需要開啟gateway.discovery.locator.url-expression
:路由的目標地址的 Spring EL 表達式,默認為"'lb://' + serviceId"
可能大家對url-expression
這個配置項不太理解,我們來舉個例子。
假設注冊中心有user-service
和order-service
兩個服務,url-expression
這個配置項最終效果和如下配置等價:
spring:
cloud:
gateway:
routes:
- id: ReactiveCompositeDiscoveryClient_user-service
uri: lb://user-service
predicates:
- Path=/user-service/**
filters:
- RewritePath=/user-service/(?<remaining>.*), /${remaining}
- id: ReactiveCompositeDiscoveryClient_order-service
uri: lb://order-service
predicates:
- Path=/order-service/**
filters:
- RewritePath=/order-service/(?<remaining>.*), /${remaining}
其中uri: lb://user-service
表達式是user-service
服務實例地址的一種簡寫,lb://
前綴表示將請求以負載均衡方式轉發到對應的目標服務實例上。
2.3、構建業務微服務
為了方便測試服務的路由效果,我們還需要創建一個 Spring Boot 服務,并將服務注冊到 Nacos,實現方式也很簡單,只需如下幾步即可完成。
首先,創建一個 SpringBoot 工程,命名為user-service
,其pom.xml
與上文類似,修改dependencies
內容,改成如下內容即可。
<dependencies>
<!-- SpringBoot web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Nacos 服務發現 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
然后,創建一個服務啟動類并添加@EnableDiscoveryClient
,將當前服務注冊到 Nacos。
@EnableDiscoveryClient
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}
接著,創建一個 web 接口,以便測試服務的轉發效果,示例如下:
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "hello,我是用戶服務";
}
}
最后,創建application.properties
配置文件中添加服務注冊中心地址,示例如下:
spring.application.name=user-service
server.port=9010
# 設置Nacos的服務地址,多個地址可使用【,】分隔
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
2.4、服務測試
將服務網關和user-service
都啟動起來,訪問 Nacos 服務控制臺,可以看到服務的注冊信息。
圖片
Spring Cloud Gateway 注冊到服務中心之后,網關會自動代理所有注冊中心的服務,訪問這些服務的方式為:
http://網關地址:端口/服務中心注冊 serviceId/具體服務接口的url
比如,訪問http://127.0.0.1:8080/user-service/hello
,它會自動轉發到user-service
服務的/hello
接口上,返回結果如下圖。
圖片
當一個服務在多個機器上部署時,服務網關會依次輪流請求,實現負載均衡的效果。
三、整合配置中心
在上文中,Spring Cloud Gateway 整合服務注冊中心之后,會自動代理所有注冊中心的服務。
但是很多時候,我們并不想通過網關把服務都暴露出去,每個服務的路由規則可能不同,會存在配置不同過濾器的情況,并且可能需要經常經常調整,這個時候如何處理呢?
此時可以借助服務配置中心,將路由規則從服務網關中抽離出來,通過配置中心實現服務網關動態加載路由規則。
Spring Cloud 支持的配置中心組件有很多,比如 Config、Apollo、Nacos 等。其中 Nacos 應用比較廣泛,因為它既可以做服務注冊中心又可以做服務配置中心。
下面我們還是以 Nacos 作為服務配置中心為例,通過具體的案例看看如何使用 Spring Cloud Gateway 來實現將路由規則動態加載效果。
3.1、構建服務網關
還是以上文的gateway-nacos
服務網關工程為例,復制一個新的服務網關工程,命名為gateway-application
,并在pom.xml
中引入 Nacos 配置中心依賴包,示例如下:
<dependencies>
<!-- 引入 Spring Cloud Gateway 網關組件 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- 引入 Spring Cloud Alibaba Nacos 作為注冊中心 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- 引入 Spring Cloud Alibaba Nacos 作為配置中心 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
</dependencies>
3.2、修改配置文件
因為Nacos
配置中心的配置項,只有在bootstrap.yaml
才能生效。
將application.yaml
文件修改成bootstrap.yaml
文件,并添加Nacos
配置中心相關的配置項。
配置內容如下:
server:
port: 8080
spring:
application:
name: gateway-application
cloud:
nacos:
# Nacos 作為注冊中心
discovery:
server-addr: 127.0.0.1:8848
# Nacos 作為配置中心,對應 NacosConfigProperties 配置屬性類
config:
server-addr: 127.0.0.1:8848 # Nacos 服務器地址
namespace: # 對應 Nacos 的命名空間,默認為 null
group: DEFAULT_GROUP # 對應 Nacos 配置分組,默認為 DEFAULT_GROUP
name: gateway-config # 對應 Nacos 配置集的 dataId,默認為 spring.application.name
file-extension: yaml
在上文中,我們配置了一個dataId
為gateway-config
,所屬分組為DEFAULT_GROUP
的配置文件。
接著,在 nacos 配置中心創建對應的配置項并發布,示例如下:
圖片
配置內容為:
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/user-service/**
filters:
- RewritePath=/user-service/(?<remaining>.*), /${remaining}
當網關啟動時會自動將 Nacos 中配置中心中的路由規則內容載入到服務容器中,并自動進行刷新。
3.3、服務測試
最后將網關服務啟動,再次訪問http://127.0.0.1:8080/user-service/hello
,會自動轉發到user-service
服務的/hello
接口上。
圖片
回到 Nacos 配置中心頁面修改路由規則,將/user-service
路徑改成/user
。
圖片
然后訪問http://127.0.0.1:8080/user/hello
,返回結果如下圖。
圖片
可以清晰的看到,服務網關中的路由規則也被動態刷新了。
四、小結
最后總結一下,Spring Cloud Gateway 是一個功能非常強大的服務網關,在微服務架構中通常與服務注冊中心和配置中心搭配使用,以此完成服務接口的統一請求轉發效果。
五、參考
1.https://www.iocoder.cn/Spring-Cloud/Spring-Cloud-Gateway/?self