首页 > 其他分享 >阿里巴巴开源限流组件Sentinel初探之集成Gateway

阿里巴巴开源限流组件Sentinel初探之集成Gateway

时间:2022-10-07 22:04:52浏览次数:52  
标签:API PARAM STRATEGY 限流 Sentinel import Gateway


1 Sentinel主页

​github.com/alibaba/Sen…​

1.1 Sentinel介绍

阿里巴巴开源限流组件Sentinel初探之集成Gateway_spring

随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式服务架构的流量控制组件,主要以流量为切入点,从限流、流量整形、熔断降级、系统负载保护、热点防护等多个维度来帮助开发者保障微服务的稳定性。

1)Sentinel核心组件

1:核心库(Java 客户端):不依赖任何框架/库,能够运行于 Java 7 及以上的版本的运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。

2:控制台(Dashboard):控制台主要负责管理推送规则、监控、集群限流分配管理、机器发现等。

2)Sentinel vs Hystrix

对比内容

Sentinel

Hystrix

隔离策略

信号量隔离

线程池隔离/信号量隔离

熔断降级策略

基于响应时间或失败比率

基于失败比率

实时指标实现

滑动窗口

滑动窗口(基于 RxJava)

规则配置

支持多种数据源

支持多种数据源

扩展性

多个扩展点

插件的形式

基于注解的支持

支持

支持

限流

基于 QPS,支持基于调用关系的限流

不支持

流量整形

支持慢启动、匀速器模式

不支持

系统负载保护

支持

不支持

控制台

开箱即用,可配置规则、查看秒级监控、机器发现等

不完善

常见框架的适配

Servlet、Spring Cloud、Dubbo、gRPC 等

Servlet、Spring Cloud Netflix

3)Sentinel基本概念

  • 资源
资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何内容,例如,由应用程序提供的服务,或由应用程序调用的其它应用提供的服务,甚至可以是一段代码。

只要通过 Sentinel API 定义的代码,就是资源,能够被 Sentinel 保护起来。大部分情况下,可以使用方法签名,URL,甚至服务名称作为资源名来标示资源。
  • 规则
围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则。所有规则可以动态实时调整。

1.2 Sentinel核心功能

1.2.1 流量控制

流量控制在网络传输中是一个常用的概念,它用于调整网络包的发送数据。然而,从系统稳定性角度考虑,在处理请求的速度上,也有非常多的讲究。任意时间到来的请求往往是随机不可控的,而系统的处理能力是有限的。我们需要根据系统的处理能力对流量进行控制。Sentinel 作为一个调配器,可以根据需要把随机的请求调整成合适的形状,如下图所示:

阿里巴巴开源限流组件Sentinel初探之集成Gateway_Java_02

流量控制有以下几个角度:

  • 资源的调用关系,例如资源的调用链路,资源和资源之间的关系;
  • 运行指标,例如 QPS、线程池、系统负载等;
  • 控制的效果,例如直接限流、冷启动、排队等。

Sentinel 的设计理念是让您自由选择控制的角度,并进行灵活组合,从而达到想要的效果。

1.2.2 熔断降级

1)什么是熔断降级

除了流量控制以外,及时对调用链路中的不稳定因素进行熔断也是 Sentinel 的使命之一。由于调用关系的复杂性,如果调用链路中的某个资源出现了不稳定,可能会导致请求发生堆积,进而导致级联错误。

阿里巴巴开源限流组件Sentinel初探之集成Gateway_spring_03

Sentinel 和 Hystrix 的原则是一致的: 当检测到调用链路中某个资源出现不稳定的表现,例如请求响应时间长或异常比例升高的时候,则对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联故障。

2)Sentinel熔断降级设计

Hystrix 通过 线程池隔离 的方式,来对依赖(在 Sentinel 的概念中对应 资源)进行了隔离。这样做的好处是资源和资源之间做到了最彻底的隔离。缺点是除了增加了线程切换的成本(过多的线程池导致线程数目过多),还需要预先给各个资源做线程池大小的分配。

Sentinel熔断降级设计:

并发线程数限制:和资源池隔离的方法不同,Sentinel 通过限制资源并发线程的数量,来减少不稳定资源对其它资源的影响。这样不但没有线程切换的损耗,也不需要您预先分配线程池的大小。当某个资源出现不稳定的情况下,例如响应时间变长,对资源的直接影响就是会造成线程数的逐步堆积。当线程数在特定资源上堆积到一定的数量之后,对该资源的新请求就会被拒绝。堆积的线程完成任务后才开始继续接收请求。

响应时间降级:除了对并发线程数进行控制以外,Sentinel 还可以通过响应时间来快速降级不稳定的资源。当依赖的资源出现响应时间过长后,所有对该资源的访问都会被直接拒绝,直到过了指定的时间窗口之后才重新恢复。

3)系统自适应保护

Sentinel 同时提供系统维度的自适应保护能力。防止雪崩,是系统防护中重要的一环。当系统负载较高的时候,如果还持续让请求进入,可能会导致系统崩溃,无法响应。在集群环境下,网络负载均衡会把本应这台机器承载的流量转发到其它的机器上去。如果这个时候其它的机器也处在一个边缘状态的时候,这个增加的流量就会导致这台机器也崩溃,最后导致整个集群不可用。

针对这个情况,Sentinel 提供了对应的保护机制,让系统的入口流量和系统的负载达到一个平衡,保证系统在能力范围之内处理最多的请求。

Sentinel集成Gateway

我们的项目流量入口是​​SpringCloud Gateway​​​,因此我们重点讲解Sentinel集成​​Gateway​​。

3.1 Sentinel对网关支持

Sentinel 支持对 Spring Cloud Gateway、Zuul 等主流的 API Gateway 进行限流。

阿里巴巴开源限流组件Sentinel初探之集成Gateway_Java_04

Sentinel 1.6.0 引入了 ​​Sentinel API Gateway Adapter Common​​ 模块,此模块中包含网关限流的规则和自定义 API 的实体和管理逻辑

从 1.6.0 版本开始,Sentinel 提供了 Spring Cloud Gateway 的适配模块,可以提供两种资源维度的限流:

  • route 维度:即在 Spring 配置文件中配置的路由条目,资源名为对应的 routeId

spring: gateway: #路由配置 routes: #唯一标识符 - id: hailtaxi-driver uri: lb://hailtaxi-driver #路由断言 predicates: - Path=/driver/** #唯一标识符 - id: hailtaxi-order uri: lb://hailtaxi-order #路由断言 predicates: - Path=/order/**

自动将每个路由标识为资源,

  • 自定义 API 维度:用户可以利用 Sentinel 提供的 API 来自定义一些 API 分组
    这两种维度分别对应如下:
  • GatewayFlowRule:网关限流规则,针对 API Gateway 的场景定制的限流规则,可以针对不同 route 或自定义的 API 分组进行限流,支持针对请求中的参数、Header、来源 IP 等进行定制化的限流。
  • ApiDefinition:用户自定义的 API 定义分组,可以看做是一些 URL 匹配的组合。比如我们可以定义一个 API 叫 ​​my_api​​,请求 path 模式为 ​​/foo/**​​ 和 ​​/baz/**​​ 的都归到 ​​my_api​​ 这个 API 分组下面。限流的时候可以针对这个自定义的 API 分组维度进行限流。

其中网关限流规则 ​​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)​​ 注册动态规则源动态推送(推荐方式)。

3.2 GateWay集成Sentinel

阿里巴巴开源限流组件Sentinel初探之集成Gateway_ide_05

我们如果想要让微服务网关集成Sentinel,需要引入依赖包,使用时只需注入对应的 ​​SentinelGatewayFilter​​​ 实例以及 ​​SentinelGatewayBlockExceptionHandler​​ 实例即可。

1、首先在​​hailtaxi-gateway​​中引入如下依赖:

<!--Sentinel-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
<version>1.8.0</version>
</dependency>

2、实例引入:创建配置类​​com.itheima.config.GatewayConfiguration​​:

package com.itheima.config;

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.GatewayParamFlowItem;
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;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
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.http.codec.ServerCodecConfigurer;
import org.springframework.web.reactive.result.view.ViewResolver;

import javax.annotation.PostConstruct;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Configuration
public class GatewayConfiguration {

private final List<ViewResolver> viewResolvers;
private final ServerCodecConfigurer serverCodecConfigurer;

public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider,
ServerCodecConfigurer serverCodecConfigurer) {
this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
this.serverCodecConfigurer = serverCodecConfigurer;
}

/**
* 限流的异常处理器
* @return
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
}

/***
* Sentinel路由处理核心过滤器
* @return
@Bean
@Order(-1)
public GlobalFilter sentinelGatewayFilter() {
return new SentinelGatewayFilter();
}



@PostConstruct
public void doInit() {
// 自定义 api 分组
initCustomizedApis();
// 初始化网关流控规则
initGatewayRules();
}

private void initCustomizedApis() {
Set<ApiDefinition> definitions = new HashSet<>();
ApiDefinition api1 = new ApiDefinition("customer_api")
.setPredicateItems(new HashSet<ApiPredicateItem>() {{
add(new ApiPathPredicateItem().setPattern("/order/**")
/**
* 匹配策略:
* URL_MATCH_STRATEGY_EXACT:url精确匹配
* URL_MATCH_STRATEGY_PREFIX:url前缀匹配
* URL_MATCH_STRATEGY_REGEX:url正则匹配
*/
.setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
}});
definitions.add(api1);
GatewayApiDefinitionManager.loadApiDefinitions(definitions);
}

private void initGatewayRules() {
Set<GatewayFlowRule> rules = new HashSet<>();

rules.add(new GatewayFlowRule("hailtaxi-driver") // 资源名称,可以是网关中的 routeid或者用户自定义的 API分组名称
.setCount(2) // 限流阈值
.setIntervalSec(10) // 统计时间窗口默认1s
.setGrade(RuleConstant.FLOW_GRADE_QPS) // 限流模式
/**
* 限流行为:
* CONTROL_BEHAVIOR_RATE_LIMITER 匀速排队
* CONTROL_BEHAVIOR_DEFAULT 快速失败(默认)
* CONTROL_BEHAVIOR_WARM_UP:
* CONTROL_BEHAVIOR_WARM_UP_RATE_LIMITER:
*/
.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)
//匀速排队模式下的最长排队时间,单位是毫秒,仅在匀速排队模式下生效
.setMaxQueueingTimeoutMs(1000)
/**
* 热点参数限流配置
* 若不设置,该网关规则将会被转换成普通流控规则;否则会转换成热点规则
*/
.setParamItem(new GatewayParamFlowItem()
/**
* 从请求中提取参数的策略:
* PARAM_PARSE_STRATEGY_CLIENT_IP
* PARAM_PARSE_STRATEGY_HOST
* PARAM_PARSE_STRATEGY_HEADER
* PARAM_PARSE_STRATEGY_URL_PARAM
*/
.setParseStrategy(SentinelGatewayConstants.PARAM_PARSE_STRATEGY_HEADER)
/**
* 若提取策略选择 Header 模式或 URL 参数模式,
* 则需要指定对应的 header 名称或 URL 参数名称。
*/
.setFieldName("token")
/**
* 参数的匹配策略:
* PARAM_MATCH_STRATEGY_EXACT
* PARAM_MATCH_STRATEGY_PREFIX
* PARAM_MATCH_STRATEGY_REGEX
* PARAM_MATCH_STRATEGY_CONTAINS
*/
.setMatchStrategy(SentinelGatewayConstants.PARAM_MATCH_STRATEGY_EXACT)
//参数值的匹配模式,只有匹配该模式的请求属性值会纳入统计和流控
.setPattern("123456") // token=123456 10s内qps达到2次会被限流
)
);

rules.add(new GatewayFlowRule("customer_api")
/**
* 规则是针对 API Gateway 的 route(RESOURCE_MODE_ROUTE_ID)
* 还是用户在 Sentinel 中定义的 API 分组(RESOURCE_MODE_CUSTOM_API_NAME),默认是 route。
*/
.setResourceMode(SentinelGatewayConstants.RESOURCE_MODE_CUSTOM_API_NAME)
.setCount(2)
.setIntervalSec(1)
.setGrade(RuleConstant.FLOW_GRADE_QPS)
);
GatewayRuleManager.loadRules(rules);
}


}

此时集成就完成了。

3、启动​​hailtaxi-gateway​​​,​​hailtaxi-drvier​​​,​​hailtaxi-order​​测试:

使用postman测试,

请求:​​http://localhost:8001/driver/info/1​​ 10秒内请求超过2次会被限流

请求:​​localhost:8001/order​​ 1秒内qps达到2次会被限

标签:API,PARAM,STRATEGY,限流,Sentinel,import,Gateway
From: https://blog.51cto.com/boxuegu/5735138

相关文章