javascript
Spring Cloud H (五)服务网关 GateWay
目錄
前言
一、概述
微服務中網關的位置
GateWay的特性
Zuul 1.x模型
Gateway模型
二、GateWay詳解
三大核心概念
Gateway工作流程——核心邏輯:路由轉發 + 執行過濾器鏈。
配置路由的第一種方式
配置路由的第二種方式
GateWay配置動態路由
GateWay常用的Predicate
GateWay的Filter
前言
近些年,為了應對日益復雜的業務場景,網關選型成為了各大互聯網公司的一個技術關切點。而 Spring Cloud GateWay?作為微服務的入口,地位可見一斑。它集成了對負載均衡,動態路由,訪問控制,限流熔斷,埋點監控等功能的支持,旨在為微服務架構提供一種簡單有效的、統一的 API 路由管理方式。
SpringCloud Gateway作為Spring Cloud 生態系統中的網關,目標是替代Zuul,在Spring Cloud 2.0以上版本中,沒有對新版本的Zul 2.0以上最新高性能版本進行集成,仍然還是使用的Zuul 1.x非Reactor模式的老版本。而為了提升網關的性能,SpringCloud Gateway是基于WebFlux框架實現的,而WebFlux框架底層則使用了高性能的Reactor模式通信框架Netty。
?
GateWay官方網站
一、概述
微服務中網關的位置
GateWay的特性
基于Spring Framework 5,Project Reactor和Spring Boot 2.0進行構建;
動態路由:能夠匹配任何請求屬性;
可以對路由指定Predicate (斷言)和Filter(過濾器);
集成Hystrix的斷路器功能;
集成Spring Cloud 服務發現功能;
易于編寫的Predicate (斷言)和Filter (過濾器);
請求限流功能;
支持路徑重寫。
Zuul 1.x模型
Springcloud中所集成的Zuul版本,采用的是Tomcat容器,使用的是傳統的Serviet IO處理模型。
Servlet的生命周期?servlet由servlet container進行生命周期管理。
container啟動時構造servlet對象并調用servlet init()進行初始化;
container運行時接受請求,并為每個請求分配一個線程(一般從線程池中獲取空閑線程)然后調用service);
container關閉時調用servlet destory()銷毀servlet。
上述模式的缺點:
Servlet是一個簡單的網絡IO模型,當請求進入Servlet container時,Servlet container就會為其綁定一個線程,在并發不高的場景下這種模型是適用的。但是一旦高并發(如抽風用Jmeter壓),線程數量就會上漲,而線程資源代價是昂貴的(上線文切換,內存消耗大)嚴重影響請求的處理時間。在一些簡單業務場景下,不希望為每個request分配一個線程,只需要1個或幾個線程就能應對極大并發的請求,這種業務場景下servlet模型沒有優勢。
所以Zuul 1.X是基于servlet之上的一個阻塞式處理模型,即Spring實現了處理所有request請求的一個servlet (DispatcherServlet)并由該servlet阻塞式處理處理。所以SpringCloud Zuul無法擺脫servlet模型的弊端。
Gateway模型
傳統的Web框架,比如說: Struts2,SpringMVC等都是基于Servlet APl與Servlet容器基礎之上運行的。
但是在Servlet3.1之后有了異步非阻塞的支持。而WebFlux是一個典型非阻塞異步的框架,它的核心是基于Reactor的相關API實現的。相對于傳統的web框架來說,它可以運行在諸如Netty,Undertow及支持Servlet3.1的容器上。非阻塞式+函數式編程(Spring 5必須讓你使用Java 8)。
Spring WebFlux是Spring 5.0 引入的新的響應式框架,區別于Spring MVC,它不需要依賴Servlet APl,它是完全異步非阻塞的,并且基于Reactor來實現響應式流規范。
Spring Cloud Gateway requires the Netty runtime provided by Spring Boot and Spring Webflux. It does not work in a traditional Servlet Container or when built as a WAR
?同步、異步、阻塞、非阻塞IO總結
二、GateWay詳解
三大核心概念
Route(路由) - 路由是構建網關的基本模塊,它由ID,目標URI,一系列的斷言和過濾器組成,如斷言為true則匹配該路由;
Predicate(斷言) - 參考的是Java8的java.util.function.Predicate,開發人員可以匹配HTTP請求中的所有內容(例如請求頭或請求參數),如果請求與斷言相匹配則進行路由;
Filter(過濾) - 指的是Spring框架中GatewayFilter的實例,使用過濾器,可以在請求被路由前或者之后對請求進行修改。
web請求,通過一些匹配條件,定位到真正的服務節點。并在這個轉發過程的前后,進行一些精細化控制。
predicate就是我們的匹配條件;而fliter,就可以理解為一個無所不能的攔截器。有了這兩個元素,再加上目標uri,就可以實現一個具體的路由了
Gateway工作流程——核心邏輯:路由轉發 + 執行過濾器鏈。
?Clients make requests to Spring Cloud Gateway. If the Gateway Handler Mapping determines that a request matches a route, it is sent to the Gateway Web Handler. This handler runs the request through a filter chain that is specific to the request. The reason the filters are divided by the dotted line is that filters can run logic both before and after the proxy request is sent. All “pre” filter logic is executed. Then the proxy request is made. After the proxy request is made, the “post” filter logic is run.
客戶端向Spring Cloud Gateway發出請求。然后在Gateway Handler Mapping 中找到與請求相匹配的路由,將其發送到GatewayWeb Handler。Handler再通過指定的過濾器鏈來將請求發送到我們實際的服務執行業務邏輯,然后返回。過濾器之間用虛線分開是因為過濾器可能會在發送代理請求之前(“pre”)或之后(“post")執行業務邏輯。Filter在“pre”類型的過濾器可以做參數校驗、權限校驗、流量監控、日志輸出、協議轉換等,在“post”類型的過濾器中可以做響應內容、響應頭的修改,日志的輸出,流量監控等有著非常重要的作用。
配置路由的第一種方式
Gateway9527搭建
(1)建moudle——Module - cloud-gateway-gateway9527
(2)改pom
<?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"><parent><artifactId>LearnCloud</artifactId><groupId>com.lun.springcloud</groupId><version>1.0.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>cloud-gateway-gateway9527</artifactId><dependencies><!--gateway--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency><!--eureka-client--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><!-- 引入自己定義的api通用包,可以使用Payment支付Entity --><dependency><groupId>com.lun.springcloud</groupId><artifactId>cloud-api-commons</artifactId><version>${project.version}</version></dependency><!--一般基礎配置類--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies></project>(3)YML
server:port: 9527spring:application:name: cloud-gatewayeureka:instance:hostname: cloud-gateway-serviceclient: #服務提供者provider注冊進eureka服務列表內service-url:register-with-eureka: truefetch-registry: truedefaultZone: http://eureka7001.com:7001/eureka(4)主啟動
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient;@SpringBootApplication @EnableEurekaClient public class GateWayMain9527 {public static void main(String[] args) {SpringApplication.run(GateWayMain9527.class, args);} }(5)業務類
無
我們目前不想暴露8001端口,希望在8001外面套一層9527
更改YML
server:port: 9527spring:application:name: cloud-gateway #############################新增網關配置###########################cloud:gateway:routes:- id: payment_routh #payment_route #路由的ID,沒有固定規則但要求唯一,建議配合服務名uri: http://localhost:8001 #匹配后提供服務的路由地址#uri: lb://cloud-payment-service #匹配后提供服務的路由地址predicates:- Path=/payment/get/** # 斷言,路徑相匹配的進行路由- id: payment_routh2 #payment_route #路由的ID,沒有固定規則但要求唯一,建議配合服務名uri: http://localhost:8001 #匹配后提供服務的路由地址#uri: lb://cloud-payment-service #匹配后提供服務的路由地址predicates:- Path=/payment/lb/** # 斷言,路徑相匹配的進行路由 ####################################################################eureka:instance:hostname: cloud-gateway-serviceclient: #服務提供者provider注冊進eureka服務列表內service-url:register-with-eureka: truefetch-registry: truedefaultZone: http://eureka7001.com:7001/eureka測試:
先啟動7001,8001,9527網關
添加網關前 - http://localhost:8001/payment/get/1
添加網關后 - http://localhost:9527/payment/get/1
兩者訪問成功,返回相同結果
配置路由的第二種方式
代碼中注入RouteLocator的Bean
業務類實現
import org.springframework.cloud.gateway.route.RouteLocator; import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;@Configuration public class GateWayConfig {@Beanpublic RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder){RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();routes.route("path_route_atguigu",r -> r.path("/guonei").uri("http://news.baidu.com/guonei")).build();return routes.build();} }測試
瀏覽器輸入http://localhost:9527/guonei,返回http://news.baidu.com/guonei相同的頁面。
GateWay配置動態路由
默認情況下Gateway會根據注冊中心注冊的服務列表,以注冊中心上微服務名為路徑創建動態路由進行轉發,從而實現動態路由的功能(不寫死一個地址)。
改pom
<!--eureka-client--> <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>寫yml
需要注意的是uri的協議為lb,表示啟用Gateway的負載均衡功能。
lb://serviceName是spring cloud gateway在微服務中自動為我們創建的負載均衡uri。
server:port: 9527spring:application:name: cloud-gateway #############################新增網關配置###########################cloud:gateway:discovery:locator:enabled: true #開啟從注冊中心動態創建路由的功能,利用微服務名進行路由routes:- id: payment_routh #payment_route #路由的ID,沒有固定規則但要求唯一,建議配合服務名#uri: http://localhost:8001 #匹配后提供服務的路由地址uri: lb://cloud-payment-service #匹配后提供服務的路由地址predicates:- Path=/payment/get/** # 斷言,路徑相匹配的進行路由- id: payment_routh2 #payment_route #路由的ID,沒有固定規則但要求唯一,建議配合服務名#uri: http://localhost:8001 #匹配后提供服務的路由地址uri: lb://cloud-payment-service #匹配后提供服務的路由地址predicates:- Path=/payment/lb/** # 斷言,路徑相匹配的進行路由 ####################################################################eureka:instance:hostname: cloud-gateway-serviceclient: #服務提供者provider注冊進eureka服務列表內service-url:register-with-eureka: truefetch-registry: truedefaultZone: http://eureka7001.com:7001/eureka測試
瀏覽器輸入 - http://localhost:9527/payment/lb
結果
不停刷新頁面,8001/8002兩個端口切換。
GateWay常用的Predicate
Route Predicate Factories是什么
Spring Cloud Gateway matches routes as part of the Spring WebFlux HandlerMapping infrastructure. Spring Cloud Gateway includes many built-in route predicate factories. All of these predicates match on different attributes of the HTTP request. You can combine multiple route predicate factories with logical and statements.
Spring Cloud Gateway將路由匹配作為Spring WebFlux HandlerMapping基礎架構的一部分。Spring Cloud Gateway包括許多內置的Route Predicate工廠。所有這些Predicate都與HTTP請求的不同屬性匹配。多個RoutePredicate工廠可以進行組合。Spring Cloud Gateway創建Route 對象時,使用RoutePredicateFactory 創建 Predicate對象,Predicate 對象可以賦值給Route。Spring Cloud Gateway包含許多內置的Route Predicate Factories。所有這些謂詞都匹配HTTP請求的不同屬性。多種謂詞工廠可以組合,并通過邏輯and。
常用的Route Predicate Factory
The After Route Predicate Factory
The Before Route Predicate Factory
The Between Route Predicate Factory
The Cookie Route Predicate Factory
The Header Route Predicate Factory
The Host Route Predicate Factory
The Method Route Predicate Factory
The Path Route Predicate Factory
The Query Route Predicate Factory
The RemoteAddr Route Predicate Factory
The weight Route Predicate Factory.
The After Route Predicate Factory
spring:cloud:gateway:routes:- id: after_routeuri: https://example.orgpredicates:# 這個時間后才能起效- After=2017-01-20T17:42:47.789-07:00[America/Denver]可以通過下述方法獲得上述格式的時間戳字符串
import java.time.ZonedDateTime;public class T2 {public static void main(String[] args){ZonedDateTime zbj = ZonedDateTime.now(); // 默認時區System.out.println(zbj);//2021-02-22T15:51:37.485+08:00[Asia/Shanghai]} }The Cookie Route Predicate Factory
spring:cloud:gateway:routes:- id: cookie_routeuri: https://example.orgpredicates:#Cokkie中帶有下面內容才生效- Cookie=chocolate, ch.pGateWay的Filter
Route filters allow the modification of the incoming HTTP request or outgoing HTTP response in some manner. Route filters are scoped to a particular route. Spring Cloud Gateway includes many built-in GatewayFilter Factories.
路由過濾器可用于修改進入的HTTP請求和返回的HTTP響應,路由過濾器只能指定路由進行使用。Spring Cloud Gateway內置了多種路由過濾器,他們都由GatewayFilter的工廠類來產生。
Spring Cloud Gateway的Filter:
-
生命周期:
- pre
- post
-
種類(具體看官方文檔):官方文檔
- GatewayFilter - 有31種——主要是配置在yml文件中
- GlobalFilter - 有10種——主要是使用兩個接口
?GlobalFilter的案例分析
import lombok.extern.slf4j.Slf4j; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.core.Ordered; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono;import java.util.Date;@Component @Slf4j public class MyLogGateWayFilter implements GlobalFilter,Ordered {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain){log.info("***********come in MyLogGateWayFilter: "+new Date());String uname = exchange.getRequest().getQueryParams().getFirst("uname");if(uname == null){log.info("*******用戶名為null,非法用戶,o(╥﹏╥)o");exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);return exchange.getResponse().setComplete();}return chain.filter(exchange);}@Overridepublic int getOrder(){return 0;} }啟動7001,8001,9527,8002
http://localhost:9527/payment/lb - 訪問異常
http://localhost:9527/payment/lb?uname=abc - 正常訪問
總結
以上是生活随笔為你收集整理的Spring Cloud H (五)服务网关 GateWay的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 做一个简单的打飞碟游戏
- 下一篇: Spring Cloud入门+深入(十二