spring cloud gateway 网关限流

spring cloud gateway 通过redis限流原理

https://blog.csdn.net/weixin_38405253/article/details/108891772

缓存降级 和 限流 被称为高并发、分布式系统的三驾马车

网关作为整个分布式系统中的第一道关卡

限流被称为 请求频率限流(Request rate limiting)和 并发量限流(Concurrent requests limiting)。

限流的处理方式:拒绝服务, 排队等待, 服务降级。

限流架构:网关层限流 和 中间件限流。

限流算法:

       固定窗口算法(Fixed Window)

  滑动窗口算法(Rolling Window 或 Sliding Window)

  漏桶算法(Leaky Bucket)

  令牌桶算法(Token Bucket)

复制代码
spring:
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
          lowerCaseServiceId: true
      predicate:
        weight:
          enabled: false
      routes:
         #test服务
        - id: ihs-test
          uri: lb://ihs-test
          predicates:
            - Path=/tests/**
          filters:
            - StripPrefix=1
            - name: NewRequestRateLimiter
              args:  
                key-resolver: "#{@remoteHostLimitationKey}"
                # rate-limter: "#{@customerRateLimiter}"
                # status-code: "BANDWIDTH_LIMIT_EXCEEDED"
                redis-rate-limiter.replenishRate: 100 #生成令牌速率:个/秒
                redis-rate-limiter.burstCapacity: 200 #令牌桶容量
                redis-rate-limiter.requestedTokens: 1 #每次消费的Token数量,默认是 1
复制代码

 

 

复制代码
@Configuration
public class RedisLimitationConfig {

    // 限流的维度
    @Bean
    @Primary
    public KeyResolver remoteHostLimitationKey() {
        return exchange -> Mono.just(
                exchange.getRequest()
                        .getRemoteAddress()
                        .getAddress()
                        .getHostAddress()
                //Mono.just(exchange.getRequest().getPath().value());
        );
    }

    //template服务限流规则
    /*@Bean("tempalteRateLimiter")
    public RedisRateLimiter templateRateLimiter() {
        //第一个参数表示每秒发放的令牌数量 第二个参数表示令牌桶的容量
        return new RedisRateLimiter(1, 1);
    }*/

    // customer服务限流规则
   /* @Bean("customerRateLimiter")
    public RedisRateLimiter customerRateLimiter() {
        return new RedisRateLimiter(1, 1);
    }*/

    /*@Bean("defaultRateLimiter")
    @Primary
    public RedisRateLimiter defaultRateLimiter() {
        return new RedisRateLimiter(1, 1);
    }*/
}
复制代码

 

复制代码
/**
 * 网关限流过滤器
 */
@Component
public class NewRequestRateLimiterGatewayFilterFactory extends RequestRateLimiterGatewayFilterFactory {

    private final RateLimiter defaultRateLimiter;

    private final KeyResolver remoteHostLimitationKey;

    private boolean denyEmptyKey = true;

    private String emptyKeyStatusCode = HttpStatus.FORBIDDEN.name();

    public NewRequestRateLimiterGatewayFilterFactory(RateLimiter defaultRateLimiter, KeyResolver remoteHostLimitationKey) {
        super(defaultRateLimiter, remoteHostLimitationKey);
        this.defaultRateLimiter = defaultRateLimiter;
        this.remoteHostLimitationKey = remoteHostLimitationKey;
    }

    @Override
    public GatewayFilter apply(Config config) {
        KeyResolver resolver = this.getOrDefault(config.getKeyResolver(), this.remoteHostLimitationKey);
        RateLimiter<Object> limiter = (RateLimiter)this.getOrDefault(config.getRateLimiter(), this.defaultRateLimiter);
        boolean denyEmpty = this.getOrDefault(config.getDenyEmptyKey(), this.denyEmptyKey);
        HttpStatusHolder emptyKeyStatus = HttpStatusHolder.parse(this.getOrDefault(config.getEmptyKeyStatus(), this.emptyKeyStatusCode));
        return (exchange, chain) -> {
            return resolver.resolve(exchange).defaultIfEmpty("____EMPTY_KEY__").flatMap((key) -> {
                if ("____EMPTY_KEY__".equals(key)) {
                    if (denyEmpty) {
                        ServerWebExchangeUtils.setResponseStatus(exchange, emptyKeyStatus);
                        return exchange.getResponse().setComplete();
                    } else {
                        return chain.filter(exchange);
                    }
                } else {
                    String routeId = config.getRouteId();
                    if (routeId == null) {
                        Route route = (Route)exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
                        routeId = route.getId();
                    }

                    return limiter.isAllowed(routeId, key).flatMap((response) -> {
                        Iterator var4 = response.getHeaders().entrySet().iterator();

                        while(var4.hasNext()) {
                            Map.Entry<String, String> header = (Map.Entry)var4.next();
                            exchange.getResponse().getHeaders().add((String)header.getKey(), (String)header.getValue());
                        }

                        if (response.isAllowed()) {
                            return chain.filter(exchange);
                        } else {
                            ServerHttpResponse httpResponse = exchange.getResponse();
                            httpResponse.getHeaders().set("Content-Type", "application/json");
                            Result result = Result.error("当前请求人数较多,请稍后再访问");
                            DataBuffer dataBuffer = httpResponse.bufferFactory().wrap(JSON.toJSONString(result).getBytes(StandardCharsets.UTF_8));
                            return httpResponse.writeWith(Mono.just(dataBuffer));
                        }
                    });
                }
            });
        };
    }

    private <T> T getOrDefault(T configValue, T defaultValue) {
        return configValue != null ? configValue : defaultValue;
    }
复制代码

 

posted @   Peter.Jones  阅读(15)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 推荐几款开源且免费的 .NET MAUI 组件库
· 实操Deepseek接入个人知识库
· 易语言 —— 开山篇
· Trae初体验
历史上的今天:
2020-02-12 spring-security
2019-02-12 设计模式研究
点击右上角即可分享
微信分享提示