聊聊Spring Cloud Gateway

2023-06-03 21:00:40

閘道器概述

整體來看,閘道器有點類似於門面,所有的外部請求都會先經過閘道器這一層。

閘道器不僅只是做一個請求的轉發及服務的整合,有了閘道器這個統一的入口之後,它還能提供以下功能。

  • 針對所有請求進行統一鑑權、限流、熔斷、紀錄檔。
  • 協定轉化。針對後端多種不同的協定,在閘道器層統一處理後以HTTP對外提供服務。譬如針對Dubbo服務還需要提供一個Web應用來進行協定轉化,此時可以在API閘道器層轉換協定。
  • 統一錯誤碼處理。
  • 灰度釋出
  • 請求轉發,並且可以基於閘道器實現內、外網隔離。

常用的解決方案場景如下:

Spring Cloud Gateway

Spring Cloud Gateway是基於Spring Boot 2.0、Spring WebFlux和Project Reactor等技術開發的閘道器,它不僅提供了統一的路由請求的方式,還基於過濾鏈的方式提供了閘道器最基本的功能;解決了Spring Cloud Zuul的效能問題:

  • Zuul 1.x採用的是傳統的thread per connection方式來處理請求,也就是針對每一個請求,會為這個請求專門分配一個執行緒來進行處理,直到這個請求完成之後才會釋放執行緒,一旦後臺伺服器響應較慢,就會使得該執行緒被阻塞,所以它的效能不是很好。

  • Zuul 1.x採用的是傳統的thread per connection方式來處理請求,也就是針對每一個請求,會為這個請求專門分配一個執行緒來進行處理,直到這個請求完成之後才會釋放執行緒,一旦後臺伺服器響應較慢,就會使得該執行緒被阻塞,所以它的效能不是很好。

Spring WebFlux基於Project Reactor響應式框架實現了完全無阻塞的、響應式的、高並行效能的、網路請求響應;解決了如上的Zuul效能問題。

個人覺得,其實就是類似Nginx、Redis等基於Reactor模式的實現;也是非阻塞IO(Epoll)的另一種體現。

請求過程及關鍵概念

Spring Cloud Gateway的請求處理過程如圖所示,其中有幾個非常重要的概念。

  • 路由(Route):它是閘道器的基本元件,由ID、目標URI、Predicate集合、Filter集合組成。

  • 謂語(Predicate):它是Java 8中引入的函數式介面,提供了斷言的功能。它可以匹配HTTP請求中的任何內容。如果Predicate的聚合判斷結果為true,則意味著該請求會被當前Router進行轉發。

  • 謂語(Predicate):它是Java 8中引入的函數式介面,提供了斷言的功能。它可以匹配HTTP請求中的任何內容。如果Predicate的聚合判斷結果為true,則意味著該請求會被當前Router進行轉發。

Spring Cloud Gateway啟動時基於Netty Server監聽一個指定的埠(該埠可以通過server.port屬性自定義)。當用戶端傳送一個請求到閘道器時,閘道器會根據一系列Predicate的匹配結果來決定存取哪個Route路由,然後根據過濾器鏈進行請求的處理。過濾器鏈可以在請求傳送到後端伺服器之前和之後執行,也就是首先執行Pre過濾器鏈,然後將請求轉發到後端的微服務執行具體的業務,最後執行Post過濾器鏈。

Route Predicate Factories

Predicate是Java 8提供的一個函數式介面,它允許接收一個引數並返回一個布林值,可以用於條件過濾、請求引數的校驗。

在Spring Cloud Gateway中,Predicate提供了路由規則的匹配機制。比如:

意思是通過Path屬性來匹配URL字首是/gateway/的請求。

如下,Spring Cloud Gateway預設提供了很多Route Predicate Factory,這些Predicate會分別匹配HTTP請求的不同屬性,並且多個Predicate可以通過and邏輯進行組合。

Gateway Filter Factories

Filter分為Pre型別的過濾器和Post型別的過濾器。

  • Pre型別的過濾器在請求轉發到後端微服務之前執行,在Pre型別過濾器鏈中可以做鑑權、限流等操作。

  • Post型別的過濾器在請求執行完之後、將結果返回給使用者端之前執行。

在Spring Cloud Gateway中內建了很多Filter,Filter有兩種實現,分別是GatewayFilter和GlobalFilter。GlobalFilter會應用到所有的路由上,而GatewayFilter只會應用到單個路由或者一個分組的路由上。

GatewayFilter

Spring提供了一些內建的GatewayFilter,如:

  • AddRequestParameter GatewayFilter Factory:該過濾器的功能是對所有匹配的請求新增一個查詢引數。

  • AddResponseHeader GatewayFilter Factory:該過濾器會對所有匹配的請求,在返回結果給使用者端之前,在Header中新增相應的資料。
    在上面這段設定中,會在Response中新增Header頭,

    在上面這段設定中,會在Response中新增Header頭,key=X-Response-Foo,Value=Bar。

  • RequestRateLimiter GatewayFilter Factory:該過濾器會對存取到當前閘道器的所有請求執行限流過濾,如果被限流,預設情況下會響應HTTP 429-Too Many Requests。
    RequestRateLimiterGatewayFilterFactory預設提供了RedisRateLimiter的限流實現,它採用令牌桶演演算法來實現限流功能。

    redis-rate-limiter過濾器有兩個設定屬性:

  • Retry GatewayFilter Factory:Retry GatewayFilter Factory為請求重試過濾器,當後端服務不可用時,閘道器會根據設定引數來發起重試請求。

    RetryGatewayFilter提供4個引數來控制重試請求,引數說明如下。

GlobalFilter

GlobalFilter和GatewayFilter的作用是相同的,只是GlobalFilter針對所有的路由設定生效。Spring Cloud Gateway內建的全域性過濾器也有很多,比如:

全域性過濾鏈的執行順序是,當Gateway接收到請求時,Filtering Web Handler處理器會將所有的GlobalFilter範例及所有路由上所設定的GatewayFilter範例新增到一條過濾器鏈中。該過濾器鏈裡的所有過濾器都會按照@Order註解所指定的數位大小進行排序。

  • LoadBalancerClientFilter:LoadBalancerClientFilter是用於實現請求負載均衡的全域性過濾器,設定如下。

    如果URI設定的是lb://example_service,那麼這個過濾器會識別到lb://,並且使用Spring Cloud LoadBalancerClient將example_service名稱解析成實際存取的主機和埠地址。

  • GatewayMetricsFilter:GatewayMetricsFilter是閘道器指標過濾器,這個過濾器會新增name=gateway.requests的timer metrics,其中包含以下資料。

    這些指標通過http://ip:port/actuator/metrics/gateway.requests獲得,前提是需要新增Spring Boot Actuator依賴。

自定義過濾器

Spring Cloud Gateway提供了過濾器的擴充套件功能,開發者可以根據實際業務需求來自定義過濾器。同樣,自定義過濾器也支援GlobalFilter和GatewayFilter兩種。

  • 自定義GatewayFilter:自定義過濾器類GpDefineGatewayFilterFactory,繼承AbstractGatewayFilterFactory。

  • 自定義GlobalFilter:GlobalFilter的實現比較簡單,它不需要額外的設定,只需要實現GlobalFilter介面,自動會過濾所有的Route。

整合

Spring Cloud Gateway支援與其他解決方案整合,實現更強大的功能,比如Spring Cloud Alibaba系列。