Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】

Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】

    • 一、分布式系统遇到的问题
      • 1、服务挂掉的一些原因
    • 二、解决方案
    • 三、Sentinel:分布式系统的流量防卫兵
      • 1、Sentinel是什么
      • 2、Sentinel和Hystrix对比
      • 3、Sentinel快速开发
      • 4、通过注解的方式来控流
      • 5、启动Sentinel控制台
    • 四、Spring Cloud Alibaba 整合Sentinel
      • 1、复制创建项目并,引入依赖
      • 2、完善代码
      • 3、启动测试
    • 五、Sentinel流控规则
      • 1、实时监控
      • 2、簇点链路
    • 六、流控规则
      • 1、流量控制(iow conrol)
      • 2、QPS
      • 3、并发线程数
      • 4、BlockException异常统一处理
    • 七、流控模式
      • 1、直接
      • 2、关联
      • 3、链路
    • 八、流控效果
      • 1、Warm Up(激增流量)预热冷启动
      • 2、均匀排队(脉冲流量)
    • 九、降级规则
      • 1、熔断策略:慢调用比例(LO_REOESLRATO):
      • 2、熔断策略:异常比例
      • 3、熔断策略:异常数

一、分布式系统遇到的问题

1、服务挂掉的一些原因


Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第1张图片
如果其中的下单服务不可用,就会出现线程池里所有线程都因等待响应而被阻塞,从而造成整个服务链路不可用,进而导致整个系统的服务雪崩.如图所示;

服务雪崩效应:因服务提供者的不可用导致服务调用者的不可用,并将不可用逐渐放大的过程,就叫服务雪崩效应导致服务不可用的原因:
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第2张图片

二、解决方案

稳定性、恢复性
Reliability && Resilience
常见的容错机制:

  • 超时机制
    在不做任何处理的情况下,服务提供者不可用会导致消费者请求线程强制等待,而造成系统资源耗尽。加入超时机制,一旦超时,就释放资源。由于释放资源速度较快,一定程度上可以抑制资源耗尽的问题。
  • 服务限流

Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第3张图片

  • 隔离
    原理:用户的请求将不再直接访问服务,而是通过线程池中的空闲线程来访问服务,如果线程池已满,则会进行降级处理,用户的请求不会被阻塞,至少可以看到一个执行锌果(例如返回友好的提示信息),而不是无休止的等待或者看到系统崩溃。

隔离前:
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第4张图片
b)信号隔离
信号隔离也可以甲于限制并发访问,防止阻塞扩散、与线租隔离最大不同在于执行依赖代码的线程依然是请求线程(该线程需要通过信号申请,如果客户端是可信的且可以快速返回,可以使用信号隔离替换线程隔离,降低开销。信号量的大小可以动态调整,线程池大小不可以。

  • 服务熔断
    远程服务不稳定或网络抖动时暂时关闭,就叫服务熔断。

现实世界的断路器大家肯定都很了解,断路器实时监控电路的情况,如果发现电路电流异常,就会跳闸,从而防止电路被烧毁。

软件世界的断路器可以这样理解︰实时监测应用,如果发现在一定时间内失败次数失败率达到一定阈值,就"跳闸”,断路器打开——此时,请求直接返回,而不去调用原本调用的逻辑。

跳闸一段时间后(例如10秒),断路器会进入半开状态,这是一个瞬间态,此时允许一次请求调用该调的逻辑,如果成功,则断路器关闭,应用正常调用;如果调用依然不成功,断路器继续回到打开状态,过段时间再进入半开状态尝试——通过"跳闸,应用可以保护自己,而且避免浪费资源;而通过半开的设计,可实现应用的"自我修复"。

所以,同样的道理,当依赖的服务有大量超时时,在让新的请求去访问根本没有意义,只会无畏的消耗现有资源。

比如我们设置了超时时间为1s.如果短时间内有大量请求在1s内都得不到响应,就意味着这个服务出现了异常,此时就没有必要再让其他的请求去访问这个依赖了,这个时候就应该使用断路器避免资源浪费。
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第5张图片

  • 服务降级
    有服务熔断,必然要有服务降级。
    所谓降级,就是当某个服务熔断之后,服务将不再被调用,此时客户端可以自己准备一个本地的tllack(回退)回调,返回一个缺省值。例如:(备用接口缓存/mok数据)。

这样做,虽然服务水平下降,但好歹可用,比直接挂掉要强,当然这也要看适合的业务场景。

Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第6张图片

三、Sentinel:分布式系统的流量防卫兵

1、Sentinel是什么

Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第7张图片
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel是面向分布式服务架构的流量控制组件,主要以流量为切入点,从限流、流量整形、熔断降级、系统负
载保护、热点防护等多
个维度来帮助开发者保障微服务的稳定性。
源码地址: https://github.com/alibaba/Sentinel
官方文档: https://github.com/alibaba/Sentinel/wiki
Sentinel具有以下特征:

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

阿里云提供了企业级的Sentinel服务,应用高可用服务AHAS

Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第8张图片

2、Sentinel和Hystrix对比

Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第9张图片

3、Sentinel快速开发

在官方文档中,定义的Sentinel进行资源保护的几个步骤:
1.定义资源
2.定义规则
3.检验规则是否生效
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第10张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第11张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第12张图片
完善pom文件
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第13张图片

<dependencies>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
        
        <dependency>
            <groupId>com.alibaba.cspgroupId>
            <artifactId>sentinel-coreartifactId>
            <version>1.8.0version>
        dependency>
        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
            <version>1.18.18version>
        dependency>
        
        <dependency>
            <groupId>com.alibaba.cspgroupId>
            <artifactId>sentinel-annotation-aspectjartifactId>
            <version>1.8.0version>
        dependency>

    dependencies>

Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第14张图片

package com.itbluebox.sentinelnew.controller;

import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.Tracer;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PostConstruct;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;



/***
 * @Author 徐庶   QQ:1092002729
 * @Slogan 致敬大师,致敬未来的你
 */
@RestController
@Slf4j
public class HelloController {

    private static final String RESOURCE_NAME = "hello";
    private static final String USER_RESOURCE_NAME = "user";
    private static final String DEGRADE_RESOURCE_NAME = "degrade";


    // 进行sentinel流控
    @RequestMapping(value = "/hello")
    public String hello() {

        Entry entry = null;
        try {
            // 1.sentinel针对资源进行限制的
            entry = SphU.entry(RESOURCE_NAME);
            // 被保护的业务逻辑
            String str = "hello world";
            log.info("====="+str+"=====");
            return str;
        } catch (BlockException e1) {
            // 资源访问阻止,被限流或被降级
            //进行相应的处理操作
            log.info("block!");
            return "被流控了!";
        } catch (Exception ex) {
            // 若需要配置降级规则,需要通过这种方式记录业务异常
            Tracer.traceEntry(ex, entry);
        } finally {
            if (entry != null) {
                entry.exit();
            }
        }
        return null;
    }


    /**
     * 定义规则
     *
     * spring 的初始化方法
     */
    @PostConstruct  //
    private static void initFlowRules(){

        // 流控规则
        List<FlowRule> rules = new ArrayList<>();

        // 流控
        FlowRule rule = new FlowRule();
        // 为哪个资源进行流控
        rule.setResource(RESOURCE_NAME);
        // 设置流控规则 QPS
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        // 设置受保护的资源阈值
        // Set limit QPS to 20.
        rule.setCount(1);
        rules.add(rule);



        // 通过@SentinelResource来定义资源并配置降级和流控的处理方法
        FlowRule rule2 = new FlowRule();
        //设置受保护的资源
        rule2.setResource(USER_RESOURCE_NAME);
        // 设置流控规则 QPS
        rule2.setGrade(RuleConstant.FLOW_GRADE_QPS);
        // 设置受保护的资源阈值
        // Set limit QPS to 20.
        rule2.setCount(1);

        rules.add(rule2);

        // 加载配置好的规则
        FlowRuleManager.loadRules(rules);
    }

    @PostConstruct  // 初始化
    public void initDegradeRule(){
        /*降级规则 异常*/
        List<DegradeRule> degradeRules = new ArrayList<>();
        DegradeRule degradeRule = new DegradeRule();
        degradeRule.setResource(DEGRADE_RESOURCE_NAME);
        // 设置规则侧率: 异常数
        degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);
        // 触发熔断异常数 : 2
        degradeRule.setCount(2);
        // 触发熔断最小请求数:2
        degradeRule.setMinRequestAmount(2);
        // 统计时长:  单位:ms    1分钟
        degradeRule.setStatIntervalMs(60*1000); //  时间太短不好测

        // 一分钟内: 执行了2次  出现了2次异常  就会触发熔断

        // 熔断持续时长 : 单位 秒
        // 一旦触发了熔断, 再次请求对应的接口就会直接调用  降级方法。
        // 10秒过了后——半开状态: 恢复接口请求调用, 如果第一次请求就异常, 再次熔断,不会根据设置的条件进行判定
        degradeRule.setTimeWindow(10);


        degradeRules.add(degradeRule);
        DegradeRuleManager.loadRules(degradeRules);

        /*
        慢调用比率--DEGRADE_GRADE_RT
        degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_RT);
        degradeRule.setCount(100);
        degradeRule.setTimeWindow(10);
        //请求总数小于minRequestAmount时不做熔断处理
        degradeRule.setMinRequestAmount(2);
        // 在这个时间段内2次请求
        degradeRule.setStatIntervalMs(60*1000*60);   //  时间太短不好测
        // 慢请求率:慢请求数/总请求数> SlowRatioThreshold ,
        // 这里要设置小于1   因为慢请求数/总请求数 永远不会大于1
        degradeRule.setSlowRatioThreshold(0.9);*/

    }





}

设置配置文件
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第15张图片

server:
  port: 8060

Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第16张图片

Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第17张图片
访问:http://localhost:8060/hello
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第18张图片
不断刷新页面
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第19张图片

4、通过注解的方式来控流

Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第20张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第21张图片

@Data
public class User {
    private final String username;
}

Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第22张图片

/**
     * @SentinelResource 改善接口中资源定义和被流控降级后的处理方法
     * 怎么使用: 1.添加依赖sentinel-annotation-aspectj
     *          2.配置bean——SentinelResourceAspect
     *   value  定义资源
     *   blockHandler 设置 流控降级后的处理方法(默认该方法必须声明在同一个类)
     *      如果不想在同一个类中 blockHandlerClass 但是方法必须是static
     *   fallback 当接口出现了异常,就可以交给fallback指定的方法进行处理
     *      如果不想在同一个类中 fallbackClass 但是方法必须是static
     *
     *   blockHandler 如果和fallback同时指定了,则blockHandler优先级更高
     *      exceptionsToIgnore 排除哪些异常不处理
     * @param id
     * @return
     */
    @RequestMapping("/user")
    @SentinelResource(value = USER_RESOURCE_NAME,  fallback = "fallbackHandleForGetUser",
            /*exceptionsToIgnore = {ArithmeticException.class},*/
            /*blockHandlerClass = User.class,*/ blockHandler = "blockHandlerForGetUser")
    public User getUser(String id) {
      
        return new User("xushu");
    }

    public User fallbackHandleForGetUser(String id,Throwable e) {
        e.printStackTrace();
        return new User("异常处理");
    }

    /**
     * 注意:
     *  1. 一定要public
     *  2. 返回值一定要和源方法保证一致, 包含源方法的参数。
     *  3. 可以在参数最后添加BlockException 可以区分是什么规则的处理方法
     * @param id
     * @param ex
     * @return
     */
    public User blockHandlerForGetUser(String id, BlockException ex) {
        ex.printStackTrace();
        return new User("流控!!");
    }


    @RequestMapping("/degrade")
    @SentinelResource(value = DEGRADE_RESOURCE_NAME,entryType = EntryType.IN,
            blockHandler = "blockHandlerForFb")
    public User degrade(String id) throws InterruptedException {
        // 异常数\比例
        throw new RuntimeException("异常");

        /* 慢调用比例
        TimeUnit.SECONDS.sleep(1);
        return new User("正常");*/
    }

    public User blockHandlerForFb(String id, BlockException ex) {
        return new User("熔断降级");
    }

对应的依赖我们已经添加过了
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第23张图片
重新运行并访问
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第24张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第25张图片
多次刷新

5、启动Sentinel控制台

下载控制台jar包并在本地启动
下载地址:https://github.com/alibaba/Sentinel/releases
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第26张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第27张图片
运行jar

java -jar sentinel-dashboard-1.8.0.jar

运行成功
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第28张图片
访问:127.0.0.1:8080
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第29张图片

用户名:sentinel
密码:sentinel

用户可以通过如下参数进行配置

java -Dsentinel.dashboard.auth.username=sentinel  sentinel-dashboard-1.8.0.jar  #用于指定控制台用户名
java -Dsentinel.dashboard.auth.password=123456  sentinel-dashboard-1.8.0.jar  #用于指定控制台密码
java -Dserver.servlet.session.timeout=8858  sentinel-dashboard-1.8.0.jar  #用于指定Spring Boot端口

为了方便快捷启动可以在桌面创建.bat文件

java -Dserver.port=8858 -Dsentinel.dashboard.auth.username=xushu -Dsentinel.dashboard.auth.password=123456 -jar C:\Users\ZHENG\Desktop\sentinel-dashboard-1.8.0.jar

访问:http://127.0.0.1:8858/
输入上述设置的账号和密码
账号:xushu
密码:123456
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第30张图片
登录成功
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第31张图片
流控规则设置可以通过Sentinel dashboard配置
客户端需要引入Transport 模块来与Sentinel 控制台进行通信
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第32张图片


        <dependency>
            <groupId>com.alibaba.cspgroupId>
            <artifactId>sentinel-transport-simple-httpartifactId>
            <version>1.8.0version>
        dependency>

四、Spring Cloud Alibaba 整合Sentinel

1、复制创建项目并,引入依赖

Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第33张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第34张图片

 <artifactId>order-sentinelartifactId>

Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第35张图片

<module>order-sentinelmodule>

Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第36张图片

        
        <dependency>
            <groupId>com.alibaba.cloudgroupId>
            <artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
        dependency>

记住启动要Sentinel

2、完善代码

Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第37张图片

@SpringBootApplication
public class OrderApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class);
    }
}

Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第38张图片

@RestController
@RequestMapping("/order")
public class OrderController {
    @RequestMapping("/add")
    public String add(){
        System.out.println("下单成功");
        return "Hello world";
    }
}

Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第39张图片

3、启动测试

Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第40张图片
访问一下:http://localhost:8861/
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第41张图片

然后访问:http://127.0.0.1:8858/
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第42张图片
不断访问:http://localhost:8861/order/add
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第43张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第44张图片

五、Sentinel流控规则

1、实时监控

Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第45张图片

2、簇点链路

Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第46张图片
创建一个新接口
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第47张图片

    @GetMapping("/flow")
    public String flow(){
        return "正常访问";
    }

重新启动
访问:http://localhost:8861/order/flow

不断访问:
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第48张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第49张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第50张图片

六、流控规则

1、流量控制(iow conrol)

其原理是监控应用流量的QPS或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性
==== FlowRule
RT(响应时间)1/0.2s =5

Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第51张图片
同一个资源可以创建多条限流规则。

Flcowlot会对该资源的所有限流规则依次遍历,直到有规则触发限流或者所有规则遍历完毕。

一条限流规叫主要由下面几个因素组成,我可以组合这些元素来实现不同的限流效果。
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第52张图片

2、QPS

进入簇点链路选择具体的访问的API,然后点击流控按钮
QPS (Query Per Second):每秒请求数,就是说服务器在一秒的时间内处理了多少个请求。
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第53张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第54张图片
访问:http://localhost:8861/order/flow
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第55张图片
一秒内多次刷新页面
被限流了
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第56张图片
自定义返回的流控信息
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第57张图片

    @GetMapping("/flow")
    @SentinelResource(value = "flow",blockHandler = "flowBlockHandler")
    public String flow(){
        return "正常访问";
    }
    public String flowBlockHandler(BlockException exception){
        return "流控";
    }

重新启动服务
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第58张图片
我们再次访问:http://localhost:8861/order/flow
我们发现我们如何访问流控都不生效
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第59张图片
因为流控没有持久化,后期会说明持久化相关内容,现在就这样
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第60张图片

Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第61张图片

多次访问:http://localhost:8861/order/flow

Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第62张图片

3、并发线程数

并发数控制用于保护业务线程池不被慢调用耗尽。

例如,当应用所依赖的下游应用由于某种原因导致服务不稳定、响应延迟增加,对于调用者来说,意味着吞吐量下降和更多的线程数占用,极端情况下甚至导致线程池耗尽。

为应对太多线程占用的情况,业内有使用隔离的方案,比如通过不同业务逻辑使用不同线程池来隔离业务自身之间的资源争抢(线程池隔离)。

这种隔离方案虽然隔离性比较好,但是代价就是线程数目太多,线程上下文切换的 overhead 比较大,特别是对低延时的调用有比较大的影响。

Sentihel并发控制不负责创建和管理线程池,而是简单统计当前请求上下文的线程数目(正在执行的调用数目),如果超出阈值,新的请求会被立即拒绝,效果类似于信号量隔离。

并发数控制通常在调用端进行配置。

可以利用jmeter测试

Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第63张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第64张图片
设置接口睡眠
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第65张图片

@GetMapping("/flowThread")
    @SentinelResource(value = "flowThread",blockHandler = "flowBlockHandler")
    public String flowThread() throws InterruptedException{
        TimeUnit.SECONDS.sleep(5);
        return "正常访问";
    }

访问:http://localhost:8861/order/flowThread
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第66张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第67张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第68张图片
多次访问以后触发流控
开启两个浏览器
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第69张图片

Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第70张图片

4、BlockException异常统一处理

spigwebomvo接口资源限流入口在Handlerinterceptor的实现类AbstractSentiellterceptor的preHandle方法中,对异常的处理是BlockExceptionHandler的实现类

sentinel 1.7.1 引入了sentinel-spring-webmvc-adapter.jar

自定义BlockExceptionHandler的实现类统─处理BlockException

Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第71张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第72张图片

@Component
public class MyBlockExceptionHandler implements BlockExceptionHandler {
    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception {
        //  getRule() 资源 规则的详细详细
        System.out.println("BlockExceptionHandler BlockException===日日日日日日日日日日===" + e.getRule());
        String r = "";
        if (e instanceof FlowException) {
            System.out.println(100+"接口限流了");
            r = 100+"接口限流了";
        } else if (e instanceof DegradeException) {
            System.out.println(101+"服务降级了");
            r = 101+"服务降级了";
        } else if (e instanceof ParamFlowException) {
            System.out.println(102+"热点参数限流了");
            r = 102+"热点参数限流了";
        } else if (e instanceof SystemBlockException) {
            System.out.println(103+"触发系统保护规则了");
            r = 103+"触发系统保护规则了";
        } else if (e instanceof AuthorityException) {
            System.out.println(104+"授权规则不通过");
            r = 104+"授权规则不通过";
        }
        httpServletResponse.setStatus(500);
        httpServletResponse.setCharacterEncoding("utf-8");
        httpServletResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);
        new ObjectMapper().writeValue(httpServletResponse.getWriter(),r);
    }
}

修改一下之前的接口
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第73张图片

    @GetMapping("/flow")
    @SentinelResource(value = "flow",blockHandler = "flowBlockHandler")
    public String flow() throws InterruptedException{
        return "正常访问";
    }

重新启动运行
访问:http://localhost:8861/order/flow
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第74张图片

Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第75张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第76张图片
不断访问:http://localhost:8861/order/flow
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第77张图片

七、流控模式

基于调用关系的流量控制。调用关系包括调用方、被调用方;

一个方法可能会调用其它方法,形成一个调用链路的层次关系。

直接资源调用达到设置的阈值后直接被流控抛出异常

1、直接

资源调用达到设置的阈值后直接被流控抛出异常
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第78张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第79张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第80张图片

2、关联

当两个资源之间具有资源争抢或者依赖关系的时候,这两个资源便具有了关联。比如对数据库同一个字段的读操作和写操作存在争抢,读的速度过高会影响写得速度,写的速度过高会影响读的速度。

如果放任读写操作争抢资源,则争抢本身带来的开销会降低整体的吞吐量。可使用关联限流来避免具有关联关系的资源之间过度的争抢,举例来说,read_dbwrite_db这两个资源分别代表数据库读
写,
我们可以给read_db设置限流规则来达到写优先的目的:设置strategyfaleConstant.STRSECY_BEATE同时设置refResourewrite_db。这样当写库操作过于频繁时,读数据:杓请求会被限流。

例如为插入限流,影响查询

在这里插入图片描述
编写两个接口
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第81张图片


    @RequestMapping("/addOrder")
    public String addOrder() throws InterruptedException{
        System.out.println("下单成功");
        return "下单成功";
    }

    @RequestMapping("/getOrder")
    public String getOrder() throws InterruptedException{
        System.out.println("查询订单");
        return "查询订单";
    }

重新运行项目

Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第82张图片
分别访问:
http://localhost:8861/order/getOrder
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第83张图片

http://localhost:8861/order/addOrder
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第84张图片

Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第85张图片
生成订单触发查询订单
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第86张图片
上述效果人工无法模拟,我们用 JMeter来模拟

下载:https://jmeter.apache.org/download_jmeter.cgi

下载解压
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第87张图片
双击如下
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第88张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第89张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第90张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第91张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第92张图片
添加如下参数
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第93张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第94张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第95张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第96张图片
在这里插入图片描述
正在不断发起请求
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第97张图片
我们访问:http://localhost:8861/order/getOrder
发现被流控了
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第98张图片
等待所有的请求都处理完
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第99张图片
再次访问:http://localhost:8861/order/getOrder
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第100张图片

3、链路

更具调用链路入库限流
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第101张图片

下面中记录了资源之间的调用链路,这些资源通过调用关系,相互之间构成一棵调用树.
这棵树的根节点是一个名字为getUser【方法】的虚拟节点,调用链的入口都是这个虚节点的子节点。
—棵典型的调用树如下图所示:
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第102张图片

Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第103张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第104张图片

package com.itbluebox.order.service;

public interface IOrderService {
    public String getUser();
}

Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第105张图片

Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第106张图片

package com.itbluebox.order.service;

import org.springframework.stereotype.Service;

@Service
public class OrderServiceImpl implements IOrderService{
    @Override
    @SentinelResource(value = "getUser")
    public String getUser() {
        return "张三";
    }
}


Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第107张图片

    @Autowired
    private IOrderService iOrderService;

    @RequestMapping("/test1")
    public String test1() throws InterruptedException{
        return iOrderService.getUser();
    }

    @RequestMapping("/test2")
    public String test2() throws InterruptedException{
        return iOrderService.getUser();
    }

分别访问:
http://localhost:8861/order/test1
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第108张图片

http://localhost:8861/order/test2
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第109张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第110张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第111张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第112张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第113张图片
测试会发现链路规则不生效
注意,高版本此功能直接使用不生效,如何解决?
从1.6.3版本开始,Sentinel Web filter默认收敛所有URL的入口context,因此链路限流不生效1.7.0版本开始(对应SCA的2.1.1.RELEASE),官方在CommonFilter引入了
WEB CONTEXT_UNIFY参数,用于控制是否收敛context。将其配置为false即可根据不同的URL进行链路限流。SCA2.1.1.RELEASE之后的版本,可以通过配置

spring.cloud.sentinel.web-context-unify=false
即可关闭收敛我们当前使用的版本是SpringCloud Alibaba 2.1.0.RELEASE,无法实现链路限流。

目前官方还未发布SCA2.1.2.RELEASE,所以我们只能使用2.1.1.RELEASE,需要写代码的形式实现
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第114张图片

      web-context-unify: false #默认将调用链路收敛

重新设置流控规则
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第115张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第116张图片
http://localhost:8861/order/test2
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第117张图片
访问:http://localhost:8861/order/test1
随便怎么访问都没事
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第118张图片
自定义流控返回的内容
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第119张图片

@Service
public class OrderServiceImpl implements IOrderService{
    @Override
    @SentinelResource(value = "getUser",blockHandler = "blockHandlerGetUser")
    public String getUser() {
        return "张三";
    }
    public String blockHandlerGetUser(BlockException e){
        return "流控用户";
    }

}

重新启动运行项目
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第120张图片
重新设置流控规则
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第121张图片

Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第122张图片
连续访问:http://localhost:8861/order/test2
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第123张图片

八、流控效果

快速失败(RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式是默认的流量控制方式,

当QPS超过任意规则的阈值后,新的请求就会被立即拒绝,拒绝方式为抛出Prlvrtcerntion。

这种方式适用于对系统处理能力确切已知的情况下,比如通过压测确定了系统的准确水位时。

1、Warm Up(激增流量)预热冷启动

Warm Up (RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式,即预热冷启动方式。

当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压
垮。

通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。

冷加载因子: codeFactor默认是3,即请求QPS 从 threshold/3开始,经预热时长逐渐升至设定的QPS阈值。

通常冷启动的过程系统允许通过的QPS曲线如下图所示
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第124张图片
将原有的限流规则去除掉
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第125张图片

Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第126张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第127张图片
新建成功
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第128张图片
访问:http://localhost:8861/order/flow
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第129张图片
不断连续访问
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第130张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第131张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第132张图片
不断点击刷新,可以看到我们可以看到有 被拒绝有的通过了
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第133张图片

2、均匀排队(脉冲流量)

匀速排队((‘RuileConstant.CONTROL_BEHAVIOR_RATE_LMITER’)方式会严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法。该方式的作用如下图所示:
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第134张图片
这种方式主要用于处理间隔性突发的流量,例如消息队列。想象一下这样的场景,在某一秒有大量的请求到来,而接下来的几秒则处于空闲状态,我们希望系统能够在接下来的空闲期间逐渐处理这些请求,而不是在第一秒直接拒绝多余的请求。

注意:匀速排队模式暂时不支持QPS > 1000的场景

先演示一下直接失败的情况
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第135张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第136张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第137张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第138张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第139张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第140张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第141张图片
上述实现功能,发起10次请求中间间隔5秒
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第142张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第143张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第144张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第145张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第146张图片
等待运行结束
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第147张图片
上述请求当中有间隔是空闲的,我们应该高效的利用起来这部分时间
通过均匀排队(脉冲流量)来实现这一功能
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第148张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第149张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第150张图片
我们发现所有的请求都执行成功了

九、降级规则

除了流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。

我们需要对不稳定的弱依赖服务调用进行熔断降级,暂时切断不稳定调用,避免局部不稳定因素导致整体的雪崩。

熔断降级作为保护自身的手段,通常在客户端(调用端)进行配置。

熔断降级与隔离
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第151张图片
熔断降级规则说明
熔断降级规则(DegradeRule)包含下面几个重要的属性:
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第152张图片

1、熔断策略:慢调用比例(LO_REOESLRATO):

选择以慢调用比例作为阈值,需要设置允许的慢调用RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。

当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。

经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN状态),若接下来的一个请求响应时间小于设置的慢调用RT则结束熔断,若大于设置的慢调用RT则会再次被熔断
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第153张图片
修改源代码将这里修改为降级


    public String flowBlockHandler(BlockException exception){
        return "降级";
    }

Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第154张图片

创建成功
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第155张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第156张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第157张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第158张图片
我们立马访问:http://localhost:8861/order/flowThread
接口被流控
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第159张图片

10秒以后在访问
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第160张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第161张图片

2、熔断策略:异常比例

创建新的接口
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第162张图片

    @RequestMapping("/err")
    public String err() throws InterruptedException{
        int i = 1/0;
        return "hello";
    }

重新启动项目,访问对应的接口
http://localhost:8861/order/err
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第163张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第164张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第165张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第166张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第167张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第168张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第169张图片
我们可以看到服务第六次就被降级了
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第170张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第171张图片

现在是半开状态访问异常后直接熔断
在这里插入图片描述

3、熔断策略:异常数

上面资源处于半开状态这里需要重新启动一下对应内容
访问一下:http://localhost:8861/order/err
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第172张图片
http://localhost:8861/order/err

连续访问三次服务被熔断
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第173张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第174张图片
Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】_第175张图片

你可能感兴趣的:(Java,SpringCloud,java,spring,cloud,微服务)