Spring Cloud Gateway 扩展支持动态限流

Stella981
• 阅读 1271

之前分享过 一篇 《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 依赖

    <!--Spring Cloud Alibaba 封装的 sentinel 模块-->
    <dependency>
        <groupid>com.alibaba.cloud</groupid>
        <artifactid>spring-cloud-alibaba-sentinel-gateway</artifactid>
    </dependency>
    
    <!--使用nacos 保存限流规则-->
    <dependency>
        <groupid>com.alibaba.csp</groupid>
        <artifactid>sentinel-datasource-nacos</artifactid>
    </dependency>
    

    配置本地路由规则及其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数据源中的限流策略

    Spring Cloud Gateway  扩展支持动态限流

    • 常用限流策略 常量

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

    效果演示

    • 以上nacos 配置为 每秒只能通过5个请求,我们使用jmeter 4.0 来并发10个线程测试一下 Spring Cloud Gateway  扩展支持动态限流 Spring Cloud Gateway  扩展支持动态限流 Spring Cloud Gateway  扩展支持动态限流

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

    动态修改限流参数

    • sentinel-datasource-nacos 作为sentinel的数据源,可以从如上 nacos 管理台实时刷新限流参数及其阈值
    • 目前sentinel dashboard 1.6.2 暂未实现gateway 流控图形化控制 , 1.7.0 会增加此功能

    总结

    Spring Cloud Gateway  扩展支持动态限流

    欢迎关注我们获得更多的好玩JavaEE 实践

    点赞
    收藏
    评论区
    推荐文章
    blmius blmius
    3年前
    MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
    文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
    皕杰报表之UUID
    ​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
    待兔 待兔
    4个月前
    手写Java HashMap源码
    HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
    Jacquelyn38 Jacquelyn38
    3年前
    2020年前端实用代码段,为你的工作保驾护航
    有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
    Stella981 Stella981
    3年前
    Spring Cloud Gateway 原生的接口限流该怎么玩
    关于pig:基于SpringCloud、oAuth2.0开发基于Vue前后分离的开发平台,支持账号、短信、SSO等多种登录,提供配套视频开发教程。码云地址:https://gitee.com/log4j/pig(https://gitee.com/log4j/pig)关于SpringCloudGat
    Stella981 Stella981
    3年前
    Nepxion Discovery 5.5.0 发布
    !(https://oscimg.oschina.net/oscnet/f81c043194ef4732880459d00c1a720e.png)发布日志功能更新:增加基于Opentracing调用链的支持,目前支持UberJaeger,实现在SpringCloudGateway、Zuul和服务上的灰度
    Wesley13 Wesley13
    3年前
    00:Java简单了解
    浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
    Stella981 Stella981
    3年前
    Django中Admin中的一些参数配置
    设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
    Wesley13 Wesley13
    3年前
    MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
    背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
    Python进阶者 Python进阶者
    10个月前
    Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
    大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这