小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

微服務網(wǎng)關實戰(zhàn)

 雪山紅柳 2020-01-10

導讀

作為Netflix Zuul的替代者,Spring Cloud Gateway是一款非常實用的微服務網(wǎng)關,在Spring Cloud微服務架構體系中發(fā)揮非常大的作用。本文對Spring Cloud Gateway常見使用場景進行了梳理,希望對微服務開發(fā)人員提供一些幫助。

 微服務網(wǎng)關SpringCloudGateway

1.概述

Spring cloud gateway是spring官方基于Spring 5.0、Spring Boot2.0和Project Reactor等技術開發(fā)的網(wǎng)關,Spring Cloud Gateway旨在為微服務架構提供簡單、有效和統(tǒng)一的API路由管理方式,Spring Cloud Gateway作為Spring Cloud生態(tài)系統(tǒng)中的網(wǎng)關,目標是替代Netflix Zuul,其不僅提供統(tǒng)一的路由方式,并且還基于Filer鏈的方式提供了網(wǎng)關基本的功能,例如:安全、監(jiān)控/埋點、限流等。

2.核心概念

網(wǎng)關提供API全托管服務,豐富的API管理功能,輔助企業(yè)管理大規(guī)模的API,以降低管理成本和安全風險,包括協(xié)議適配、協(xié)議轉發(fā)、安全策略、防刷、流量、監(jiān)控日志等貢呢。一般來說網(wǎng)關對外暴露的URL或者接口信息,我們統(tǒng)稱為路由信息。如果研發(fā)過網(wǎng)關中間件或者使用過Zuul的人,會知道網(wǎng)關的核心是Filter以及Filter Chain(Filter責任鏈)。Sprig Cloud Gateway也具有路由和Filter的概念。下面介紹一下Spring Cloud Gateway中幾個重要的概念。

  • 路由。路由是網(wǎng)關最基礎的部分,路由信息有一個ID、一個目的URL、一組斷言和一組Filter組成。如果斷言路由為真,則說明請求的URL和配置匹配

  • 斷言。Java8中的斷言函數(shù)。Spring Cloud Gateway中的斷言函數(shù)輸入類型是Spring5.0框架中的ServerWebExchange。Spring Cloud Gateway中的斷言函數(shù)允許開發(fā)者去定義匹配來自于http request中的任何信息,比如請求頭和參數(shù)等。

  • 過濾器。一個標準的Spring webFilter。Spring cloud gateway中的filter分為兩種類型的Filter,分別是Gateway Filter和Global Filter。過濾器Filter將會對請求和響應進行修改處理

如上圖所示,Spring cloudGateway發(fā)出請求。然后再由Gateway Handler Mapping中找到與請求相匹配的路由,將其發(fā)送到Gateway web handler。Handler再通過指定的過濾器鏈將請求發(fā)送到我們實際的服務執(zhí)行業(yè)務邏輯,然后返回。

 

 快速入門

以Spring Boot框架開發(fā)為例,啟動一個Gateway服務模塊(以Consul作為注冊中心),一個后端服務模塊。client端請求經(jīng)gateway服務把請求路由到后端服務。

前提條件:

  • Consul:版本1.5.0。

  • Spring bot:版本2.1.5。

  • Spring cloud:版本Greenwich.SR1。

  • Redis:版本5.0.5。

1.微服務開發(fā)

這里以使用Spring Boot框架開發(fā)微服務為例,啟動一個服務并注冊到Consul。

引入依賴:

  1. <dependency>
  2.     <groupId>org.springframework.cloud</groupId>
  3.     <artifactId>spring-cloud-starter-consul-discovery</artifactId>
  4. </dependency>
 

注冊服務到Consul,配置文件配置如下:

  1. spring:
  2.   application:
  3.     name: service-consumer
  4.   cloud:
  5.     consul:
  6.       host: 127.0.0.1
  7.       port: 8500
  8.       discovery:
  9.         service-name: service-consumer
 

如下定義RestController,發(fā)布HTTP接口。

  1. @RestController
  2. @RequestMapping("/user")
  3. public class UserController {
  4.     @Resource
  5.     private UserService userService;
  6.     @GetMapping(value = "/info")
  7.     public User info() {
  8.         return userService.info();
  9.     }
  10. }
 

注:此為服務端配置,經(jīng)Gateway把請求路由轉發(fā)到該服務上。

2.網(wǎng)關配置
創(chuàng)建一個Gateway服務,引入以下依賴:

  1. <dependency>
  2.     <groupId>org.springframework.cloud</groupId>
  3.     <artifactId>spring-cloud-starter-gateway</artifactId>
  4. </dependency>
  5. <dependency>
  6.     <groupId>org.springframework.cloud</groupId>
  7.     <artifactId>spring-cloud-starter-consul-discovery</artifactId>
  8. </dependency>
 

啟動類配置如下:

  1. @SpringBootApplication
  2. @EnableDiscoveryClient
  3. public class GatewayApplication {
  4.     public static void main(String[] args) {
  5.         SpringApplication.run(GatewayApplication.class, args);
  6.     }
  7. }

Spring Cloud Gateway對client端請求起到路由功能,主要配置如下:

  1. server:
  2.   port: 8098
  3. spring:
  4.   application:
  5.     name: service-gateway
  6.   cloud:
  7.     gateway:
  8.       discovery:
  9.         locator:
  10.           enabled: true   
  11.           lower-case-service-id: true  
  12.     consul:
  13.       host: 127.0.0.1 #注冊gateway網(wǎng)關到consul
  14.       port: 8500
  15.       discovery:
  16.         service-name: service-gateway

此時使用http://localhost:8089/service-consumer/user/info訪問服務,網(wǎng)關即可對服務進行路由轉發(fā),把請求轉發(fā)到具體后端服務上。此時,url中使用的url前綴service-consumer,是后端服務在Consul注冊的服務名稱轉為小寫字母以后的字符串。

 

 最佳實踐

01

Gateway網(wǎng)關配置

本文第二部分開發(fā)規(guī)范中定義了網(wǎng)關進行路由轉發(fā)的配置,除了上述配置方式還可以使用下面的方式進行配置:

  1. gateway:
  2.       discovery:
  3.         locator:
  4.           enabled: true
  5.           lower-case-service-id: true
  6.       routes:
  7.       - id: service_consumer
  8.         uri: lb://service-consumer
  9.         predicates:
  10.         - Path= /consumer/**
  11.         filters:
  12.         - StripPrefix=1

在上面的配置中,配置了一個Path的predicat,將以/consumer/**開頭的請求都會轉發(fā)到uri為lb://service-consumer的地址上,lb://service-consumer(注冊中心中服務的名稱)即service-consumer服務的負載均衡地址,并用StripPrefix的filter 在轉發(fā)之前將/consumer去掉。同時將spring.cloud.gateway.discovery.locator.enabled改為false,如果不改的話,之前的http://localhost:8081/service-consumer/user/info這樣的請求地址也能正常訪問,因為這時為每個服務創(chuàng)建了2個router。

本文第二部分和本節(jié)一共講述了兩種配置方式,兩種配置都可以實現(xiàn)請求路由轉發(fā)的功能。參數(shù)spring.cloud.gateway.discovery.locator.enabled為true,表明Gateway開啟服務注冊和發(fā)現(xiàn)的功能,并且Spring Cloud Gateway自動根據(jù)服務發(fā)現(xiàn)為每一個服務創(chuàng)建了一個router,這個router將以服務名開頭的請求路徑轉發(fā)到對應的服務。spring.cloud.gateway.discovery.locator.lowerCaseServiceId是將請求路徑上的服務名配置為小寫(因為服務注冊的時候,向注冊中心注冊時將服務名轉成大寫的了)。

  1. gateway:
  2.       discovery:
  3.         locator:
  4.           enabled: true
  5.           lower-case-service-id: true

02

Gateway跨域訪問


Spring Cloud Gateway還針對跨域訪問做了設計,可以使用以下配置解決跨域訪問問題:

  1. spring:
  2.   cloud:
  3.     gateway:
  4.       globalcors:
  5.         corsConfigurations:
  6.           '[/**]':
  7.             allowedOrigins: "https://docs."
  8.             allowedMethods:
  9.             - GET
  10.             allowHeaders:
  11.             - Content-Type

在上面的示例中,允許來自https://docs.的get請求進行訪問,并且表明服務器允許請求頭中攜帶字段Content-Type。

03

Gateway 過濾器


Spring Cloud Gateway的filter生命周期不像Zuul那么豐富,它只有兩個:“pre”和“post”:

  • pre:這種過濾器在請求被路由之前調用??梢岳眠@個過濾器實現(xiàn)身份驗證、在集群中選擇請求的微服務、記錄調試的信息。

  • post:這種過濾器在路由到服務器之后執(zhí)行。這種過濾器可用來為響應添加HTTP Header、統(tǒng)計信息和指標、響應從微服務發(fā)送給客戶端等。

Spring Cloud gateway的filter分為兩種:GatewayFilter和Globalfilter。GlobalFilter會應用到所有的路由上,而Gatewayfilter將應用到單個路由或者一個分組的路由上。

利用Gatewayfilter可以修改請求的http的請求或者是響應,或者根據(jù)請求或者響應做一些特殊的限制。更多時候可以利用Gatewayfilter做一些具體的路由配置。

下面的配置是AddRequestParameter Gatewayfilter的相關配置。

  1. spring:
  2.   application:
  3.     name: service-gateway
  4.   cloud:
  5.     gateway:
  6.      discovery:
  7.         locator:
  8.          enabled: true
  9.      routes:
  10.      - id: parameter_route
  11.       uri: http://localhost:8504/user/info
  12.       filters:
  13.       - AddRequestParameter=foo, bar
  14.       predicates:
  15.       - Method=GET
 

上述配置中指定了轉發(fā)的地址,設置所有的GET方法都會自動添加foo=bar,當請求符合上述路由條件時,即可在后端服務上接收到Gateway網(wǎng)關添加的參數(shù)。

另外再介紹一種比較常用的filter,即StripPrefix gateway filter。

配置如下:

  1. spring:
  2.   cloud:
  3.     gateway:
  4.       routes:
  5.       - id: stripprefixfilter
  6.         uri: lb://service-consumer
  7.         predicates:
  8.         - Path=/consumer/**
  9.         filters:
  10.         - StripPrefix=1

當client端使用http://localhost:8098/consumer/user/info路徑進行請求時,如果根據(jù)上述進行配置Gateway會將請求轉換為http://localhost:8098/service-consumer/user/info。以此作為前端請求的最終目的地。

04

Gateway請求匹配


Gateway網(wǎng)關可以根據(jù)不同的方式進行匹配進而把請求分發(fā)到不同的后端服務上。

通過header進行匹配,把請求分發(fā)到不同的服務上,配置如下:

  1. spring:
  2.   cloud:
  3.     gateway:
  4.       routes:
  5.       - id: header_route
  6.         uri: http://baidu.com
  7.         predicates:
  8.         - Header=X-Request-Id, \d+

通過curl測試:curl http://localhost:8080 -H "X-Request-Id:666666",返回頁面代碼證明匹配成功。

如果是以Host進行匹配,配置如下:

  1. spring:
  2.   cloud:
  3.     gateway:
  4.       routes:
  5.       - id: host_route
  6.         uri: http://baidu.com
  7.         predicates:
  8.         - Host=**.baidu.com

通過curl http://localhost:8098 -H "Host: www.baidu.com"進行測試,返回頁面代碼即轉發(fā)成功。


可以通過POST、GET、PUT、DELTE等不同的方式進行路由:

  1. spring:
  2.   cloud:
  3.     gateway:
  4.       routes:
  5.       - id: method_route
  6.         uri: http://baidu.com
  7.         predicates:
  8.         - Method=GET
 

通過 curl http://localhost:8098 進行測試,返回頁面代碼即表示成功。

上述是單個匹配進行路由,如果把多個匹配合在一起進行路由,必須滿足所有的路有條件才會進行路由轉發(fā)。

05

Gateway熔斷


Spring Cloud Gateway也可以利用Hystrix的熔斷特性,在流量過大時進行服務降級,同時項目中必須加上Hystrix的依賴。

  1. <dependency>
  2.   <groupId>org.springframework.cloud</groupId>
  3.   <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
  4. </dependency>    

配置后,Gateway將使用fallbackcmd作為名稱生成HystrixCommand對象進行熔斷處理。如果想添加熔斷后的回調內容,需要添加以下配置:

  1. spring:
  2.   cloud:
  3.     gateway:
  4.       routes:
  5.       - id: hystrix_route
  6.         uri: lb://consumer-service
  7.         predicates:
  8.         - Path=/consumer/**
  9.         filters:
  10.         - name: Hystrix
  11.           args:
  12.             name: fallbackcmd
  13.             fallbackUri: forward:/fallback
  14.         - StripPrefix=1
  15. hystrix:  
  16.   command:
  17.     fallbackcmd:
  18.       execution:
  19.         isolation:
  20.           thread:
  21.             timeoutInMilliseconds: 5000 #超時時間,若不設置超時時間則有可能無法觸發(fā)熔斷
 

上述配置中給出了熔斷之后返回路徑,因此,在Gateway服務模塊添加/fallback路徑,以作為服務熔斷時的返回路徑。

  1. @RestController
  2. public class GatewayController {
  3.     @RequestMapping(value = "/fallback")
  4.     public String fallback(){
  5.         return "fallback nothing";
  6.     }
  7. }

fallbackUri: forward:/fallback配置了 fallback 時要會調的路徑,當調用 Hystrix 的 fallback 被調用時,請求將轉發(fā)到/fallback這個 URI,并以此路徑的返回值作為返回結果。

06

Gateway重試路由器


通過簡單的配置,Spring Cloud Gateway就可以支持請求重試功能。

  1. spring:
  2.   cloud:
  3.     gateway:
  4.       routes:
  5.       - id: header_route
  6.         uri: http://localhost:8504/user/info
  7.         predicates:
  8.         - Path=/user/**
  9.         filters:
  10.         - name: Retry
  11.           args:
  12.             retries: 3
  13.             status: 503
  14.         - StripPrefix=1

Retry GatewayFilter通過四個參數(shù)來控制重試機制,參數(shù)說明如下:

  • retries:重試次數(shù),默認值是 3 次。

  • statuses:HTTP 的狀態(tài)返回碼,取值請參考:org.springframework.http.HttpStatus。

  • methods:指定哪些方法的請求需要進行重試邏輯,默認值是 GET 方法,取值參考:org.springframework.http.HttpMethod。

  • series:一些列的狀態(tài)碼配置,取值參考:org.springframework.http.HttpStatus.Series。符合的某段狀態(tài)碼才會進行重試邏輯,默認值是 SERVER_ERROR,值是 5,也就是 5XX(5 開頭的狀態(tài)碼),共有5個值。

使用上述配置進行測試,當后臺服務不可用時,會在控制臺看到請求三次的日志,證明此配置有效。

07

Gateway 限流操作


Spring Cloud Gateway本身集成了限流操作,Gateway限流需要使用Redis,pom文件中添加Redis依賴:

  1. <dependency>
  2.     <groupId>org.springframework.boot</groupId>
  3.     <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
  4. </dependency>

配置文件中配置如下:

  1. spring:
  2.   cloud:
  3.     gateway:
  4.       routes:
  5.       - id: rate_limit_route
  6.         uri: lb://service-consumer
  7.         predicates:
  8.         - Path=/user/**
  9.         filters:
  10.         - name: RequestRateLimiter
  11.           args:
  12.             key-resolver: "#{@hostAddrKeyResolver}"
  13.             redis-rate-limiter.replenishRate: 1
  14.             redis-rate-limiter.burstCapacity: 3
  15.         - StripPrefix=1
  16.     consul:
  17.       host: 127.0.0.1
  18.       port: 8500
  19.       discovery:
  20.         service-name: service-gateway
  21.         instance-id: service-gateway-233
  22.   redis:
  23.     host: localhost
  24.     port: 6379
 

在上面的配置問價中,配置了Redis的信息,并配置了RequestRateLimiter的限流過濾器,該過濾器需要配置三個參數(shù):

  • BurstCapacity:令牌桶的總容量。

  • replenishRate:令牌通每秒填充平均速率。

  • Key-resolver:用于限流的解析器的Bean對象的名字。它使用SpEL表達式#{@beanName}從Spring容器中獲取bean對象。

注意:filter下的name必須是RequestRateLimiter。

Key-resolver參數(shù)后面的bean需要自己實現(xiàn),然后注入到Spring容器中。KeyResolver需要實現(xiàn)resolve方法,比如根據(jù)ip進行限流,則需要用hostAddress去判斷。實現(xiàn)完KeyResolver之后,需要將這個類的Bean注冊到Ioc容器中。還可以根據(jù)uri限流,同hostname限流是一樣的。例如以ip限流為例,在gateway模塊中添加以下實現(xiàn):

  1. public class HostAddrKeyResolver implements KeyResolver {
  2.     @Override
  3.     public Mono<String> resolve(ServerWebExchange exchange) {
  4.         return Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
  5.     }
  6.     public HostAddrKeyResolver hostAddrKeyResolver() {
  7.         return new HostAddrKeyResolver();
  8.     }
  9. }

把該類注入到spring容器中:

  1. @SpringBootApplication
  2. @EnableDiscoveryClient
  3. public class GatewayApplication {
  4.     public static void main(String[] args) {
  5.         SpringApplication.run(GatewayApplication.class, args);
  6.     }
  7.     @Bean
  8.     public HostAddrKeyResolver hostAddrKeyResolver(){
  9.         return new HostAddrKeyResolver();
  10.     }
  11. }

基于上述配置,可以對請求基于ip的訪問進行限流。

08

自定義Gatewayfilter

Spring Cloud Gateway內置了過濾器,能夠滿足很多場景的需求。當然,也可以自定義過濾器。在Spring Cloud Gateway自定義過濾器,過濾器需要實現(xiàn)GatewayFilter和Ordered這兩個接口。

下面的例子實現(xiàn)了Gatewayfilter,它可以以log日志的形式記錄每次請求耗費的時間,具體實現(xiàn)如下:

  1. public class RequestTimeFilter implements GatewayFilter, Ordered {
  2.     private static final Log log = LogFactory.getLog(GatewayFilter.class);
  3.     private static final String REQUEST_TIME_BEGIN = "requestTimeBegin";
  4.     @Override
  5.     public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
  6.         exchange.getAttributes().put(REQUEST_TIME_BEGIN, System.currentTimeMillis());
  7.         return chain.filter(exchange).then(
  8.                 Mono.fromRunnable(() -> {
  9.                     Long startTime = exchange.getAttribute(REQUEST_TIME_BEGIN);
  10.                     if (startTime != null) {
  11.                         log.info("請求路徑:"+exchange.getRequest().getURI().getRawPath() + "消耗時間: " + (System.currentTimeMillis() - startTime) + "ms");
  12.                     }
  13.                 })
  14.         );
  15.     }
  16.     @Override
  17.     public int getOrder() {
  18.         return 0;
  19.     }
  20. }

上述代碼中定義了自己實現(xiàn)的過濾器。Ordered的int getOrder()方法是來給過濾器定優(yōu)先級的,值越大優(yōu)先級越低。還有一個filter(ServerWebExchange exchange, GatewayFilterChain chain)方法,在該方法中,先記錄了請求的開始時間,并保存在ServerWebExchange中,此處是一個“pre”類型的過濾器。然后再chain.filter()的內部類中的run()方法中相當于"post"過濾器,在此處打印了請求所消耗的時間。

接下來將該過濾器注冊到router中,代碼如下。

  1.  @Bean
  2.     public RouteLocator customerRouteLocator(RouteLocatorBuilder builder) {
  3.         return builder.routes()
  4.                 .route(r -> r.path("/user/**")
  5.                         .filters(f -> f.filter(new RequestTimeFilter())
  6.                                 .addResponseHeader("X-Response-Default-Foo", "Default-Bar"))
  7.                         .uri("http://localhost:8504/user/info")
  8.                         .order(0)
  9.                         .id("customer_filter_router")
  10.                 )
  11.                 .build();
  12.     }

除了上述代碼的方式配置我們自定義的過濾器的方式之外,也可以在application.yml文件中直接配置,這里不再贅述。

啟動程序,通過curl http://localhost:8098/user/info控制臺會打印出請求消耗時間,日志如下:

  1. ....
  2. 2019-05-22 15:13:31.221  INFO 19780 --- [ctor-http-nio-4] o.s.cloud.gateway.filter.GatewayFilter   : 請求路徑:/user/info消耗時間: 54ms
  3. ...
  4. 2019-05-22 16:46:23.785  INFO 29928 --- [ctor-http-nio-1] o.s.cloud.gateway.filter.GatewayFilter   : 請求路徑:/user/info3消耗時間: 5ms
  5. ....

09

自定義GlobalFilter


Spring Cloud Gateway根據(jù)作用范圍分為GatewayFilter和GlobalFilter,二者區(qū)別如下:

  • GatewayFilter : 需要通過spring.cloud.routes.filters 配置在具體路由下,只作用在當前路由上或通過spring.cloud.default-filters配置在全局,作用在所有路由上。

  • GlobalFilter:全局過濾器,不需要在配置文件中配置,作用在所有的路由上,最終通過GatewayFilterAdapter包裝成GatewayFilterChain可識別的過濾器,它為請求業(yè)務以及路由的URI轉換為真實業(yè)務服務的請求地址的核心過濾器,不需要配置,系統(tǒng)初始化時加載,并作用在每個路由上。

在上一小節(jié)中定義的是Gatewayfilter,下面實現(xiàn)的是Globalfilter:

  1. public class TokenFilter implements GlobalFilter, Ordered {
  2.     Logger logger= LoggerFactory.getLogger( TokenFilter.class );
  3.     @Override
  4.     public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
  5.         String token = exchange.getRequest().getQueryParams().getFirst("token");
  6.         if (token == null || token.isEmpty()) {
  7.             logger.info( "token 為空,無法進行訪問." );
  8.             exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
  9.             return exchange.getResponse().setComplete();
  10.         }
  11.         return chain.filter(exchange);
  12.     }
  13.     @Override
  14.     public int getOrder() {
  15.         return 0;
  16.     }
  17. }

上述代碼實現(xiàn)了Globalfilter,具體邏輯是判斷請求中是否含參數(shù)token,如果沒有,則校驗不通過,對所有請求都有效。如果含有token則轉發(fā)到具體后端服務上,如果沒有則校驗不通過。

通過curl http://localhost:8098/user/info進行訪問,因為路徑中不含有參數(shù)token,則無法通過校驗,打印日志如下:

  1. 2019-05-22 15:27:11.078  INFO 5956 --- [ctor-http-nio-1] com.song.gateway.TokenFilter             : token 為空,無法進行訪問.
  2. ...

通過curl http://localhost:8098/user/info?token=123進行訪問時,則可以獲取到后端服務返回結果。

本文由博云研究院原創(chuàng)發(fā)表,轉載請注明出處。

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多