文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Spring Cloud Alibaba之Sentinel实现熔断限流功能的方法

2023-06-14 22:15

关注

这篇文章主要介绍Spring Cloud Alibaba之Sentinel实现熔断限流功能的方法,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!

sentinel简介

这个在阿里云有企业级的商用版本 应用高可用服务 AHAS;现在有免费的入门级可以先体验下,之后再决定是否使用付费的专业版或者是自己搭建。

官方文档地址

Sentinel的github

本文示例代码

sentinel功能概述

sentinel和Hystrix的区别

Sentinel规则

Sentinel默认定义如下规则:

流控规则

通过QPS或并发线程数来做限制,里面的针对来源可以对某个微服务做限制,默认是都限制。

关于配置规则:可以直接使用url地址来配置,也可以通过自定义名称来配置(需要在方法上添加@SentinelResource("order")注解才能达到效果,可以重复)

链路限流不生效的问题:由于sentinel基于filter开发的拦截使用的链路收敛的模式,因此需要设置关闭链路收敛使链路收敛能够生效,

spring:   cloud:     sentinel:       filter:         # 关闭链路收敛使链路收敛能够生效         enabled: false

降级规则

当满足设置的条件,对服务进行降级。

根据平均响应时间:当资源的平均响应时间超过阀值(以ms为单位)之后,资源进入准降级状态。
如果接下来1秒持续进入的n个请求的RT都持续超过这个阀值,则在接下来的时间窗口(单位s)之内就会使这个方法进行服务降级。

注意Sentinel默认的最大时间为4900ms,超过这个时间将被默认设置为4900ms;可以通过启动配置 -Dcsp.sentinel.statistic.max.rt=xxx来修改。

异常降级:通过设置异常数或者异常比例来进行服务降级。

热点规则

必须使用@SentinelResource("order")注解来做标记,将限流做到参数级别上去,并且可以配置排除参数值等于某个值时不做限流。

授权规则

通过配置黑白名单来设置是否允许通过。

自定义来源获取规则:

import com.alibaba.csp.sentinel.adapter.servlet.callback.RequestOriginParser;import org.apache.commons.lang3.StringUtils;import org.springframework.stereotype.Component;import javax.servlet.http.HttpServletRequest;@Componentpublic class RequestOriginParserDefinition implements RequestOriginParser {    @Override  public String parseOrigin(HttpServletRequest request) {      String client = request.getHeader("client");      if(StringUtils.isNotBlank(client)){          return "NONE";      }      return client;  }}

系统规则

系统保护规则是从应用级别的入口流量进行控制,从单台机器的总体Load、RT、入口QPS、CPU使用率和线程数五个维度来监控整个应用数据,让系统跑到最大吞吐量的同时保证系统稳定性。

sentinel的使用

下面我们通过一些简单的示例来快速了解sentinel的使用。

安装控制台界面工具

在Sentinel的Github上下载安装包https://github.com/alibaba/Sentinel/releases;就是一个jar包直接使用命令启动即可。

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

-Dserver.port 是设置访问的端口号;
sentinel-dashboard.jar 就是刚刚下载的jar包名称;
为方便使用可以创建一个bat启动文件,在里面输入上面的命令行,后面启动直接点击这个bat文件即可。

从 Sentinel 1.6.0 起,Sentinel 控制台引入基本的登录功能,默认用户名和密码都是 sentinel;启动成功后浏览器输入http://127.0.0.1:9080 即可访问控制台。
注意这个控制台不是必须接入的,同时只有你的接口方法被访问过后控制台里面才会显示。

服务中使用

添加如下依赖包

<!--由于我们使用的spring-cloud,因此这里因此 sentinel的集成包来简化我们的配置 --><dependency>    <groupId>com.alibaba.cloud</groupId>    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId></dependency><!--sentinel 对dubbo的支持--><dependency>    <groupId>com.alibaba.csp</groupId>    <artifactId>sentinel-apache-dubbo-adapter</artifactId></dependency>

注意如果没有使用dubbo那么无需引入sentinel-apache-dubbo-adapter; 比如之前使用的是feign和Hystrix搭配的,只需要将Hystrix的相关配置和依赖去掉,然后加入sentinel的依赖即可。

代码中的使用示例1,如果我们只需对相关的http方法进行限流,直接引入依赖的包即可;下面是我们向对某个方法进行限流,因此使用使用@SentinelResource注解来配置。

@Servicepublic class SentinelDemoServiceImpl implements SentinelDemoService {        @SentinelResource(value = "SentinelDemoService#sentinelDemo1", defaultFallback = "sentinelDemo1Fallback")    @Override    public String sentinelDemo1() {        return "sentinel 示例1";    }        public String sentinelDemo1Fallback(Throwable t) {        if (BlockException.isBlockException(t)) {            return "Blocked by Sentinel: " + t.getClass().getSimpleName();        }        return "Oops, failed: " + t.getClass().getCanonicalName();    }}

然后在控制台配置相关的策略规则即可。

自定义Sentinel的异常返回

通过实现BlockExceptionHandler接口来自定义异常返回;注意之前的UrlBlockHandler 视乎已经在新版中移除了。

@Componentpublic class SentinelExceptionHandler implements BlockExceptionHandler {        @Override    public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {        JSONObject responseData = new JSONObject();        if (e instanceof FlowException) {            responseData.put("message", "限流异常");            responseData.put("code", "C5001");        } else if (e instanceof DegradeException) {            responseData.put("message", "降级异常");            responseData.put("code", "C5002");        } else if (e instanceof ParamFlowException) {            responseData.put("message", "参数限流异常");            responseData.put("code", "C5003");        } else if (e instanceof AuthorityException) {            responseData.put("message", "授权异常");            responseData.put("code", "C5004");        } else if (e instanceof SystemBlockException) {            responseData.put("message", "系统负载异常");            responseData.put("code", "C5005");        }        response.setContentType("application/json;charset=utf-8");        response.getWriter().write(responseData.toJSONString());    }}

基于文件实现Sentinel规则的持久化

Sentinel 控制台通过 API 将规则推送至客户端并更新到内存中,接着注册的写数据源会将新的规则保存到本地的文件中。

编写一个实现InitFunc接口的类,在里面定义持久化的方式,这里使用文件

public class FilePersistence implements InitFunc {  @Value("spring.application.name")  private String applicationName;  @Override  public void init() throws Exception {      String ruleDir = System.getProperty("user.home") + "/sentinel-rules/" + applicationName;      String flowRulePath = ruleDir + "/flow-rule.json";      String degradeRulePath = ruleDir + "/degrade-rule.json";      String systemRulePath = ruleDir + "/system-rule.json";      String authorityRulePath = ruleDir + "/authority-rule.json";      String paramFlowRulePath = ruleDir + "/param-flow-rule.json";      this.mkdirIfNotExits(ruleDir);      this.createFileIfNotExits(flowRulePath);      this.createFileIfNotExits(degradeRulePath);      this.createFileIfNotExits(systemRulePath);      this.createFileIfNotExits(authorityRulePath);      this.createFileIfNotExits(paramFlowRulePath);      // 流控规则      ReadableDataSource<String, List<FlowRule>> flowRuleRDS = new FileRefreshableDataSource<>(              flowRulePath,              flowRuleListParser      );      FlowRuleManager.register2Property(flowRuleRDS.getProperty());      WritableDataSource<List<FlowRule>> flowRuleWDS = new FileWritableDataSource<>(              flowRulePath,              this::encodeJson      );      WritableDataSourceRegistry.registerFlowDataSource(flowRuleWDS);      // 降级规则      ReadableDataSource<String, List<DegradeRule>> degradeRuleRDS = new FileRefreshableDataSource<>(              degradeRulePath,              degradeRuleListParser      );      DegradeRuleManager.register2Property(degradeRuleRDS.getProperty());      WritableDataSource<List<DegradeRule>> degradeRuleWDS = new FileWritableDataSource<>(              degradeRulePath,              this::encodeJson      );      WritableDataSourceRegistry.registerDegradeDataSource(degradeRuleWDS);      // 系统规则      ReadableDataSource<String, List<SystemRule>> systemRuleRDS = new FileRefreshableDataSource<>(              systemRulePath,              systemRuleListParser      );      SystemRuleManager.register2Property(systemRuleRDS.getProperty());      WritableDataSource<List<SystemRule>> systemRuleWDS = new FileWritableDataSource<>(              systemRulePath,              this::encodeJson      );      WritableDataSourceRegistry.registerSystemDataSource(systemRuleWDS);      // 授权规则      ReadableDataSource<String, List<AuthorityRule>> authorityRuleRDS = new FileRefreshableDataSource<>(              authorityRulePath,              authorityRuleListParser      );      AuthorityRuleManager.register2Property(authorityRuleRDS.getProperty());      WritableDataSource<List<AuthorityRule>> authorityRuleWDS = new FileWritableDataSource<>(              authorityRulePath,              this::encodeJson      );      WritableDataSourceRegistry.registerAuthorityDataSource(authorityRuleWDS);      // 热点参数规则      ReadableDataSource<String, List<ParamFlowRule>> paramFlowRuleRDS = new FileRefreshableDataSource<>(              paramFlowRulePath,              paramFlowRuleListParser      );      ParamFlowRuleManager.register2Property(paramFlowRuleRDS.getProperty());      WritableDataSource<List<ParamFlowRule>> paramFlowRuleWDS = new FileWritableDataSource<>(              paramFlowRulePath,              this::encodeJson      );      ModifyParamFlowRulesCommandHandler.setWritableDataSource(paramFlowRuleWDS);  }  private Converter<String, List<FlowRule>> flowRuleListParser = source -> JSON.parseObject(          source,          new TypeReference<List<FlowRule>>() {          }  );  private Converter<String, List<DegradeRule>> degradeRuleListParser = source -> JSON.parseObject(          source,          new TypeReference<List<DegradeRule>>() {          }  );  private Converter<String, List<SystemRule>> systemRuleListParser = source -> JSON.parseObject(          source,          new TypeReference<List<SystemRule>>() {          }  );  private Converter<String, List<AuthorityRule>> authorityRuleListParser = source -> JSON.parseObject(          source,          new TypeReference<List<AuthorityRule>>() {          }  );  private Converter<String, List<ParamFlowRule>> paramFlowRuleListParser = source -> JSON.parseObject(          source,          new TypeReference<List<ParamFlowRule>>() {          }  );  private void mkdirIfNotExits(String filePath) throws IOException {      File file = new File(filePath);      if (!file.exists()) {          file.mkdirs();      }  }  private void createFileIfNotExits(String filePath) throws IOException {      File file = new File(filePath);      if (!file.exists()) {          file.createNewFile();      }  }  private <T> String encodeJson(T t) {      return JSON.toJSONString(t);  }}

在resources下创建配置目录META-INF/services,然后添加文件 com.alibaba.csp.sentinel.init.InitFunc;在文件中添加上面写的配置类的全路径top.vchar.order.config.FilePersistence

使用Nacos实现动态规则配置

动态规则扩展文档

添加如下依赖

<dependency>    <groupId>com.alibaba.csp</groupId>    <artifactId>sentinel-datasource-nacos</artifactId></dependency>

添加如下配置(具体可以参考SentinelProperties 配置类):

spring:  cloud:    sentinel:      datasource:        flow:          # 配置nacos的          nacos:            rule-type: FLOW            server-addr: 127.0.0.1:8848            namespace: public            groupId: "DEFAULT_GROUP"            dataId: dubbo-customer-demo-sentinel.rule            username: nacos            password: 123456

然后在nacos中创建一个配置文件 dubbo-customer-demo-sentinel.rule,类型为text; 具体配置参数见官网说明;下面是一个示例:

[    {        "resource": "SentinelDemoService#sentinelDemo2",        "count": 0,        "grade": 1,        "limitApp":"default",        "strategy":0,        "controlBehavior":0,        "clusterMode":false    }]

实际使用不建议这样做,还是建议使用控制台的方式;因为使用官方提供的集成方式时,nacos的时候会疯狂的拉取数据,同时只支持一个规则的配置;因此要么自己去基于nacos实现,要么使用控制台的方式;
且配置项很多,因此还是建议使用控制台的方式来实现,或者是对接其rest api接口,在实际操作中还是建议使用界面化的操作。

关于熔断降级是如何实现自动调用我们配置的Fallback方法

sentinel使用了spring的AOP切面编程功能拦截有@SentinelResource注解的类,具体查看com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect类,在执行实际的方法时使用try-catch进行异常捕获,
如果异常是BlockException的时候会调用handleBlockException方法(注意我们也可以配置自己自定义的异常也走这个方法),通过反射执行配置的Fallback方法。

以上是“Spring Cloud Alibaba之Sentinel实现熔断限流功能的方法”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注编程网行业资讯频道!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯