Spring Cloud微服務安全實戰_4-10_用spring-cloud-zuul-ratelimit做限流


本篇講網關上的限流

用開源項目spring-cloud-zuul-ratelimit 做網關上的限流 (項目github:https://github.com/marcosbarbero/ 

 

1,在網關項目里,引入限流組件的maven依賴:

 

 

 2,在網關項目yml配置里,配限流相關配置

github也有相關配置說明:https://github.com/marcosbarbero/spring-cloud-zuul-ratelimit

限流框架限流需要存一些信息,可以存在數據庫里,也可以存在redis里,這里就用redis做實驗,而且我看該組件的限流存儲枚舉類里,如果使用數據庫保存限流信息,只能用JPA,不能用mybatis(可能歪果仁更喜歡JPA):

 

public enum RateLimitRepository {
    REDIS,
    CONSUL,
    JPA,
    BUCKET4J_JCACHE,
    BUCKET4J_HAZELCAST,
    BUCKET4J_IGNITE,
    BUCKET4J_INFINISPAN,
}

 

限流yml配置:

限流的信息,在redis是有有效期的,過了有效期會自動清除,所以要想在redis看到限流的相關信息,這里時間窗口就設置為 10 秒(剛開始我設置的是1秒,redis死活看不到限流信息,浪費了十幾分鍾時間)

zuul:
  routes: #路由的配置是個Map,可以配置多個
    token:  #token結尾的請求,都轉發到http://localhost:9090認證服務器地址
      url:  http://localhost:9090
    order:  #order結尾的請求,都轉發到http://localhost:9060 頂單服務
      url:  http://localhost:9060
  sensitive-headers:  null  #設置敏感頭設置為空,Authorization等請求頭的請求,都往后轉發
  ratelimit:
      key-prefix: rate
      enabled: true
      repository: REDIS
      default-policy-list:
        #    ########### 如下的配置就是說:每1秒內不能超過2個請求,2個請求時間加起來不能超過1秒(quota)############
        - limit: 2 #optional - request number limit per refresh interval window
          quota: 1 #optional - request time limit per refresh interval window (in seconds)
          refresh-interval: 10 #時間窗口 (in seconds)
          type: ##根據什么控制流量,可以組合使用,如url、httpmethod組合,就會把 /orders的get和post請求分開處理
            - url
            - http_method
          #- user  #根據用戶控制需要Security支持,(一般不用)
          #- origin #根據客戶端的ip控制

3,實驗 

1,分別啟動 訂單 、認證、網關 三個服務

 

 

 

 2,從網關獲取一個token:

OAuth2 password模式參數

 

 

 網關client的username,password

 3,拿token訪問網關創建訂單

手速點的快點,Http就會返回 429 狀態碼,表示過多的請求。

 

 

 看redis,已經有限流的信息了:

 

生成的限流的key是: rate:order:/orders:POST        rate是配置的限流信息的前綴,order是zuul轉發的規則,/orders:POST 是配置的限流類型 url 和http_method的組合

當下一個請求過來的時候就會計算key,然后根據key去redis找,看當前的key已經過了多少個請求了,來判斷這次請求能不能過。

大部分情況下,根據user 、origin、 url 、http_method已經滿足需求了。有些特殊的場景,需要根據傳過來的參數進行限流,比如有兩種優惠券A、B,優惠券A業務簡單,每秒能處理100個請求,優惠券B復雜,每秒能處理10個請求,此時自帶的限流規則就不能滿足需求了。限流歸根揭底是根據key來限流的,所以此時就要自定義key的生成規則。

自定義key的生成規則:

 

import com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.config.RateLimitUtils;
import com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.config.properties.RateLimitProperties;
import com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.support.DefaultRateLimitKeyGenerator;
import org.springframework.cloud.netflix.zuul.filters.Route;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

/**
 * 自定義限流key生成規則,自定義限流規則
 */
@Component
public class MyKeyGen extends DefaultRateLimitKeyGenerator {

    public MyKeyGen(RateLimitProperties properties, RateLimitUtils rateLimitUtils){
        super(properties,rateLimitUtils);
    }

    @Override
    public String key(HttpServletRequest request, Route route, RateLimitProperties.Policy policy) {
        //可以從route拿出路由信息,自定義key生成規則:https://github.com/marcosbarbero/spring-cloud-zuul-ratelimit#usage
        return super.key(request, route, policy);
    }
}

 

重寫錯誤處理:

 

package com.nb.security.filter;

import com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.config.repository.DefaultRateLimiterErrorHandler;
import org.springframework.stereotype.Component;

/**
 * 限流錯誤自定義處理
 */
@Component
public class MyRateLimitErrorHandler extends DefaultRateLimiterErrorHandler {

    //限流數據存時候報錯了的處理,一般不覆蓋
    @Override
    public void handleSaveError(String key, Exception e) {
        super.handleSaveError(key, e);
    }

    //限流取數據報錯的處理,一般不覆蓋
    @Override
    public void handleFetchError(String key, Exception e) {
        super.handleFetchError(key, e);
    }

    //限流錯誤處理,記日志等
    @Override
    public void handleError(String msg, Exception e) {
        super.handleError(msg, e);
    }
}

都在網關上做限流是有問題的

 

 

1,耦合

  如上所述的根據不同的優惠券進行的限流,如果優惠券又多了種類型,就要重寫網關的限流的代碼,重寫部署網關,這就是耦合,是不行的。服務和服務之間,以及服務和基礎組件之間,一定要解耦。微服務場景下解耦是價值最大的事。一旦兩個服務耦合在一塊,一個變了,另一個也要跟着變。

2,限流的數量的問題

  網關只能處理從整個微服務外邊進來的請求,並不處理微服務之間的調用。如,有A B兩個微服務,A還調用了B服務,A、B服務每秒處理的請求最大都是100個,網關限流 A 100請求/秒   ,B 100請求/秒。此時有100個A請求到網關,100個B請求也到了網關,都通過了網關,而此時,100個到A的請求又請求了100次B,導致B服務不可用!

所以:在網關上不要做細粒度的限流,沒有用,因為很多服務之間的調用,都不走網關。網關層面只根據硬件設備的處理能力做一些限流,如服務的節點用的是tomcat,根據每個tomcat的資源配置,計算能處理的多少並發請求,根據這個去限流。具體的方法,跟業務邏輯的耦合,都不要發生在網關上的限流邏輯里。這就是上邊配置里說的,限流類型 user最好不在網關上用。

       

 本篇github :  https://github.com/lhy1234/springcloud-security/tree/chapt-4-10-ratelimit  如果對你有一點幫助,點個小星星吧!謝謝

 

 

歡迎關注個人公眾號一起交流學習:

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM