網關之多維度限流


github https://github.com/marcosbarbero/spring-cloud-zuul-ratelimit

spring-cloud-zuul-ratelimit 說明

spring-cloud-zuul-ratelimit是和zuul整合提供分布式限流策略的擴展

  • 對請求的目標URL進行限流(例如:某個URL每分鍾只允許調用多少次)
  • 對客戶端的訪問IP進行限流(例如:某個IP每分鍾只允許請求多少次)
  • 對某些特定用戶或者用戶組進行限流(例如:非VIP用戶限制每分鍾只允許調用100次某個API等)
  • 多維度混合的限流。此時,就需要實現一些限流規則的編排機制。與、或、非等關系。

支持的限流粒度

  • 服務粒度 (默認配置,當前服務模塊的限流控制)
  • 用戶粒度
    用戶限流的實現:如果你的項目整合 Shiro 或者 Spring Security 安全框架,那么會自動維護request域UserPrincipal,如果是自己的框架,請登錄成功后維護request域UserPrincipal,才能使用用戶粒度的限流。未登錄默認是:anonymous
  • ORIGIN粒度 (用戶請求的origin作為粒度控制)
    某個IP的客戶端被限流並不影響其他客戶端,即API網關對每個客戶端限流是相互獨立的
  • URL 接口粒度 (請求接口的地址作為粒度控制)
  • 以上粒度自由組合,又可以支持多種情況。
  • 如果還不夠,自定義RateLimitKeyGenerator實現

支持數據存儲

  • InMemoryRateLimiter - 使用 ConcurrentHashMap作為數據存儲
  • ConsulRateLimiter - 使用 Consul 作為數據存儲
  • RedisRateLimiter - 使用 Redis 作為數據存儲
  • JpaRateLimiter - 使用 數據庫 作為數據存儲
  • Bucket4j JCache 等其它緩存存儲

pom 依賴

        <dependency>
            <groupId>com.marcosbarbero.cloud</groupId>
            <artifactId>spring-cloud-zuul-ratelimit</artifactId>
            <version>1.7.1.RELEASE</version>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

限流配置

  • limit 單位時間內允許訪問的次數
  • quota 單位時間內允許訪問的總時間(單位時間窗口期內,所有的請求的總時間不能超過這個時間限制)
  • refresh-interval 單位時間設置
  • type 限流類型
    1. url類型的限流就是通過請求路徑區分
    2. origin是通過客戶端IP地址區分
    3. user是通過登錄用戶名進行區分,也包括匿名用戶
  • default-policy 可選 - 針對所有的路由配置的策略,除非特別配置了policy-list
  • policies 對特定的服務id進行限流
    • 缺點
      • 可以配置多個url,但是這些url都使用一個限流配置,沒有辦法指定每個url的限流配置
  • policy-list 對特定的服務id進行限流
    • 優點
      • 可以為某個服務id的每個url 指定不同的限流配置

policies 配置多個url共用一個限流次數

zuul.routes.hello-feign.path=/hello-feign/**
zuul.routes.hello-feign.serviceId=feign-service-1

#*********************************************************
#  特定的路由
#
# 測試客戶端 30秒內允許10個訪問,並且要求總請求時間小於20秒
#
#*********************************************************
zuul.ratelimit.policies.hello-feign.limit=10
zuul.ratelimit.policies.hello-feign.quota=20
zuul.ratelimit.policies.hello-feign.refreshInterval=30

zuul.ratelimit.policies.hello-feign.type[0].type=url
zuul.ratelimit.policies.hello-feign.type[0].matcher=/custom/zuul/test

zuul.ratelimit.policies.hello-feign.type[1].type=url
zuul.ratelimit.policies.hello-feign.type[1].matcher=/custom/zuul/timeout

policy-list 配置每個url的限流次數

zuul.routes.hello-feign.path=/hello-feign/**
zuul.routes.hello-feign.serviceId=feign-service-1

zuul.ratelimit.policy-list.hello-feign.[0].limit=10
zuul.ratelimit.policy-list.hello-feign.[0].quota=4
zuul.ratelimit.policy-list.hello-feign.[0].refreshInterval=10
zuul.ratelimit.policy-list.hello-feign.[0].type[0].type=url
zuul.ratelimit.policy-list.hello-feign.[0].type[0].matcher=/custom/zuul/test

zuul.ratelimit.policy-list.hello-feign.[1].limit=2
zuul.ratelimit.policy-list.hello-feign.[1].quota=4
zuul.ratelimit.policy-list.hello-feign.[1].refreshInterval=10
zuul.ratelimit.policy-list.hello-feign.[1].type[0].type=url
zuul.ratelimit.policy-list.hello-feign.[1].type[0].matcher=/request-body

擴展 策略生成的key,因為默認的策略key 在循環policy-list 的配置時會將當前的url對應的策略 policy 覆蓋掉。

@Configuration
public class CustomPolicy extends DefaultRateLimitKeyGenerator {

    private final RateLimitProperties properties;
    private final RateLimitUtils rateLimitUtils;


    public CustomPolicy(RateLimitProperties properties, RateLimitUtils rateLimitUtils) {
        super(properties, rateLimitUtils);
        this.properties = properties;
        this.rateLimitUtils = rateLimitUtils;
    }

    @Override
    public String key(HttpServletRequest request, Route route, RateLimitProperties.Policy policy) {
        // 獲取當前 policy 的索引
        int indexOf = properties.getPolicies(route.getId()).indexOf(policy);

        final List<RateLimitProperties.Policy.Type> types = policy.getType().stream().map(RateLimitProperties.Policy.MatchType::getType).collect(Collectors.toList());
        final StringJoiner joiner = new StringJoiner(":");
        joiner.add(properties.getKeyPrefix());
        if (route != null) {
            joiner.add(route.getId());
        }
        if (!types.isEmpty()) {
            if (types.contains(RateLimitProperties.Policy.Type.URL) && route != null) {
                joiner.add(route.getPath());
            }
            if (types.contains(RateLimitProperties.Policy.Type.ORIGIN)) {
                joiner.add(rateLimitUtils.getRemoteAddress(request));
            }
            if (types.contains(RateLimitProperties.Policy.Type.USER)) {
                joiner.add(rateLimitUtils.getUser(request));
            }
        }
        
        // 添加索引
        joiner.add(String.valueOf(indexOf));

        return joiner.toString();

    }
}

其它限流配置項

# redis
spring.redis.port=6379
spring.redis.host=127.0.0.1
spring.redis.timeout=2000

# 開啟限流
zuul.ratelimit.enabled=true
# 對應用來標識請求的key的前綴
zuul.ratelimit.key-prefix=hello-feign
zuul.ratelimit.repository=redis
# 代理之后
zuul.ratelimit.behind-proxy=true


免責聲明!

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



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