千家信息网

Spring Cloud中怎么利用Gateway实现扩展支持动态限流

发表于:2024-11-23 作者:千家信息网编辑
千家信息网最后更新 2024年11月23日,本篇文章为大家展示了Spring Cloud中怎么利用Gateway实现扩展支持动态限流,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。原生RequestRat
千家信息网最后更新 2024年11月23日Spring Cloud中怎么利用Gateway实现扩展支持动态限流

本篇文章为大家展示了Spring Cloud中怎么利用Gateway实现扩展支持动态限流,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。

原生RequestRateLimiter 的不足

  • 配置方式

spring:  cloud:    gateway:      routes:      - id: requestratelimiter_route        uri: lb://pigx-upms        order: 10000        predicates:        - Path=/admin/**        filters:        - name: RequestRateLimiter          args:            redis-rate-limiter.replenishRate: 1              redis-rate-limiter.burstCapacity: 3            key-resolver: "#{@remoteAddrKeyResolver}" #SPEL表达式去的对应的bean        - StripPrefix=1
  • RequestRateLimiterGatewayFilterFactory

public GatewayFilter apply(Config config) {        KeyResolver resolver = getOrDefault(config.keyResolver, defaultKeyResolver);        RateLimiter limiter = getOrDefault(config.rateLimiter,                        defaultRateLimiter);        boolean denyEmpty = getOrDefault(config.denyEmptyKey, this.denyEmptyKey);        HttpStatusHolder emptyKeyStatus = HttpStatusHolder                        .parse(getOrDefault(config.emptyKeyStatus, this.emptyKeyStatusCode));        return (exchange, chain) -> {                                return exchange.getResponse().setComplete();                        });                });        };}
  • 在实际生产过程中,必定不能满足我们的需求

    生产中路由信息是保存数据库持久化或者配置中心,RequestRateLimiterGatewayFilterFactory 并不能随着持久化数据的改变而动态改变限流参数,不能做到实时根据流量来改变流量阈值

Sentinel Spring Cloud Gateway 流控支持

Sentinel 是什么?

随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性,分布式系统的流量防卫兵。
从 1.6.0 版本开始,Sentinel 提供了 Spring Cloud Gateway 的适配模块,可以提供两种资源维度的限流: route 维度:即在 Spring 配置文件中配置的路由条目,资源名为对应的 routeId 自定义 API 维度:用户可以利用 Sentinel 提供的 API 来自定义一些 API 分组

pom 依赖

    com.alibaba.cloud    spring-cloud-alibaba-sentinel-gateway    com.alibaba.csp    sentinel-datasource-nacos

配置本地路由规则及其sentinel数据源

spring:  application:    name: sentinel-spring-cloud-gateway  cloud:    gateway:      enabled: true      discovery:        locator:          lower-case-service-id: true      routes:      - id: pigx_route        uri: https://api.readhub.cn        predicates:        - Path=/topic/**    sentinel:      datasource.ds1.nacos:        server-addr: 127.0.0.1:8848        data-id: gw-flow        group-id: DEFAULT_GROUP        ruleType: gw-api-group      filter:        enabled: true

配置nacos数据源中的限流策略

  • 常用限流策略 常量

以客户端IP作为限流因子public static final int PARAM_PARSE_STRATEGY_CLIENT_IP = 0;以客户端HOST作为限流因子public static final int PARAM_PARSE_STRATEGY_HOST = 1;以客户端HEADER参数作为限流因子public static final int PARAM_PARSE_STRATEGY_HEADER = 2;以客户端请求参数作为限流因子public static final int PARAM_PARSE_STRATEGY_URL_PARAM = 3;以客户端请求Cookie作为限流因子public static final int PARAM_PARSE_STRATEGY_COOKIE = 4;
  • 核心源码解析 SentinelGatewayFilter

sentinel通过扩展Gateway的过滤器,通过选择的不同GatewayParamParser 过处理请求限流因子和数据源中的配置进行比较 源码如下:

public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {    Route route = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);    Mono asyncResult = chain.filter(exchange);    if (route != null) {        String routeId = route.getId();        Object[] params = paramParser.parseParameterFor(routeId, exchange,            r -> r.getResourceMode() == SentinelGatewayConstants.RESOURCE_MODE_ROUTE_ID);        String origin = Optional.ofNullable(GatewayCallbackManager.getRequestOriginParser())            .map(f -> f.apply(exchange))            .orElse("");        asyncResult = asyncResult.transform(            new SentinelReactorTransformer<>(new EntryConfig(routeId, EntryType.IN,                1, params, new ContextConfig(contextName(routeId), origin)))        );    }    Set matchingApis = pickMatchingApiDefinitions(exchange);    for (String apiName : matchingApis) {        Object[] params = paramParser.parseParameterFor(apiName, exchange,            r -> r.getResourceMode() == SentinelGatewayConstants.RESOURCE_MODE_CUSTOM_API_NAME);        asyncResult = asyncResult.transform(            new SentinelReactorTransformer<>(new EntryConfig(apiName, EntryType.IN, 1, params))        );    }    return asyncResult;}

效果演示

  • 以上nacos 配置为 每秒只能通过5个请求,我们使用jmeter 4.0 来并发10个线程测试一下

  • 通过上图可以结果证明sentinel限流确实有效

动态修改限流参数

  • sentinel-datasource-nacos 作为sentinel的数据源,可以从如上 nacos 管理台实时刷新限流参数及其阈值

  • 目前sentinel dashboard 1.6.2 暂未实现gateway 流控图形化控制 , 1.7.0 会增加此功能

上述内容就是Spring Cloud中怎么利用Gateway实现扩展支持动态限流,你们学到知识或技能了吗?如果还想学到更多技能或者丰富自己的知识储备,欢迎关注行业资讯频道。

0