java 单机接口限流处理方案
655
2022-11-05
【云原生&微服务>SCG网关篇十二】Spring Cloud Gateway集成Sentinel API实现多种限流方式
文章目录
一、前言二、Gateway集成Sentinel API
0、集成Sentinel的核心概念
1)GatewayFlowRule 和 ApiDefinition2)GatewayFlowRule字段解释
1、针对Route维度限流
验证
2、针对API维度限流
验证
3、自定义限流异常返回值
验证
三、总结
一、前言
至此微服务网关系列文章已出:
【云原生&微服务>SCG网关篇一】为什么要有网关、生产环境如何选择网关云原生&微服务>SCG网关篇二】生产上那些灰度发布方式【云原生&微服务>SCG网关篇三】Spring Cloud Gateway是什么、详细使用案例云原生&微服务>SCG网关篇四】Spring Cloud Gateway内置的11种PredicateFactory如何使用【云原生&微服务>SCG网关篇五】Spring Cloud Gateway自定义PredicateFactory【云原生&微服务>SCG网关篇六】Spring Cloud Gateway内置的18种Filter使用姿势【云原生&微服务>SCG网关篇七】Spring Cloud Gateway基于内置Filter实现限流、熔断、重试【云原生&微服务>SCG网关篇八】Spring Cloud Gateway三种自定义Filter、GlobalFilter的方式【云原生&微服务>SCG网关篇九】Spring Cloud Gateway集成Nacos详细案例【云原生&微服务>SCG网关篇十】Spring Cloud Gateway集成Actuator、Zipkin详细案例【云原生&微服务>SCG网关篇十一】Spring Cloud Gateway解决跨域问题
聊了以下问题:
为什么要有网关?网关的作用是什么?网关的分类?网关的技术选型?使用网关时常用的灰度发布方式有哪些?Spring Cloud Gateway是什么?详细使用案例?Spring Cloud Gateway内置的11种PredicateFactory如何自定义PredicateFactory?Spring Cloud Gateway内置的18种常用的FilterSpring Cloud Gateway基于内置Filter实现限流、熔断、重试Spring Cloud Gateway三种自定义Filter、GlobalFilter的方式Spring Cloud Gateway集成Nacos案例Spring Cloud Gateway集成Actuator、Zipkin案例Spring Cloud Gareway如何解决CORS跨域问题
我们已经聊过了Spring Cloud Gateway的一种限流方式:使用内置的Filter(RequestRateLimiterGatewayFilterFactory)结合Redis使用令牌桶算法实现限流;这里我们再聊一下另外一种:Spring Cloud Gateway集成Sentinel实现限流。
PS:SpringCloud版本信息:
二、Gateway集成Sentinel API
sentinel服务1.6.0以上的版本可支持整合到网关进行统一流控:
sentinel提供了两种资源维度的限流:
route维度:在配置文件中配置路由,资源名为对应的 routeId,一般是对某个微服务进行限流;这种维度属于粗粒度的限流。自定义API维度:通过Sentinel 提供的API来自定义一些API分组,针对某一类的uri进行匹配限流,可以跨多个微服务;这种维度属于细粒度的限流。
gateway整合sentinel默认不支持 URL 粒度限流;因此通过 Spring Cloud Alibaba 接入时,将spring.cloud.sentinel.filter.enabled 配置为 false,以关闭流控控制台上的 URL 资源视图。
gateway整合Sentinel的maven依赖:
0、集成Sentinel的核心概念
整体集成原理如下:
1)GatewayFlowRule 和 ApiDefinition
网关的限流规则GatewayFlowRule:
针对 API Gateway 的场景定制的限流规则,可以针对不同 route 或自定义的 API 分组进行限流,支持针对请求中的参数、Header、来源 IP 等进行定制化的限流;
用户自定义的API分组ApiDefinition:
ApiDefinition可以看做是一些 URL 匹配的组合;限流的时候可以针对这个自定义的 API 分组进行限流。
2)GatewayFlowRule字段解释
网关限流规则 GatewayFlowRule 的字段如下:
resource:资源名称,可以是网关中的 route 名称或者用户自定义的 API 分组名称。resourceMode:规则是针对 API Gateway 的 route(RESOURCE_MODE_ROUTE_ID)还是用户在 Sentinel 中定义的 API 分组(RESOURCE_MODE_CUSTOM_API_NAME),默认是 route。grade:限流指标维度,同限流规则的 grade 字段。count:限流阈值intervalSec:统计时间窗口,单位是秒,默认是 1 秒。controlBehavior:流量整形的控制效果,同限流规则的 controlBehavior 字段,目前支持快速失败和匀速排队两种模式,默认是快速失败。burst:应对突发请求时额外允许的请求数目。maxQueueingTimeoutMs:匀速排队模式下的最长排队时间,单位是毫秒,仅在匀速排队模式下生效。paramItem:参数限流配置。若不提供,则代表不针对参数进行限流,该网关规则将会被转换成普通流控规则;否则会转换成热点规则。其中的字段:parseStrategy:从请求中提取参数的策略,目前支持提取来源 IP(PARAM_PARSE_STRATEGY_CLIENT_IP)、Host(PARAM_PARSE_STRATEGY_HOST)、任意 Header(PARAM_PARSE_STRATEGY_HEADER)和任意 URL 参数(PARAM_PARSE_STRATEGY_URL_PARAM)四种模式。fieldName:若提取策略选择 Header 模式或 URL 参数模式,则需要指定对应的 header 名称或 URL 参数名称。pattern:参数值的匹配模式,只有匹配该模式的请求属性值会纳入统计和流控;若为空则统计该请求属性的所有值。(1.6.2 版本开始支持)matchStrategy:参数值的匹配策略,目前支持精确匹配(PARAM_MATCH_STRATEGY_EXACT)、子串匹配(PARAM_MATCH_STRATEGY_CONTAINS)和正则匹配(PARAM_MATCH_STRATEGY_REGEX)。(1.6.2 版本开始支持)
可以通过GatewayRuleManager.loadRules(rules) 手动加载网关规则、 或 通过 GatewayRuleManager.register2Property(property) 注册规则(推荐方式);
特别注意:当使用 Spring Cloud Alibaba Sentinel 数据源模块时,需要注意网关流控规则数据源类型是 gw-flow,若将网关流控规则数据源指定为 flow 则不生效。
application.yml配置文件:
spring: application: name: nacos-gateway cloud: nacos: discovery: server-addr: 106.15.139.143:8848 gateway: discovery: locator: # 开启从注册中心动态创建路由的功能 enabled: true # 是否使用service-id的小写,默认是大写 lower-case-service-id: true routes: - id: gateway-nacos-service-route # 其中配置的lb://表示从注册中心获取服务,后面的gateway-nacos-provider表示目标服务在注册中心上的服务名 uri: lb://gateway-nacos-provider predicates: - Path=/nacos/sentinel/** #被限流 filters: - StripPrefix=2 # 自定义Sentinel API分组限流 - id: red_route uri: lb://gateway-nacos-provider predicates: - Path=/red/** #被限流 filters: - StripPrefix=1 - id: green_route uri: lb://gateway-nacos-provider predicates: - Path=/green/** #不被限流 filters: -
下面的三个样例均依赖此application.yml配置文件。
1、针对Route维度限流
搞一个ConfigurationClass,在类初始化的最后阶段(@PostConstruct标注的方法)实例化一个GatewayFlowRule,并将其添加到GatewayRuleManager中;GatewayFlowRule中指定针对哪个Route限流、限流的规则是什么?
package com.saint.gateway.sentinel;import java.util.Collections;import java.util.HashSet;import java.util.List;import java.util.Set;import javax.annotation.PostConstruct;import org.springframework.beans.factory.ObjectProvider;import org.springframework.cloud.gateway.filter.GlobalFilter;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.core.Ordered;import org.springframework.core.annotation.Order;import org.springframework.org.springframework.web.reactive.result.view.ViewResolver;import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler;/** * 针对某个Route限流 * * @author Saint */@Configurationpublic class GatewayConfiguration { private final List> viewResolvers, ServerCodecConfigurer serverCodecConfigurer) { this.viewResolvers = viewResolvers.getIfAvailable(Collections::emptyList); this.serverCodecConfigurer = serverCodecConfigurer; } /** * 注入一个全局限流过滤器SentinelGatewayFilter * Filter的优先级最高 */ @Bean @Order(Ordered.HIGHEST_PRECEDENCE) public GlobalFilter sentinelGatewayFilter() { return new SentinelGatewayFilter(); } /** * 注入限流异常处理器 * Filter的优先级最高 */ @Bean @Order(Ordered.HIGHEST_PRECEDENCE) public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() { return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer); } /** * 初始化限流规则 */ @PostConstruct public void doInit() { initGatewayRules(); } /** * Route维度限流规则 */ private void initGatewayRules() { Set
当前案例表示针对routeId为gateway-nacos-service-route的路由做限流:1s仅允许一个请求通过;
验证
当请求被限流时会返回429状态码,响应体内容为:
{"code":429,"message":"Blocked by Sentinel: ParamFlowException"}
2、针对API维度限流
自定义API分组限流,将/nacos/sentinel/**和/red/**进行统一分组,并提供name=saint_customized_api,然后在初始化网关限流规则时,针对该name设置限流规则;
package com.saint.gateway.sentinel;import java.util.Collections;import java.util.HashSet;import java.util.List;import java.util.Set;import javax.annotation.PostConstruct;import org.springframework.beans.factory.ObjectProvider;import org.springframework.cloud.gateway.filter.GlobalFilter;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.core.Ordered;import org.springframework.core.annotation.Order;import org.springframework.org.springframework.web.reactive.result.view.ViewResolver;import com.alibaba.csp.sentinel.adapter.gateway.common.SentinelGatewayConstants;import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition;import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPathPredicateItem;import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPredicateItem;import com.alibaba.csp.sentinel.adapter.gateway.common.api.GatewayApiDefinitionManager;import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler;/** * 自定义API分组限流 * * @author Saint */@Configurationpublic class GatewayConfiguration1 { private final List> viewResolvers, ServerCodecConfigurer serverCodecConfigurer) { this.viewResolvers = viewResolvers.getIfAvailable(Collections::emptyList); this.serverCodecConfigurer = serverCodecConfigurer; } /** * 注入SentinelGatewayFilter * Filter的优先级最高 */ @Bean @Order(Ordered.HIGHEST_PRECEDENCE) public GlobalFilter sentinelGatewayFilter() { return new SentinelGatewayFilter(); } /** * 注入限流异常处理器 * Filter的优先级最高 */ @Bean @Order(Ordered.HIGHEST_PRECEDENCE) public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() { return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer); } /** * 初始化限流规则 */ @PostConstruct public void doInit() { initCustomizedApis(); initGatewayRules(); } /** * 自定义API分组限流,将/nacos/sentinel/**和/red/**进行统一分组,并提供name=saint_customized_api,然后在初始化网关限流规则时,针对该name设置 * 限流规则。同时,可以通过setMatchStrategy来设置不同path下的限流参数策略 */ private void initCustomizedApis() { Set
验证
当我们访问/nacos/sentinel/**和/red/**路径时才会被限流,其他路径均不会。
3、自定义限流异常返回值
Sentinel默认的异常处理器是com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler,我们可以根据这个Handler自定义一个WebExceptionHandler实现类。
1> 自定义WebExceptionHandler实现类:
package com.saint.gateway.sentinel;import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;import com.alibaba.csp.sentinel.slots.block.BlockException;import com.alibaba.csp.sentinel.util.function.Supplier;import org.springframework.core.io.buffer.DataBuffer;import org.springframework.org.springframework.org.springframework.org.springframework.web.reactive.function.server.ServerResponse;import org.springframework.web.reactive.result.view.ViewResolver;import org.springframework.web.server.ServerWebExchange;import org.springframework.web.server.WebExceptionHandler;import reactor.core.publisher.Mono;import java.util.List;/** * 异常处理器 */public class MySentinelGatewayBlockExceptionHandler implements WebExceptionHandler { private List
2> 将MySentinelGatewayBlockExceptionHandler注入到Spring容器中:
// 注入自定义的限流异常处理器@Bean@Order(Ordered.HIGHEST_PRECEDENCE)public MySentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() { return new MySentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);}
验证
接着根据API分组限流的案例进行验证;
响应的状态码是200,body是我们自定义的body:
{"code":999,"msg":"访问人数太多了,让我歇歇吧"}
三、总结
sentinel提供了两种资源维度的限流:
route维度:在配置文件中配置路由,资源名为对应的 routeId,一般是对某个微服务进行限流;这种维度属于粗粒度的限流。自定义API维度:通过Sentinel 提供的API来自定义一些API分组,针对某一类的uri进行匹配限流,可以跨多个微服务;这种维度属于细粒度的限流。
本文的演示案例基于文章()
PS:Sentinel整合Nacos配置源:
spring: cloud: #配置SpringCloudGateway的路由 sentinel: transport: dashboard: ip:port #sentinel控制台的请求地址 datasource: ds1: nacos: server-addr: ip:port data-id: ${spring.application.name}-${spring.profiles.active}-sentinel-gw-flow group-id: DEFAULT_GROUP data-type: json # 流控规则 rule-type: gw-flow ds2: nacos: server-addr: ip:port data-id: ${spring.application.name}-${spring.profiles.active}-sentinel-gw-api-group group-id: DEFAULT_GROUP data-type: json # api类型 rule-type: gw-api-group eager: true #立即加载 log: # 日志存放目录 dir:
引入maven依赖:
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~