SpringCloud集成sentinel

本文介绍了如何在SpringCloudAlibaba环境中集成Sentinel,解决微服务中的流量控制、限流、熔断等问题,包括Sentinel的功能概述、配置步骤和使用@SentinelResource注解进行服务降级的示例。同时提到配置的持久化问题和未来可能的解决方案。
摘要由CSDN通过智能技术生成

SpringCloud-Alibaba集成Sentinel以及流控+熔断改造

一:项目搭建环境:

Jdk:17
Nacos:2.2.1
Sentinel:1.8.6

二:引入sentinel的原因

微服务可能存在的问题

1.流量激增CPU符合过高无法正常处理请求
2.数据未进行预热导致的缓存击穿
3.消息太多导致消息积压
4.慢sql导致数据库连接占满
5.三方系统无响应重复点击导致线程卡满
6.系统异常内存无法正常释放OOM
7.服务器内存瓶颈,程序异常退出

所以服务不可用的问题我们是需要分场景进行解决的,Sentinel就是做这个使用的,它被称为分布式系统的流量防卫兵,他的主要作用就是保证系统的稳定性(reliability)和恢复性(resilience),他支持多种系统的容错机制,常见的有:

1.超时机制
设置超时时间,在指定的时间内处理,超时以后处理超时逻辑

2.限流机制
可根据QPS来对服务进行流程管控

3.线程隔离机制
利用线程池来对请求进行管理,超出部分可定义其他处理策略

4.服务熔断
当服务到达定义的熔断标准或者降级标准时对服务进行次一级的信息处理,可能是消息排队处理,可能是入库等待最终一致性的处理

5.服务降级
感觉这个感念其实和服务熔断类似,只是服务异常处理颗粒度的问题,都是需要对服务进行次一级处理。

三:Sentinel

Sentinel是什么?

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

源码地址:https://github.com/alibaba/Sentinel
官方文档:https://github.com/alibaba/Sentinel/wiki
下载地址:https://github.com/alibaba/Sentinel/releases/tag/1.8.6

四:可视化界面-Sentinel-dashboard

根据下载地址选择1.8.6版本下载源码或者jar选其一启动
在这里插入图片描述
启动方式

1:源码

  • 找到对应sentinel-dashboard/resources下的application.propertis,修改链接的nacos信息。

  • 启动sentinel-dashboard/java下的DashboardApplication.java。

2:jar包

  • cmd 命令
java -jar jar包名

访问对应地址 http://ip:8080 用户名/密码:sentinel/sentinel
在这里插入图片描述

五:在SpringCloudAlibaba中整合Sentinel

1:添加对应版本pom

 <!--SpringCloud-sentinel集成-->
 <dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-sentinel-datasource</artifactId>
    <version>2.2.7.RELEASE</version>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    <version>2.2.7.RELEASE</version>
</dependency>

2:Sentinel 对应yml中配置

spring:
  cloud:
    # sentinel降级配置
    sentinel:
      transport:
        client-ip: ${spring.cloud.client.ip-address} # 获取本机IP地址
        port: 8719  #默认8719端口,如果被占用会向上扫描。
        #控制台地址
        dashboard: 127.0.0.1:19527
      log:
        #日志路径
        dir: logs/sentinel
        # 默认将调用链路收敛,导致链路流控效果无效
        web-context-unify: false
        #持久化nacos配置中
      datasource:
        #sentinel-rule: 唯一名称可自定义
        #限流
        flow:
          nacos:
            # 设置Nacos的连接地址、命名空间和Group ID
            server-addr: 127.0.0.1:8848
            namespace: sentinel
            # 设置Nacos中配置文件的命名规则
            data-id:  transport-sentinel-flow-rules
            group-id: SENTINEL_GROUP
            data-type: json
            # 必填的重要字段,指定当前规则类型是"限流"
            rule-type: flow
        #熔断
        degrade:
          nacos:
            server-addr: 127.0.0.1:8848
            namespace: sentinel
            data-id: transport-sentinel-degrade-rules
            group-id: SENTINEL_GROUP
            #熔断
            rule-type: degrade
      #取消慢加载
      eager: true

上诉配置完成即能进入sentinel页面查看数据

六:服务降级

服务降级-Sentinel

这里需要使用Sentinel的注解 @SentinelResource ,这个注解是Sentinel的核心注解,这里先简单说下后面会详细介绍这个注解的使用及各个参数的释义。该注解这里只是用于做服务降级,可以不去注册资源(声明value才会注册)。该注解有四个属性和服务降级有关:

关于@SentinelResource注解的官方详细介绍:注解@SentinelResource

1.fallback降级
2.fallbackClass降级
3.defaultFallback降级
4.fallbackClass降级
exceptionsToIgnore属性:忽略异常,被忽略的异常不会触发降级

1.降级:fallback

fallback需要传入一个字符串,这个字符串就是我们降级的处理方法的方法名。降级方法必须遵循以下规则

  1. 返回值类型必须与原函数返回值类型一致
  2. 方法参数列表需要和原函数一致,或者可以额外多一个 Throwable类型的参数用于接收对应的异常。
  3. fallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static函数(使用fallbackClass时),否则无法解析

2.应用示例

以下仅放入熔断示例,限流一样处理即可。

 /**
     * 限流测试示例
     * @return
     */
    //value将该方法定义为sentinel的资源,blockHandlerClass指明流控处理的类,blockHandler是流控时调用的方法。
    //这里需要注意处理异常的方法必须是静态方法添加static, 并需要添加sentinel的异常参数BlockException。
    @RequestMapping(value = "sentinelFlowDemo", method = RequestMethod.GET)
    @SentinelResource(value = "sentinelFlowDemo", blockHandlerClass = CustomBlockExceptionHandler.class, blockHandler = "sentinelFlowBlock")
    public HttpResult sentinelFlowDemo() {
        return HttpResult.ok("sentinelFlowDemo正常返回");
    }

    /**
     * 熔断测试示例
     * @param id
     * @return
     */
    @RequestMapping(value = "sentinelDegradeDemo", method = RequestMethod.GET)
    @SentinelResource(value = "sentinelDegradeDemo", blockHandlerClass = SysUserController.class, blockHandler = "sentinelDegradeBlock")
    public HttpResult sentinelDegradeDemo(@RequestParam("id") String id) {
        if ("2".equals(id)){
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        return HttpResult.ok("sentinelDegradeDemo正常返回");
    }

3.自定义sentinel异常


/**
 * @author lfdc
 * @version 1.0
 * @className CustomBlockExceptionHandler
 * @description 自定义sentinel异常Handler
 * @company 
 * @date 2023-06-08 09:06:59
 */

@Slf4j
@Configuration
public class CustomBlockExceptionHandler implements BlockExceptionHandler {
    HttpResult httpResult = null;
    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception {
        log.info("urlBlock.......................");
        //不同的异常返回不同的提示语
        //FlowException  //限流异常
        //DegradeException  //降级异常
        //ParamFlowException //参数限流异常
        //SystemBlockException //系统负载异常
        //AuthorityException //授权异常
        boolean einstanceof;
        if (e instanceof FlowException) {
            httpResult.setCode(HttpStatus.CODE_60701);
            httpResult.setMsg(HttpStatus.FLOW_EXCEPTION_ERROR_MESSAGE);

        } else if (e instanceof DegradeException) {
            httpResult.setCode(HttpStatus.CODE_60801);
            httpResult.setMsg(HttpStatus.DEGRADE_EXCEPTION_ERROR_MESSAGE);

        } else if (e instanceof ParamFlowException) {
            httpResult.setCode(HttpStatus.CODE_60901);
            httpResult.setMsg(HttpStatus.PARAM_FLOW_EXCEPTION_ERROR_MESSAGE);

        } else if (e instanceof SystemBlockException) {
            httpResult.setCode(HttpStatus.CODE_601001);
            httpResult.setMsg(HttpStatus.SYSTEM_BLOCK_EXCEPTION_ERROR_MESSAGE);
        } else if (e instanceof AuthorityException) {
            httpResult.setCode(HttpStatus.CODE_601101);
            httpResult.setMsg(HttpStatus.AUTHORITY_EXCEPTION_ERROR_MESSAGE);
        } else {
            //其他规则
            httpResult.setCode(HttpStatus.CODE_601201);
            httpResult.setMsg(HttpStatus.OTHER_EXCEPTION_ERROR_MESSAGE);
        }
    }

    public static HttpResult sentinelFlowBlock(BlockException ex){
        log.info("flowException ERROR:{}",ex.getRule(),ex);
        return HttpResult.error(HttpStatus.CODE_60701, HttpStatus.FLOW_EXCEPTION_ERROR_MESSAGE);
    }

    public static HttpResult sentinelDegradeBlock(BlockException ex){
//        log.info("sentinelDegradeDemo进入熔断");
        log.info("degradeException ERROR:{}",ex.getRule(),ex);
        return HttpResult.error(HttpStatus.CODE_60801, HttpStatus.DEGRADE_EXCEPTION_ERROR_MESSAGE);
    }

    public static HttpResult sentinelParamFlowBlock(BlockException ex){
        log.info("paramFlowException ERROR:{}",ex.getRule(),ex);
        return HttpResult.error(HttpStatus.CODE_60901, HttpStatus.PARAM_FLOW_EXCEPTION_ERROR_MESSAGE);
    }

    public static HttpResult sentinelSystemBlock(BlockException ex){
        log.info("systemException ERROR:{}",ex.getRule(),ex);
        return HttpResult.error(HttpStatus.CODE_601001, HttpStatus.SYSTEM_BLOCK_EXCEPTION_ERROR_MESSAGE);
    }

    public static HttpResult sentinelAuthorityBlock(BlockException ex){
        log.info("authorityException ERROR:{}",ex.getRule(),ex);
        return HttpResult.error(HttpStatus.CODE_601101,HttpStatus.AUTHORITY_EXCEPTION_ERROR_MESSAGE);
    }


    public static HttpResult sentinelOtherBlock(BlockException ex){
        log.info("otherException ERROR:{}",ex.getRule(),ex);
        return HttpResult.error(HttpStatus.CODE_601201, HttpStatus.OTHER_EXCEPTION_ERROR_MESSAGE);
    }

    @PostConstruct
    public void init() {
        new CustomBlockExceptionHandler();
    }
}

4.熔断数据配置

对接口进行熔断配置,快速调用会进行熔断响应

对接口调用进行熔断或者流控配置

新增熔断规则
在这里插入图片描述

七:总结

以上为之前搭建项目时,根据版本简单集成并实现,当前仅仅为简单,但新服务宕机或者服务重启,之前的限流、降级、熔断等配置会丢失。需要重新进行配置,不仅繁琐还容易配置不当。后续文档会新增Sentinel持久化nacos操作,可以使用脚本推送、Nacos脚本配置、或者Sentinel本身项目进行持久化Nacos。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值