Sentinel服务流控熔断降级

发布时间 2023-04-17 19:46:18作者: 西东怪

Sentinel

目录旁边可以查询具体的目录结构和跳转

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

1.服务雪崩

如果其中的订单服务不可用, 就会出现线程池里所有线程都因等待响应而被阻塞, 从而造成整个服务链路不可用, 进而导致整个系统的服务雪崩. 如图所示

服务雪崩效图片:因服务提供者的不可用导致服务调用者的不可用,并将不可用逐渐放大的过程,就叫服务雪崩效应

导致服务不可用的原因

图片1

在服务提供者不可用的时候,会出现大量重试的情况:用户重试、代码逻辑重试,这些重试最终导致:进一步加大请求流量。所以归根结底导致雪崩效应的最根本原因是:大量请求线程同步等待造成的资源耗尽。当服务调用者使用同步调用时, 会产生大量的等待线程占用系统资源。一旦线程资源被耗尽,服务调用者提供的服务也将处于不可用状态, 于是服务雪崩效应产生了。

2.解决方法

常见的容错机制:

1.超时机制

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

2.服务限流(流控)

服务限流

3.隔离(和服务限流类似)

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

4.服务熔断(重点!!!)

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

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

软件世界的断路器可以这样理解:实时监测应用,如果发现在一定时间内失败次数/失败率达到一定阈值,就“跳闸”,断路器打开——此时,请求直接返回,而不去调用原本调用的逻辑。跳闸一段时间后(例如10秒),断路器会进入半开状态,这是一个瞬间态,此时允许一次请求调用该调的逻辑,如果成功,则断路器关闭,应用正常调用;如果调用依然不成功,断路器继续回到打开状态,过段时间再进入半开状态尝试——通过”跳闸“,应用可以保护自己,而且避免浪费资源;而通过半开的设计,可实现应用的“自我修复“。

所以,同样的道理,当依赖的服务有大量超时时,在让新的请求去访问根本没有意义,只会无畏的消耗现有资源。比如我们设置了超时时间为1s,如果短时间内有大量请求在1s内都得不到响应,就意味着这个服务出现了异常,此时就没有必要再让其他的请求去访问这个依赖了,这个时候就应该使用断路器避免资源浪费

服务熔断

服务降级

有服务熔断,必然要有服务降级。

所谓降级,就是当某个服务熔断之后,服务将不再被调用,此时客户端可以自己准备一个本地的fallback(回退)回调,返回一个缺省值。 例如:(备用接口/缓存/mock数据) 。这样做,虽然服务水平下降,但好歹可用,比直接挂掉要强,当然这也要看适合的业务场景。

二.快速开始

1.添加依赖

		<!--sentinel核心库-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-core</artifactId>
            <version>1.8.5</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.18</version>
        </dependency>

        <!--如果要使用@SentinelResource-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-annotation-aspectj</artifactId>
            <version>1.8.5</version>
        </dependency>

        <!--整合控制台 客户端需要引入 Transport 模块来与 Sentinel 控制台进行通信。-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-transport-simple-http</artifactId>
            <version>1.8.5</version>
        </dependency>

2.编写测试代码(限流)

@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; //Map.entry 存入用完就要退出
        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;
    }

    /**
     * 定义规则
     *注解修饰的init方法就会在Spring容器的启动时自动的执行
     * spring 的初始化方法
     */
    @PostConstruct  //注解修饰的init方法就会在Spring容器的启动时自动的执行
    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);

        // 加载配置好的规则
        FlowRuleManager.loadRules(rules);
    }
}
//注解修饰的init方法就会在Spring容器的启动时自动的执行
@PostConstruct

3.@SentinelResource注解开发(限流)

接口资源注册和抛出异常

3.1注意事项和提前准备

1.添加依赖<artifactId>sentinel-annotation-aspectj</artifactId>
2.配置切面支持bean——SentinelResourceAspect(或者直接将Bean添加在启动类中)

@Configuration
public class SentinelAspectConfiguration {
    @Bean
    public SentinelResourceAspect sentinelResourceAspect() {
    return new SentinelResourceAspect();
    }
}

3.value  定义资源
    
(如果使用fallbackClass和blockHandlerClass方法去调用对应 类.class,
	然后还要使用blockHandler去指定具体方法,记得方法必须是static)
    
4.blockHandler 设置 流控降级后的处理方法(默认该方法必须声明在同一个类)
  如果不想在同一个类中 blockHandlerClass 但是方法必须是static
    
5.fallback 当接口出现了异常,就可以交给fallback指定的方法进行处理
  如果不想在同一个类中 fallbackClass 但是方法必须是static
    
6.fallbac在异常处理类传参中增加一个Throwable 类型的参数,可以通过这个参数来实现捕获不同的异常,从而做对应的异常处理。不然捕捉不到异常。

7.blockHandle在异常处理类传参中增加一个BlockException 类型的参数,可以通过这个参数来实现捕获不同的异常,从而做对应的异常处理。不然捕捉不到异常。
 
!!! blockHandler 如果和fallback同时指定了,则blockHandler优先级更高

exceptionsToIgnore 排除哪些异常不处理

3.2测试@SentinelResource测试代码

@RestController
@Slf4j
public class Hello2Controller {
    
    private static final String USER_RESOURCE_NAME = "user";
    
    
    /**
     * @SentinelResource 改善接口中资源定义和被流控降级后的处理方法        
     * @param id
     * @return
     */
    @RequestMapping("/user")
    @SentinelResource(value = USER_RESOURCE_NAME, 
             /*fallbackClass = FallGetUser.class,*/
             fallback = "fallbackHandleForGetUser",
            /*exceptionsToIgnore = {ArithmeticException.class},*/
            /*blockHandlerClass = User.class,*/ 
             blockHandler = "blockHandlerForGetUser")
    public User getUser(String id) {
        System.out.println("--zxy--");
        return new User("zxy");
    }


    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("流控!!");
    }
    
    /**
     * 定义规则
     *
     * spring 的初始化方法
     */
    @PostConstruct
    private static void initFlowRules(){

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

        // 通过@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);
    }
}

4.@SentinelResource测试(服务熔断降级策略)

@RestController
public class DegradeController {

    private static final String DEGRADE_RESOURCE_NAME = "degrade";

    @SentinelResource(value = DEGRADE_RESOURCE_NAME,
            blockHandler = "blockHandlerForFb",
            entryType = EntryType.IN
    )
    @RequestMapping("/degrade")
    public User degrade(String id) throws InterruptedException {
        // 异常数\比例
        throw new RuntimeException("异常");
        /* 慢调用比例
        TimeUnit.SECONDS.sleep(1);
        return new User("正常");*/
    }

    public User blockHandlerForFb(String id, BlockException e){
        return new User("熔断降级");
    }
    @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);

    }
}

三.Sentinel dashboard 界面

1.依赖

<!--整合控制台 客户端需要引入 Transport 模块来与 Sentinel 控制台进行通信。-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-transport-simple-http</artifactId>
            <version>1.8.5</version>
        </dependency>

2.启动

java ‐jar sentinel‐dashboard‐1.8.5.jar

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

java -Dserver.port=8858 -Dsentinel.dashboard.auth.username=zxy -Dsentinel.dashboard.auth.password=123456 -jar C:\Users\zxy\Desktop\Sentinel\sentinel-dashboard-1.8.5.jar
pause

默认的为:访问http://localhost:8080/#/login ,默认用户名密码: sentinel/sentinel

四.SpringCloudAlibaba整合Sentinel(重点)

**流控针对privoder **

熔断降级 针对consumer

1.alibaba整合后不需要注册切面支持bean——SentinelResourceAspect
2.依靠可视化界面对接口资源的调用和默认异常抛出
3.@SentinelResource功能更多被用来调用异常抛出

1.导入依赖

<!--alibaba  Sentinel启动器  有着一个就不需要原生中的多个依赖了-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

2.yml配置

server:
  port: 8070
spring:
  application:
    name: order-sentinel
  cloud:
    sentinel:
      transport:
        #添加sentinel的控制台地址
        dashboard: 127.0.0.1:8858

3.QPS和并发线程数----流控规则

在sentinel控制台中设置流控规则

资源名: 接口的API

针对来源: 默认是default,当多个微服务都调用这个资源时,可以配置微服务名来对指定的微服务设置阈值

阈值类型: 分为QPS和线程数 假设阈值为1

QPS类型: 只得是每秒访问接口的次数>1就进行限流(在一秒中内的访问数超过1的进行流控)

线程数: 为接受请求该资源分配的线程数>1就进行限流 (对同一个接口同时处理访问数超过1的进行流控)

如果使用了@SentinelResource就选择对应value的接口

没有使用选择对应http接口

图形化流控

新增流控规则

4.公共异常处理

接口资源图形化界面调用 公共异常类抛出单一简单的异常

一般只要公共的简单且统一的异常处理就使用公共处理,针对性复杂性的异常处理使用@SentinelResource

使用了@SentinelResource就不会使用公共异常类

@Component
public class MyBlockExceptionHandler implements BlockExceptionHandler {

    Logger log= LoggerFactory.getLogger(this.getClass());

    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse response, BlockException e) throws Exception {
        // getRule() 资源  规则的详细信息
        log.info("BlockExceptionHandler BlockException================"+e.getRule());

        Result r = null;

        if (e instanceof FlowException) {
            r = Result.error(100,"接口限流了");

        } else if (e instanceof DegradeException) {
            r = Result.error(101,"服务降级了");

        } else if (e instanceof ParamFlowException) {
            r = Result.error(102,"热点参数限流了");

        } else if (e instanceof SystemBlockException) {
            r = Result.error(103,"触发系统保护规则了");

        } else if (e instanceof AuthorityException) {
            r = Result.error(104,"授权规则不通过");
        }

        //返回json数据
        response.setStatus(500);
        response.setCharacterEncoding("utf-8");
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        new ObjectMapper().writeValue(response.getWriter(), r);
    }
}

实体类

public class Result<T> {
    private Integer code;
    private String msg;
    private T data;

    public Result(Integer code, String msg, T data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }

    public Result(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public static Result error(Integer code, String msg){
        return new Result(code,msg);
    }
}

五.流控策略,熔断策略(基于Alibaba和dashboard窗口)

1.直接,关联,链路流控模式

可以使用postman进行批量接口测试

1.直接

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

2.关联

当两个资源之间具有资源争抢或者依赖关系的时候,这两个资源便具有了关联。比如对数据库同一个字段的读操作和写操作存在争抢,读的速度过高会影响写得速度,写的速度过高会影响读的速度。如果放任读写操作争抢资源,则争抢本身带来的开销会降低整体的吞吐量。可使用关联限流来避免具有关联关系的资源之间过度的争抢,举例来说,read_db 和write_db 这两个资源分别代表数据库读写,我们可以给 read_db 设置限流规则来达到写优先的目的:设置 strategy 为RuleConstant.STRATEGY_RELATE 同时设置 refResource 为 write_db。这样当写库操作过于频繁时,读数据的请求会被限流。

关联流控模式

3.链路

1.配置和理解

@SentinelResource不仅可以流控接口,还可以流控方法

下面中记录了资源之间的调用链路,这些资源通过调用关系,相互之间构成一棵调用树。这棵树的根节点是一个名字为getUser 的虚拟节点,调用链的入口都是这个虚节点的子节点。

一棵典型的调用树如下图所示:

1  	    getUser
2       /      \
3      /         \
4 /order/test1 /order/test2

上图中来自入口 /order/test1 和 /order/test2的请求都调用到了资源 getUser,Sentinel 允许只根据某个入口的统计信息对资源限流。

链路流控规则

测试会发现链路规则不生效

注意,高版本此功能直接使用不生效,如何解决?

从1.6.3 版本开始,Sentinel Web filter默认收敛所有URL的入口context,因此链路限流不生效。

1.7.0 版本开始(对应SCA的2.1.1.RELEASE),官方在CommonFilter 引入了

WEB_CONTEXT_UNIFY 参数,用于控制是否收敛context。将其配置为 false 即可根据不同的URL 进行链路限流。

SCA 2.1.1.RELEASE之后的版本,可以通过配置spring.cloud.sentinel.web-context-unify=false即可关闭收敛 
!!! spring.cloud.sentinel.web‐context‐unify: false

测试,此场景拦截不到BlockException,对应@SentinelResource指定的资源必须在@SentinelResource注解中指定blockHandler处理BlockException

2.代码测试
	@Resource
    IOrderService orderService;

    // 链路流控   访问/test1
    @RequestMapping("/test1")
    public String test1(){
        return orderService.getUser();
    }
    // 链路流控  访问/test2
    @RequestMapping("/test2")
    public String test2(){
        return orderService.getUser();
    }
@Service
public class OrderServiceImpl implements IOrderService {

    @Override
    @SentinelResource(value="getUser",blockHandler = "blockHandlerGetUser")
    public String getUser() {
        return "查询用户";
    }

    public String blockHandlerGetUser(BlockException e) {
        return "流控用户";
    }
}
public interface IOrderService {
    String getUser();
}

2.快速失败,Warm Up(激增流量),排队流控效果

可以使用postman进行批量接口测试

1.快速失败

(RuleConstant.CONTROL_BEHAVIOR_DEFAULT)方式是默认的流量控制方式,当QPS超过任意规则的阈值后,新的请求就会被立即拒绝,拒绝方式为抛出FlowException。这种方式适用于对系统处理能力确切已知的情况下,比如通过压测确定了系统的准确水位时。

2.Warm Up(针对激增流量)

激增流量:先长时间处于平稳的流量突然迎来洪峰流量,然后又很长时间处于平稳

Warm Up(RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式,即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。

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

Warm up流控效果

3.排队等待(针对脉冲流量)

脉冲流量:就行波浪一样,先空闲然后洪峰,又空闲又洪峰的反复来临

匀速排队RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)方式会严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法。(排队等待只能是 QPS)

该方式的作用如下图所示:

匀速排队作用图

这种方式主要用于处理间隔性突发的流量,例如消息队列。想象一下这样的场景,在某一秒有大量的请求到来,而接下来的几秒则处于空闲状态,我们希望系统能够在接下来的空闲期间逐渐处理剩下的请求而不是在第一秒直接拒绝多余的请求

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

匀速排队

比如:现在QPS阈值为5,直接且排队等待,超时时间2s,现在有100个请求过来,服务器最多处理 5 个,其他慢慢排队,在处理所有的请求的时候,都是均匀的处理,0.01S处理第一个请求,0.21S处理第二个请求,0.41S请求处理第三个请求...0.81S处理第5个请求,然后依次类推,间隔时间为 1秒/QPS,比如1/5,0.2S处理一个请求;在排队的请求,如果排队的时间超过了超时时间,就不再等待,返回给客户端一个提示信息。

3.慢调用比例,异常比例,异常数熔断规则

!!!熔断时长结束后进入探测恢复状态若接下来的一个请求成功完成(没有错误)则结束熔断否则会再次被熔断

1.慢调用比例

慢调用比例 (SLOW_REQUEST_RATIO):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF­OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。

慢调用比例

测试用例

	@RequestMapping("/flowThread")
    public String flowThread() throws InterruptedException {
        Thread.sleep(100);
        System.out.println("正常访问!");
        return "正常访问";
    }

2.异常比例

异常比例 (ERROR_RATIO):当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长结束后后熔断器会进入探测恢复状态(HALF­OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% ­ 100%。

异常比例熔断

测试:

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

3.异常数

异常数 (ERROR_COUNT):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF­OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。注意:异常降级仅针对业务异常,对 Sentinel 限流降级本身的异常(BlockException)不生效。

异常数熔断

测试:

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

六.热点参数限流,系统保护规则

1.热点参数限流

何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的数据,并对其访问进行限制。

什么是热点参数

热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。

热点参数限流

注意:

  1. 热点规则需要使用@SentinelResource("resourceName")注解,否则不生效

  2. 参数必须是7种基本数据类型才会生效

测试用例:

/**
     * 热点规则,必须使用@SentinelResource
     * @param id
     * @return
     * @throws InterruptedException
     */
    @RequestMapping("/get/{id}")
    @SentinelResource(value = "getById",blockHandler = "HotBlockHandler")
    public String getById(@PathVariable("id") Integer id) throws InterruptedException {

        System.out.println("正常访问");
        return "正常访问";
    }

    public String HotBlockHandler(@PathVariable("id") Integer id, BlockException e) throws InterruptedException {

        return "热点异常处理";
    }

(参数设置的注意点!!!) 单机阈值: 针对所有参数的值进行设置的一个公共的阈值

  1. 假设当前 参数 大部分的值都是热点流量, 单机阈值就是针对热点流量进行设置, 额外针对普通流量进行参数值流控

  2. 假设当前 参数 大部分的值都是普通流量, 单机阈值就是针对普通流量进行设置, 额外针对热点流量进行参数值流控

配置热点参数规则

注意: 资源名必须是@SentinelResource(value="资源名")中 配置的资源名,热点规则依赖于注解

热点参数

2.系统保护规则

Sentinel 系统自适应限流从整体维度对应用入口流量进行控制,结合应用的 Load、CPU 使用率、总体平均 RT、入口 QPS 和并发线程数等几个维度的监控指标,通过自适应的流控策略,让系统的入口流量和系统的负载达到一个平衡,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。

Load 自适应(仅对 Linux/Unix­like 机器生效):系统的 load1 作为启发指标,进行自适应系统保护。当系统load1 超过设定的启发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护(BBR 阶段)。系统容量由系统的 maxQps * minRt 估算得出。设定参考值一般是 CPU cores * 2.5。https://www.cnblogs.com/gentlemanhai/p/8484839.html

CPU usage(1.5.0+ 版本):当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0­1.0),比较灵敏。

平均 RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。

并发线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。

入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。

实例:

系统保护规则-QPS

七.OpenFeign和Sentinel整合

关于Feign部分不变

1.依赖

<!--Nacos服务注册发现-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <!-- openfeign 远程调用 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

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

2.application.yml

server:
  port: 8041
spring:
  application:
    name: order-openfeign-sentinel
  cloud:
    nacos:
      server-addr: localhost:8848
      discovery:
        username: nacos
        password: nacos
        namespace: public
    sentinel:
      transport:
        dashboard: 127.0.0.1:8858
feign:
  #开启OpenFeign对sentinel的支持(整合)
  sentinel:
    enabled: true

3.openfegin接口

@FeignClient(value = "stock-service",path = "/stock",
			fallback = StockFeignServiceFallback.class)
public interface StockFeignService {

    @RequestMapping("/reduct2")
    public String reduct2();

}

4.openfegin的fallback实现类

@Component
public class StockFeignServiceFallback implements StockFeignService{
    @Override
    public String reduct2() {
        return "降级!!";
    }
}

八.Sentinel规则持久化

1.导入依赖

		<!‐‐sentinel持久化 采用 Nacos 作为规则配置数据源‐‐>
		<dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>

2.yml

server:
  port: 8070
spring:
  application:
    name: order-sentinel
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    sentinel:
      transport:
        #添加sentinel的控制台地址
        dashboard: 127.0.0.1:8858
      #关闭链路资源收敛
      web-context-unify: false
      datasource:
        flow-rule: #名称自定义,唯一
          nacos:
            server-addr: localhost:8848
            username: nacos
            password: nacos
            dataId: order-sentinel-flow-rule  #Nacos配置dataId
            file-extension: json
            rule-type: flow  #选择规则 流控

3.Nacos添加配置文件

[
{
    "resource": "/order/flow",
    "controlBehavior": 0,
    "count": 2,
    "grade": 1,
    "limitApp": "default",
    "strategy": 0
}
]

Sentinel-Nacos持久化配置

4.流控和熔断配置详情

流控配置:json文件配置的各参数对应的意思:
    resource:资源名,即限流规则的作用对象
    count: 限流阈值
    grade: 限流阈值类型(1:QPS;0:并发线程数
    limitApp: 流控针对的调用来源,若为 default 则不区分调用来源
    strategy: 流控模式(0:直接;1:关联;2:链路)
    controlBehavior: 流控效果(0:快速失败;1:Warm Up(预热模式);2:排队等待)
    // 预热时间(秒,预热模式需要此参数)
    //"warmUpPeriodSec": 10,
    // 超时时间(排队等待模式需要此参数)
    //"maxQueueingTimeMs": 500,
    // 关联资源、入口资源(关联、链路模式)
    //"refResource": "rrr"


降级规则:
  	// 资源名
    "resource": "/test1",
    "limitApp": "default",
    // 熔断策略(0:慢调用比例,1:异常比率,2:异常计数)
    "grade": 0,
    // 最大RT、异常比例阈值、异常数
    "count": 200,
    // 慢调用比例阈值,仅慢调用比例模式有效(1.8.0 引入)
    "slowRatioThreshold": 0.2,
    // 最小请求数
    "minRequestAmount": 5,
    // 当单位统计时长(类中默认1000)
    "statIntervalMs": 1000,
    // 熔断时长
    "timeWindow": 10


Sentinel依赖和yml配置总合

server:
  port: 8070
spring:
  application:
    name: order-sentinel
  cloud:
    sentinel:
      transport:
        #添加sentinel的控制台地址
        dashboard: 127.0.0.1:8858
      web‐context‐unify: false #关闭链路收敛
      datasource: #Sentinel规则持久化
        flow-rule: #名称自定义,唯一
          nacos:
            server-addr: localhost:8848
            username: nacos
            password: nacos
            dataId: order-sentinel-flow-rule  #Nacos配置dataId
            file-extension: json
            rule-type: flow  #选择规则 流控
feign:
  #开启OpenFeign对sentinel的支持(整合)
  sentinel:
    enabled: true

依赖

<!--alibaba  Sentinel启动器  有着一个就不需要原生中的多个依赖了-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- openfeign 远程调用 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>