天天看點

(接上章)6 過濾器 7 網關限流8 網關高可用

目錄

6 過濾器

 6.1 局部過濾器

6.1.1 内置局部過濾器

6.2 全局過濾器

6.2.1 内置全局過濾器

6.2.2 自定義全局過濾器

 7 網關限流

7.1 常見的限流算法 

8 網關高可用

6 過濾器

三個知識點:

1 作用: 過濾器就是在請求的傳遞過程中,對請求和響應做一些手腳

2 生命周期: Pre Post

3 分類: 局部過濾器(作用在某一個路由上) 全局過濾器(作用全部路由上)

在Gateway中, Filter的生命周期隻有兩個:“pre” 和 “post”。

  1. PRE: 這種過濾器在請求被路由之前調用。我們可利用這種過濾器實作身份驗證、在叢集中選擇請求的微服務、記錄調試資訊等。
  2. POST:這種過濾器在路由到微服務以後執行。這種過濾器可用來為響應添加标準的HTTP Header、收集統計資訊和名額、将響應從微服務發送給用戶端等。
    (接上章)6 過濾器 7 網關限流8 網關高可用
    Gateway 的Filter從作用範圍可分為兩種: GatewayFilter與GlobalFilter。 GatewayFilter:應用到單個路由或者一個分組的路由上。 GlobalFilter:應用到所有的路由上。

 6.1 局部過濾器

局部過濾器是針對單個路由的過濾器。

6.1.1 内置局部過濾器

在SpringCloud Gateway中内置了很多不同類型的網關路由過濾器。

https://www.cnblogs.com/zhaoxiangjun/p/13042189.html

内置局部過濾器的使用

server:
  port: 7000
spring:
  application:
    name: api-gateway
  # 配置api
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    gateway:
#      discovery:
#        locator:
#          enabled: true
      routes:
        - id: product_route   # 路由的唯一辨別,隻要不重複都可以,如果不寫預設會通過UUID産生,一般寫成被路由的服務名稱
          uri: lb://shop-product  # 被路由的位址
          order: 1                     #表示優先級  數字越小優先級越高
          predicates:                  #斷言: 執行路由的判斷條件
            - Path=/product_serv/**
            - Age=18,60
#            - Before=2020-11-28T00:00:00.000+08:00 # 表示在2020前通路
#            - Method=POST             # 請求方式必須為POST
          filters:                     # 過濾器: 可以在請求前或請求後作一些手腳
            - StripPrefix=1
            - SetStatus=2000
           

6.2 全局過濾器

全局過濾器作用于所有路由, 無需配置。通過全局過濾器可以實作對權限的統一校驗,安全性驗證等功能。

6.2.1 内置全局過濾器

SpringCloud Gateway内部也是通過一系列的内置全局過濾器對整個路由轉發進行處理如下:

(接上章)6 過濾器 7 網關限流8 網關高可用

6.2.2 自定義全局過濾器

内置的過濾器已經可以完成大部分的功能,但是對于企業開發的一些業務功能處理,還是需要我們自己編寫過濾器來實作的,那麼我們一起通過代碼的形式自定義一個過濾器,去完成統一的權限校驗。

開發中的鑒權邏輯:

  1. 當用戶端第一次請求服務時,服務端對使用者進行資訊認證(登入)
  2. 認證通過,将使用者資訊進行加密形成token,傳回給用戶端aaaa,作為登入憑證
  3. 以後每次請求,用戶端都攜帶認證的token
  4. 服務端對token進行解密,判斷是否有效。
(接上章)6 過濾器 7 網關限流8 網關高可用

如上圖,對于驗證使用者是否已經登入鑒權的過程可以在網關統一檢驗。

檢驗的标準就是請求中是否攜帶token憑證以及token的正确性。

下面的我們自定義一個GlobalFilter,去校驗所有請求的請求參數中是否包含“token”,如何不包含請求參數“token”則不轉發路由,否則執行正常的邏輯

自定義全局過濾器 要求:必須實作GlobalFilter,Order接口

@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String token = exchange.getRequest().getQueryParams().getFirst("token");
        if(StringUtils.isNotEmpty(token) && StringUtils.equals(token,"admin")){
            return chain.filter(exchange);
        }
         exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
        return exchange.getResponse().setComplete();
    }
    //優先級 值越小優先級越高
    @Override
    public int getOrder() {
        return 1;
    }
}
           

 7 網關限流

7.1 常見的限流算法 

(1) 計數器

計數器限流算法是最簡單的一種限流實作方式。其本質是通過維護一個機關時間内的計數器,每次請求計數器加1,當機關時間内計數器累加到大于設定的門檻值,則之後的請求都被拒絕,直到機關時間已經過去,再将計數器重置為零。

(2) 漏桶算法

漏桶算法可以很好地限制容量池的大小,進而防止流量暴增。漏桶可以看作是一個帶有常量服務時間的單伺服器隊列,如果漏桶(包緩存)溢出,那麼資料包會被丢棄。 在網絡中,漏桶算法可以控制端口的流量輸出速率,平滑網絡上的突發流量,實作流量整形,進而為網絡提供一個穩定的流量。

(3) 令牌桶算法

令牌桶算法是對漏桶算法的一種改進,桶算法能夠限制請求調用的速率,而令牌桶算法能夠在限制調用的平均速率的同時還允許一定程度的突發調用。在令牌桶算法中,存在一個桶,用來存放固定數量的令牌。算法中存在一種機制,以一定的速率往桶中放令牌。每次請求調用需要先擷取令牌,隻有拿到令牌,才有機會繼續執行,否則選擇選擇等待可用的令牌、或者直接拒絕。放令牌這個動作是持續不斷的進行,如果桶中令牌數達到上限,就丢棄令牌,是以就存在這種情況,桶中一直有大量的可用令牌,這時進來的請求就可以直接拿到令牌執行,比如設定qps為100,那麼限流器初始化完成一秒後,桶中就已經有100個令牌了,這時服務還沒完全啟動好,等啟動完成對外提供服務時,該限流器可以抵擋瞬時的100個請求。是以,隻有桶中沒有令牌時,請求才會進行等待,最後相當于以一定的速率執行。

8 網關高可用

高可用HA(High Availability)是分布式系統架構設計中必須考慮的因素之一,它通常是指,通過設計減少系統不能提供服務的時間。我們都知道,單點是系統高可用的大敵,單點往往是系統高可用最大的 風險和敵人,應該盡量在系統設計的過程中避免單點。方法論上,高可用保證的原則是“叢集化”,或者叫“備援”:隻有一個單點,挂了服務會受影響;如果有備援備份,挂了還有其他backup能夠頂上。 ngnix linux

(接上章)6 過濾器 7 網關限流8 網關高可用

我們實際使用 Spring Cloud Gateway 的方式如上圖,不同的用戶端使用不同的負載将請求分發到後端的 Gateway,Gateway 再通過HTTP調用後端服務,最後對外輸出。是以為了保證 Gateway 的高可用性,前端可以同時啟動多個 Gateway 執行個體進行負載,在 Gateway 的前端使用 Nginx 或者 F5 進行負載轉發以達到高可用性。

(1) 準備多個GateWay工程

修改 shop_gateway_server8080 的application.yml。添加如下配置

server:
  port: 80
​
spring:
  application:
    name: shop-gateway-server
  cloud:
    gateway:
      routes:
        - id: product_service #路由的ID,沒有固定規則但要求唯一,簡易配合服務名
          uri: lb://shop-product-service        #比對後提供服務的路由位址
          predicates:
            #- Path=/product/**          #斷言,路徑相比對的進行路由
            - Path=/product-service/**
          filters:
            - RewritePath=/product-service/(?<segment>.*), /$\{segment}
      discovery:
        locator:
          enabled: true  # 開啟微服務名稱轉發
          lower-case-service-id: true  #微服務名小寫
​
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka/
      registry-fetch-interval-seconds: 5 # 擷取服務清單的周期:5s
    instance:
      preferIpAddress: true
      ip-address: 127.0.0.1
           

通過不同的profifiles配置啟動兩個網關服務,請求端口分别為8080和8081。浏覽器驗證發現效果是一緻的.

(2) 配置ngnix

找到ngnix添加負載均衡配置

#配置多台伺服器(這裡隻在一台伺服器上的不同端口) 
upstream gateway { 
  server 127.0.0.1:8081; 
  server 127.0.0.1:8080; 
}
#請求轉向mysvr 定義的伺服器清單 
location / { 
  proxy_pass http://gateway; 
}
           

在浏覽器上通過通路http://localhost/product-service/product/2請求的效果和之前是一樣的。這次關閉一台網關伺服器,還是可以支援部分請求的通路。