SpringCloudAlibaba-Sentinel服务容错

SpringCloudAlibaba-Sentinel服务容错

在微服务架构中,我们将业务拆分成一个个的服务,服务与服务之间可以相互调用,但是由于网络原因或者自身的原因,服务并不能保证100%可用,如果单个服务出现问题,调用这个服务就会出现网络延迟,此时若有大量的网络涌入,会形成任务堆积,最终导致服务瘫痪。(常见的如高峰期网页提示:当前人数太多,请稍后再试!)

Sentinel官方文档:https://sentinelguard.io/zh-cn/index.html

一、Sentinel的概念和功能
基本概念
  • 资源

    资源就是Sentinel要保护的东西,资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何内容,可以是一个服务,也可以是一个方法,甚至可以是一段代码。

  • 规则

    规则就是用来定义如何进行保护资源的,作用在资源之上, 定义以什么样的方式保护资源,主要包括流量控制规则、熔断降级规则以及系统保护规则。

  • 重要功能

    Sentinel的主要功能就是容错,主要体现为下面这三个:

    • 流量控制

      流量控制在网络传输中是一个常用的概念,它用于调整网络包的数据。任意时间到来的请求往往是随机不可控的,而系统的处理能力是有限的。我们需要根据系统的处理能力对流量进行控制。Sentinel 作为一个调配器,可以根据需要把随机的请求调整成合适的形状。

    • 熔断降级

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

      Sentinel 对这个问题采取了两种手段:

      1 通过并发线程数进行限制

    Sentinel 通过限制资源并发线程的数量,来减少不稳定资源对其它资源的影响。当某个资源出现不稳定的情况下,例如响应时间变长,对资源的直接影响就是会造成线程数的逐步堆积。当线程数在特定资源上堆积到一定的数量之后,对该资源的新请求就会被拒绝。堆积的线程完成任务后才开始继续接收请求。

    2 通过响应时间对资源进行降级

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

    Sentinel Hystrix 的区别

    两者的原则是一致的, 都是当一个资源出现问题时, 让其快速失败, 不要波及到其它服务,但是在限制的手段上, 确采取了完全不一样的方法:

    Hystrix 采用的是线程池隔离的方式,优点是做到了资源之间的隔离, 缺点是增加了线程切换的成本。
    Sentinel 采用的是通过并发线程的数量和响应时间来对资源做限制。

    • 系统负载保护

      Sentinel 同时提供系统维度的自适应保护能力。当系统负载较高的时候,如果还持续让请求进入可能会导致系统崩溃,无法响应。在集群环境下,会把本应这台机器承载的流量转发到其它的机器上去。如果这个时候其它的机器也处在一个边缘状态的时候,Sentinel 提供了对应的保护机制,让系统的入口流量和系统的负载达到一个平衡,保证系统在能力范围之内处理最多的请求。

二、名词解释
  1. 服务限流:好似去景点玩,景点限流。

目的为了保护我们的服务,在高并发情况下,如果客户端的请求服务器端达到一定的极限(设置阈值),请求的数量超出我们设置的阈值,开启我们的自我保护机制,直接执行我们的服务降级的方法,不会去执行我们的业务逻辑,走本地的 fallback 方法。

  1. 服务降级:类比秒杀一件商品,当前排队人数过多,请稍后重试。

在高并发的情况下,为了防止用户一直等待,采用限流和熔断机制,保护我们的服务,不会执行我们的业务逻辑,走本地 fallback 方法,返回一个友好的提示给客户端。

  1. 服务雪崩的效应:

在分布式系统中,由于网络原因或自身的原因,服务一般无法保证 100% 可用。如果一个服务出现了问题,调用这个服务就会出现线程阻塞的情况,此时若有大量的请求涌入,就会出现多条线程阻塞等待,进而导致服务瘫痪。

由于服务与服务之间的依赖性,故障会传播,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的 雪崩效应

  1. 服务雪崩解决方案:

服务的隔离机制:线程池隔离 或者 信号量隔离机制

线程池隔离:每个接口都由自己的独立的线程池维护我们的请求、每个线程池互不影响。缺点:占用服务器内存非常大。
信号量隔离:设置最多允许我们某个接口有一定的阈值线程数量去处理接口,如果超出线程数量,拒绝访问。

三、Sentinel 和 Hystrix 的区别(直接上alibaba官方图)

在这里插入图片描述

四、配置限流的方式

本人另一篇笔记,sentinel五大规则详细讲解(建议先看完本篇再衔接看另一篇):
https://blog.csdn.net/weixin_44780078/article/details/128242453?spm=1001.2014.3001.5501

  • 手动代码配置(纯代码、主机的形式)

    1. 纯手工方式整合(不推荐,只演示demo)

      sentinel依赖

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

    mumberService.java

    @RestController
    public class MumberService {
    
        private static final String GETUSER_KEY = "getUser";
    
        @GetMapping("/getUser")
        public String getUser(){
            Entry entry = null;
            try {
                entry = SphU.entry(GETUSER_KEY);
                //正常执行逻辑
                return "getUser接口...";
            } catch (BlockException e) {
                //接口被限流的情况下,走catch
                return "当前访问人数太多,请稍后重试!";
            } finally {
                if (entry != null){
                    entry.exit();
                }
            }
        }
    
        /**
         * 初始化路由策略
         */
        @RequestMapping("/initFlowQpsRule")
        public String initFlowQpsRule(){
            List<FlowRule> ruleList = new ArrayList<>();
            FlowRule rule = new FlowRule();
            //QPS控制在1以内
            rule.setCount(1);
            //QPS限流
            rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
            rule.setLimitApp("default");
            ruleList.add(rule);
            FlowRuleManager.loadRules(ruleList);
            return "初始化策略成功...";
        }
    }
    

    接下来先初始化,即访问initFlowQpsRule接口,然后再访问getUser接口,当访问getUser接口的频率快于1s时,就会自动限流。

    若想实现自动装配(不访问initFlowQpsRule接口),则实现ApplicationRunner类:

    SentinelApplicationRunner.java

    public class SentinelApplicationRunner implements ApplicationRunner {
        private static final String GETUSER_KEY = "/getUser"; //一般是请求路径或有SentinelResource注解类定义的访问资源
    
        @Override
        public void run(ApplicationArguments args) throws Exception {
            initFlowQpsRule();
        }
    
        public String initFlowQpsRule(){
            List<FlowRule> ruleList = new ArrayList<>();
            FlowRule rule = new FlowRule();
            rule.setCount(0.5); //QPS限流阈值
            rule.setGrade(RuleConstant.FLOW_GRADE_QPS); 限流阈值类型,QPS 或线程数模式
            rule.setLimitApp("default");
            ruleList.add(rule);
            FlowRuleManager.loadRules(ruleList);
            return "初始化策略成功...";
        }
    }
    

    效果与上面一样。

    1. 采用注解化方式(推荐)

    把步骤1代码重构。

        /**
         * 使用注解实现
         */
        @RequestMapping("/insertUser")
        @SentinelResource(value = INSERTUSER_KEY, blockHandler = "insertUserBlockHandler")
        public String insertUser(){
            return "insertUser接口...";
        }
    
        /**
         * 回调方法,
         */
        public String insertUserBlockHandler(BlockException e){
            return "当前访问人数太多,请稍后重试!" + e.toString();
        }
    

    但是数量QPS数量只能在控制台更改。

  • Sentinel 控制台形式配置

    1 下载jar包,解压到文件夹

    网址:https://github.com/alibaba/Sentinel/releases

    2 启动控制台

    //jar命令启动,自定义端口号(控制台本身是一个SpringBoot项目)    
    java -Dserver.port=8718 -Dcsp.sentinel.dashboard.server=localhost:8718 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.0.jar
    
    //或者直接默认启动,端口号8080
    java -jar sentinel-dashboard-1.8.0.jar
    

    在这里插入图片描述

    3 mumber-producer向控制台注册

    server:
      port: 8080
    
    spring:
      application:
        name: mumber-producer #服务名程
    
      cloud:
        nacos:
          discovery:
            server-addr: localhost:8848 # nacos默认端口地址为8848
            enabled: true
        sentinel:
          transport:
            dashboard: localhost:8718/  #sentinel-dashboard 地址
          eager: true #默认为false,设置为true限流才有效果
    

    4 编写接口

    @RequestMapping("/getOrderConsle")
    public String getOrderConsle(){
        return "getOrderConsle接口...";
    }
    

    5 通过浏览器访问localhost:8718 进入控制台 (默认用户名密码是 sentinel/sentinel)

    在这里插入图片描述

    6 添加一个接口限流规则

    在这里插入图片描述

    此时访问 localhost:8080/getOrderConsole 太频繁时会看到如下提示:

    在这里插入图片描述

    7 自定义提示

    修改上述java代码

    @RequestMapping("/getOrderConsle")
    @SentinelResource(value = "getOrderConsle", blockHandler = "insertUserBlockHandler")
    public String getOrderConsle(){
        return "getOrderConsle接口...";
    }
    
    /**
     * 回调方法
    */
    public String insertUserBlockHandler(BlockException e){
        return "当前访问人数太多,请稍后重试!";
    }
    

    修改限流规则,在5的基础上,取消斜杠即可(此处不再截图),此时访问接口

    在这里插入图片描述

    此处注意:控制台限流规则并非持久化,重启项目会失效,需重新添加先流规则。

五、 @SentinelResource的使用

上面步骤四已经接触了SentinelResource的使用,此处对此作详细讲解。

@SentinelResource 用于定义资源,并提供可选的异常处理和 fallback 配置项。其主要参数如下:

请添加图片描述
BlockException包含很多个子类,分别对应不同的场景:
请添加图片描述
此处可以理解为除了上图列举的那些异常,其他异常由fallback处理。fallback代码配置如下:

/**
* blockHandler 用法上面已举例
*/
   @RequestMapping("/user")
   @SentinelResource(value = "user", blockHandler = "fail",fallback = "fallback")
   public String user(Integer age) {
       if (age % 3 == 0){
           throw new RuntimeException();
       }
       return   "年龄:" + age;
   }
   public String fallback(Integer age) {
       log.error("{}", age);
       return "user接口发生异常了";
   }
       public String fail(String name,Integer age, BlockException e){
       return "user接口参数被限流了,请稍后重试!";
   }

blockHandler 和 fallback ,默认和原方法写在一个类中,如需写在其他类中,需用到blockHandlerClass和fallbackClass。

@Slf4j
/**
* 此类可以不注入到spring容器
*/
public class BlockHandlerAndFallBackImpl {

    /**
     *  注意这里必须使用static修饰方法
     *  参数、返回类型,必须与原类一致
     */
    public static String fail(Integer age, BlockException ex) {
        log.error("{}", age);
        return "接口参数被限流了,请稍后重试!";
    }

    public static String fallback(Integer age) {
        log.error("{}", age);
        return "接口发生异常了...";
    }
}
@RestController
@Slf4j
public class MumberController2 {

    @RequestMapping("/user")
    @SentinelResource(value = "user", blockHandlerClass = BlockHandlerAndFallBackImpl.class, blockHandler = "fail", fallbackClass = BlockHandlerAndFallBackImpl.class, fallback = "fallback")
    public String user(Integer age) {
        if (age % 3 == 0){
            throw new RuntimeException();
        }
        return   "年龄:" + age;
    }
}
六、Sentinel规则持久化

可以发现上面的演示都没有依赖数据库,那配置的规则数存到哪里的呢?答案是:内存中 ,这种做法的好处是简单,无依赖;坏处是应用重启规则就会消失,仅用于简单测试,不能用于生产环境。
官方文档:https://github.com/alibaba/Sentinel/wiki/在生产环境中使用-Sentinel

Sentinel提供了以下三种模式,其中Pull模式和Push模式可以保证规则持久化:
请添加图片描述

  • 原始模式:上述的演示过程即为原始模式,不可用于生产环境。
  • 拉模式:客户端主动向某个规则管理中心定期轮询拉取规则,这个规则中心可以是 RDBMS、文件,甚至是 VCS 等。这样做的方式是简单,缺点是无法及时获取变更;
  • 推模式:规则中心统一推送,客户端通过注册监听器的方式时刻监听变化,比如使用 Nacos、Zookeeper 等配置中心。这种方式有更好的实时性和一致性保证。

由于生产环境使用的是第三种方式:推模式,所以接下来采用nacos注册中心演示持久化规则,这种方式的交互切断了Sentinel客户端和 Sentinel Dashboard的联系。它的交互方式变为: 配置中心控制台/Sentinel 控制台===>配置中心(Nacos)===>Sentinel客户端。演示过程在步骤七。

七、nacos整合sentinel规则持久化

1 SpringBoot 整合 nacos-sentinel 持久化依赖

<!-- SpringBoot 整合 nacos-sentinel 持久化 -->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
    <version>1.8.0</version>
</dependency>

2 添加配置

server:
  port: 8080

spring:
  application:
    name: mumber-producer #服务名程

  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #nacos默认端口地址为8848
        enabled: true
    sentinel:
      transport:
        dashboard: localhost:8718  #sentinel-dashboard 地址
      eager: true
	  #nacos整合sentinel持久化
      datasource:
        - nacos:
            server-addr: localhost:8848 #nacos连接地址
            group-id: DEFAULT_GROUP #nacos连接分组
            rule-type: flow #路由存储规则flow、degrade、param-flow、gw-flow
            data-id: ${spring.application.name}-sentinel #读取配置文件的 data-id
            data-type: json #读取配置文件类型为 JSON 和 XML

3 创建接口

//集成 nacos 实现 sentinel 流控规则的持久化
@RequestMapping("/getOrderSentinel")
public String getOrderSentinel() {
    return "getOrderSentinel接口...";
}

4 访问nacos控制台,创建配置

在这里插入图片描述

配置内容:

[
    {
        "resource": "/getOrderSentinel",
        "limitApp": "default",
        "grade": 1,
        "count": 10,
        "strategy": 0,
        "controlBehavior": 0,
        "clusterMode": false
    }
]

resource: 资源名,即限流规则的作用对象
limitApp: 流控针对的调用来源,若为 default 则不区分调用来源
grade:限流阙值类型(QPS 或并发线程数);0 代表根据并发数量来限流, 1 代表 QPS 来进行流量控制
count:限流阙值
strategy:调用关系限流策略

5 启动项目

6 回到sentinel控制台,看到刚配置的规则已生效

在这里插入图片描述

7 通过nacos修改该阈值,修改为100,然后发布

在这里插入图片描述

然后回到sentinel控制台,查看刚才的阈值,发现已变化为100,则已实现通过 nacos 配置中心修改限流规则。

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值