8

SpringCloud系列教程(六)之SpringCloud 使用sentinel作为熔断器

 2 years ago
source link: https://blog.winterchen.com/2021/08/05/2021-08-05-spring-cloud-hoxton-6-sentinel/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

阅读提醒:

  1. 本文面向的是有一定springboot基础者
  2. 本次教程使用的Spring Cloud Hoxton RELEASE版本
  3. 由于knife4j比swagger更加友好,所以本文集成knife4j
  4. 本文依赖上一篇的工程,请查看上一篇文章以做到无缝衔接,或者直接下载源码:https://github.com/WinterChenS/spring-cloud-hoxton-study
  • 什么是熔断器
  • 什么是sentinel
  • spring cloud 整合sentinel
  • 实际的应用场景

什么是熔断器

想必大家都知道一个生活中常见的物件,保险丝,其实它就是一种熔断器,当电器出现短路故障导致瞬间电流超过瞬间值会触发熔断,导致断开电路,从而保护了整个电路和电器的安全。

熔断器(fuse)是指当电流超过规定值时,以本身产生的热量使熔体熔断,断开电路的一种电器。熔断器是根据电流超过规定值一段时间后,以其自身产生的热量使熔体熔化,从而使电路断开;运用这种原理制成的一种电流保护器。熔断器广泛应用于高低压配电系统和控制系统以及用电设备中,作为短路和过电流的保护器,是应用最普遍的保护器件之一。

可能就有同学要问了,这个跟我们说的服务的熔断器有什么关系呢?其实很多原理性的事物都跟生活息息相关的,电路的熔断,保护电路和电器。在代码的世界里,可以对服务起到流量控制和降级熔断的能力,可以做到部分服务的宕机不会导致整个服务集群的雪崩。

什么是sentinel

sentinel是阿里巴巴开源的服务治理的框架,sentinel中文译名为哨兵,是为微服务提供流量控制、熔断降级的功能,它和Hystrix提供的功能一样,可以有效的解决微服务调用产生的“雪崩”效应,为微服务系统提供了稳定性的解决方案。

随着Hytrxi进入了维护期,不再提供新功能,Sentinel是一个不错的替代方案。通常情况,Hystrix采用线程池对服务的调用进行隔离,Sentinel才用了用户线程对接口进行隔离,二者相比,Hystrxi是服务级别的隔离,Sentinel提供了接口级别的隔离,Sentinel隔离级别更加精细,另外Sentinel直接使用用户线程进行限制,相比Hystrix的线程池隔离,减少了线程切换的开销。另外Sentinel的DashBoard提供了在线更改限流规则的配置,也更加的优化。

通过官方文档的介绍,sentinel有以下特征:

  • 丰富的应用场景: Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、实时熔断下游不可用应用等。
  • 完备的实时监控: Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
  • 广泛的开源生态: Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。
  • 完善的 SPI 扩展点: Sentinel 提供简单易用、完善的 SPI 扩展点。您可以通过实现扩展点,快速的定制逻辑。例如定制规则管理、适配数据源等。

Sentinel的主要特性:

Sentinel 功能和设计理念

流量控制

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

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

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

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

除了流量控制以外,降低调用链路中的不稳定资源也是 Sentinel 的使命之一。由于调用关系的复杂性,如果调用链路中的某个资源出现了不稳定,最终会导致请求发生堆积。这个问题和 Hystrix 里面描述的问题是一样的。

Sentinel 和 Hystrix 的原则是一致的: 当调用链路中某个资源出现不稳定,例如,表现为 timeout,异常比例升高的时候,则对这个资源的调用进行限制,并让请求快速失败,避免影响到其它的资源,最终产生雪崩的效果。

Sentinel 是如何工作的

Sentinel 的主要工作机制如下:

  • 对主流框架提供适配或者显示的 API,来定义需要保护的资源,并提供设施对资源进行实时统计和调用链路分析。
  • 根据预设的规则,结合对资源的实时统计信息,对流量进行控制。同时,Sentinel 提供开放的接口,方便您定义及改变规则。
  • Sentinel 提供实时的监控系统,方便您快速了解目前系统的状态。

Spring Cloud 整合 Sentinel

注意:本文整合的工程是基于前几篇文章提供的,所以需要根据前几篇的内容一步步的搭建

下载安装sentinel dashboard

从官方的github仓库下载最新的release版本:https://github.com/alibaba/Sentinel/releases

下载完之后启动服务,端口为8748,启动命令如下:

java -Dserver.port=8748 -Dcsp.sentinel.dashboard.server=localhost:8748 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.2.jar

启动完之后登录控制台:http://localhost:8748

账号:sentinel 密码: sentinel

改造工程consumer

增加maven依赖:

<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

修改配置application.yml(只显示部分需要修改的配置):

spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
sentinel:
transport:
port: 18763 #1
dashboard: 127.0.0.1:8748

feign:
sentinel:
enabled: true #2
  1. 这里的 spring.cloud.sentinel.transport.port 端口配置会在应用对应的机器上启动一个 Http Server,该 Server 会与 Sentinel 控制台做交互。比如 Sentinel 控制台添加了一个限流规则,会把规则数据 push 给这个 Http Server 接收,Http Server 再将规则注册到 Sentinel 中。
  2. 通过feign.sentinel.enable开启Feign和sentinel的自动适配。

分别启动provider/consumer/gateway服务,然后多次请求: http://localhost:16011/nacos/feign-test/hello

注意:需要请求接口之后才可以在控制台看到对应的服务和接口。

打开控制台可以看到:

实时监控:

簇点链路:

增加流控规则

可以通过修改后面的一些控制来限制接口的一些功能,大家可以改一改尝试一下,这里就不赘述了。

可以给其他的服务:provider和auth也按照上面的步骤进行配置。

Spring Cloud Gateway使用Sentinel

在工程 gateway中修改

增加maven依赖:

<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>

修改application.yml配置文件:

spring:
cloud:
sentinel:
transport:
port: 15000
dashboard: localhost:8748

创建一个网关分组和网关的限流规则:

@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;
}

@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
// Register the block exception handler for Spring Cloud Gateway.
return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
}

@PostConstruct
public void doInit() {
initCustomizedApis();
initGatewayRules();
}

private void initCustomizedApis() {
Set<ApiDefinition> definitions = new HashSet<>();
ApiDefinition api1 = new ApiDefinition("consumer")
.setPredicateItems(new HashSet<ApiPredicateItem>() {{

add(new ApiPathPredicateItem().setPattern("/consumer/**")
.setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
}});
ApiDefinition api2 = new ApiDefinition("provider")
.setPredicateItems(new HashSet<ApiPredicateItem>() {{
add(new ApiPathPredicateItem().setPattern("/provider/**")
.setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
}});
definitions.add(api1);
definitions.add(api2);
GatewayApiDefinitionManager.loadApiDefinitions(definitions);
}

private void initGatewayRules() {
Set<GatewayFlowRule> rules = new HashSet<>();
rules.add(new GatewayFlowRule("consumer")
.setCount(10)
.setIntervalSec(1)
);
rules.add(new GatewayFlowRule("consumer")
.setCount(2)
.setIntervalSec(2)
.setBurst(2)
.setParamItem(new GatewayParamFlowItem()
.setParseStrategy(SentinelGatewayConstants.PARAM_PARSE_STRATEGY_CLIENT_IP)
)
);
rules.add(new GatewayFlowRule("provider")
.setCount(10)
.setIntervalSec(1)
.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)
.setMaxQueueingTimeoutMs(600)
.setParamItem(new GatewayParamFlowItem()
.setParseStrategy(SentinelGatewayConstants.PARAM_PARSE_STRATEGY_HEADER)
.setFieldName("X-Sentinel-Flag")
)
);
rules.add(new GatewayFlowRule("provider")
.setCount(1)
.setIntervalSec(1)
.setParamItem(new GatewayParamFlowItem()
.setParseStrategy(SentinelGatewayConstants.PARAM_PARSE_STRATEGY_URL_PARAM)
.setFieldName("pa")
)
);
rules.add(new GatewayFlowRule("provider")
.setCount(2)
.setIntervalSec(30)
.setParamItem(new GatewayParamFlowItem()
.setParseStrategy(SentinelGatewayConstants.PARAM_PARSE_STRATEGY_URL_PARAM)
.setFieldName("type")
.setPattern("warn")
.setMatchStrategy(SentinelGatewayConstants.PARAM_MATCH_STRATEGY_CONTAINS)
)
);

rules.add(new GatewayFlowRule("provider")
.setResourceMode(SentinelGatewayConstants.RESOURCE_MODE_CUSTOM_API_NAME)
.setCount(5)
.setIntervalSec(1)
.setParamItem(new GatewayParamFlowItem()
.setParseStrategy(SentinelGatewayConstants.PARAM_PARSE_STRATEGY_URL_PARAM)
.setFieldName("pn")
)
);
GatewayRuleManager.loadRules(rules);
}
}

通过上面的配置gateway已经成功整合了Sentinel,然后我们可以通过请求接口:http://127.0.0.1:15010/consumer/nacos

正常的结果:

{
"code": 401,
"message": "未登录"
}

这里返回的结果是因为之前gateway做了登录权限的校验,可以通过auth服务登录之后,将header中的token值作为请求的header中的token,就可以得到正确的返回值,对于当前的测试这个都是无关紧要的,可以通过查看前面的教程知道前因后果。

通过修改限流:

多次点击可以得到异常信息:

Blocked by Sentinel: FlowException

这样就可以通过网关层进行统一的接口流量控制,当然Sentinel的作用不止于此,大家可以通过其他的功能掌握对于接口的控制。

通过接口的限流和熔断可以让微服务中的模块可以更加的稳定,当大量流量来袭的时候也丝毫不慌。

除了一些比较极端的比如秒杀抢购抢券等功能,在流量比较大的应用中也是广泛的使用。

https://github.com/WinterChenS/spring-cloud-hoxton-study

introduction

SpringCloud 2020版本教程3:使用sentinel作为熔断器_方志朋的专栏-CSDN博客


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK