springcloud笔记十sentinel

Posted 今夜月色很美

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了springcloud笔记十sentinel相关的知识,希望对你有一定的参考价值。

sentinel dashboard

下载地址

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

启动dashboard

java -jar sentinel-dashboard-1.8.2.jar

登录dashboard

http://localhost:8080/

规则的种类

官网描述的非常详细。

https://sentinelguard.io/zh-cn/docs/basic-api-resource-rule.html

Sentinel 的所有规则都可以在内存态中动态地查询及修改,修改之后立即生效。同时 Sentinel 也提供相关 API,供您来定制自己的规则策略。

Sentinel 支持以下几种规则:流量控制规则熔断降级规则系统保护规则来源访问控制规则热点参数规则

流量控制规则 (FlowRule)

流量规则的定义

重要属性:

Field说明默认值
resource资源名,资源名是限流规则的作用对象
count限流阈值
grade限流阈值类型,QPS 或线程数模式QPS 模式
limitApp流控针对的调用来源default,代表不区分调用来源
strategy调用关系限流策略:直接、链路、关联根据资源本身(直接)
controlBehavior流控效果(直接拒绝 / 排队等待 / 慢启动模式),不支持按调用关系限流直接拒绝

同一个资源可以同时有多个限流规则。

流控模式(直接)

单机阈值比较好理解,就是对QPS/线程数的控制。
QPS与线程数的区别在于:

  • QPS(每秒的访问次数),到达一定的阈值,就进行限流
  • 线程数,调用该api的线程数达到阈值的时候,进行限流

流控模式(关联)

定义:当关联的资源达到阈值时,限流自己。
如当testB的QPS的阈值到达1的时候,testA就会被限流。

Warm Up

它的实现是在 Guava 的算法的基础上实现的。然而,和 Guava 的场景不同,Guava 的场景主要用于调节请求的间隔,即 Leaky Bucket,而 Sentinel 则主要用于控制每秒的 QPS,即我们满足每秒通过的 QPS 即可,我们不需要关注每个请求的间隔,换言之,我们更像一个 Token Bucket

我们用桶里剩余的令牌来量化系统的使用率。假设系统每秒的处理能力为 b,系统每处理一个请求,就从桶中取走一个令牌;每秒这个令牌桶会自动掉落b个令牌。令牌桶越满,则说明系统的利用率越低;当令牌桶里的令牌高于某个阈值之后,我们称之为令牌桶"饱和"。

默认 coldFactor 为 3,即请求 QPS 从 threshold / 3 开始,经预热时长逐渐升至设定的 QPS 阈值。

例如如下配置流控规则是QPS从3开始,经过10s预热逐渐升至单机阈值10。

排队等待

Leaky Bucket 对应 流量整形 中的匀速器。它的中心思想是,以固定的间隔时间让请求通过。当请求到来的时候,如果当前请求距离上个通过的请求通过的时间间隔不小于预设值,则让当前请求通过;否则,计算当前请求的预期通过时间,如果该请求的预期通过时间小于规则预设的 timeout 时间,则该请求会等待直到预设时间到来通过(排队等待处理);若预期的通过时间超出最大排队时长,则直接拒接这个请求。

这种方式适合用于请求以突刺状来到,这个时候我们不希望一下子把所有的请求都通过,这样可能会把系统压垮;同时我们也期待系统以稳定的速度,逐步处理这些请求,以起到“削峰填谷”的效果,而不是拒绝所有请求。

例如,如果系统使用 Apache RocketMQ 来收发消息,系统在某个时间突然收到大量消息。我们希望以固定的速率来处理消息,而不是一下子拒绝这些消息。这个时候可以使用匀速器,也就是给消息排队

熔断策略

  • 慢调用比例 (SLOW_REQUEST_RATIO):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。
  • 异常比例 (ERROR_RATIO):当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。
  • 异常数 (ERROR_COUNT):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。

热点参数限流

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

以下热点参数限流配置即意味着调用sentinel资源aa接口的时候,如果传了该方法第0个参数则进行热点参数限流计数,满足规则触发限流。

可以通过@SentinelResource设置资源点和兜底异常处理方法(仅热点规则兜底),注意,定义兜底异常处理方法时,兜底方法参数列表和资源点参数列表一致,并在参数列表中添加BlockException。

	@GetMapping("/testParamKey")
    @SentinelResource(value = "aa", blockHandler = "deal_testParamKey")
    public String testParamKey(@RequestParam(value = "name", required = false) String name,
                               @RequestParam(value = "age", required = false) String age){
        System.out.println("name:" + name + ",age:" + age);
        return "---------------testParamKey";
    }

    public String deal_testParamKey(String name, String age, BlockException blockException){
        return "---------------deal_testParamKey";
    }

系统限流

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

全局兜底处理

自定义全局兜底方法

package com.fox.springcloud.handler;

import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.fox.springcloud.entity.CommonResult;

public class GlobalBlockExceptionHandler {

    public static CommonResult testA_handler(BlockException exception){
        return new CommonResult(500, exception.getLocalizedMessage() + "==testA服务不可用");
    }

    public static CommonResult testC_handler(BlockException exception){
        return new CommonResult(500, exception.getLocalizedMessage() + "==testC服务不可用");
    }
}

controller

@GetMapping("/testA")
    @SentinelResource(value = "testA", blockHandlerClass = GlobalBlockExceptionHandler.class, blockHandler = "testA_handler")
    public CommonResult testA(){
        log.info(Thread.currentThread().getName());
        return new CommonResult(200, Thread.currentThread().getName());
    }

    @GetMapping("/testC")
    @SentinelResource(value = "testC", blockHandlerClass = GlobalBlockExceptionHandler.class, blockHandler = "testC_handler")
    public CommonResult testC(){
        return new CommonResult(200, "testC");
    }

本人自测全局兜底处理配置流控规则时只能用资源名,用url配置的流控规则促发限流时自定义兜底不生效。

sentinel熔断

nacos使用ribbon负载均衡

nacos使用ribbon做负载均衡,服务提供者不用改,使用nacos做服务注册即可。

服务消费者添加负载均衡配置类

@Configuration
public class ApplicationContextConfig {
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

controller层注入restTemplate使用服务名调用

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.fox.springcloud.entity.CommonResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

@RestController
@Slf4j
public class CircleBreakerController {

    private static final String service_url = "http://nacos-ribbon-provider";

    @Resource
    private RestTemplate restTemplate;

    @GetMapping("/consume/echo/{id}")
    public CommonResult<String> callback(@PathVariable Long id){
        if (id == 4){
            throw new IllegalArgumentException("IllegalArgumentException 非法参数异常。。。");
        }
        return new CommonResult<>(200, restTemplate.getForObject(service_url + "/echo/" + id, String.class));
    }
}

添加sentinel熔断配置

创建兜底方法添加到要兜底的方法fallback配置属性上

	@GetMapping("/consume/echo/{id}")
    @SentinelResource(value = "fallback", fallback = "handler_fallback")
    public CommonResult<String> callback(@PathVariable Long id){
        if (id == 4){
            throw new IllegalArgumentException("IllegalArgumentException 非法参数异常。。。");
        }
        return new CommonResult<>(200, restTemplate.getForObject(service_url + "/echo/" + id, String.class));
    }

    public CommonResult<String> handler_fallback(@PathVariable Long id, Throwable e){
        return new CommonResult<>(500, "全局兜底异常处理:" + e.getMessage());
    }

配置fallback和blockhandler

	@GetMapping("/consume/echo/{id}")
    @SentinelResource(value = "fallback", fallback = "handler_fallback", blockHandler = "handler_block")
    public CommonResult<String> callback(@PathVariable Long id){
        if (id == 4){
            throw new IllegalArgumentException("IllegalArgumentException 非法参数异常。。。");
        }
        return new CommonResult<>(200, restTemplate.getForObject(service_url + "/echo/" + id, String.class));
    }

    public CommonResult<String> handler_fallback(@PathVariable Long id, Throwable e){
        return new CommonResult<>(500, "全局兜底业务异常处理:" + e.getMessage());
    }

    public CommonResult<String> handler_block(@PathVariable Long id, BlockException e){
        return new CommonResult<>(543, "全局兜底流控规则异常处理:" + e.getClass().getName());
    }

当@SentinelResource同时配置fallback熔断配置和blockhandler流控规则,流控规则优先。

exceptionsToIgnore

配置某些异常不走熔断兜底处理,支持配置多个

@SentinelResource(value = "fallback", fallback = "handler_fallback", blockHandler = "handler_block", exceptionsToIgnore = {IllegalArgumentException.class})

熔断openfeign

pom.xml添加openfeign maven坐标

		<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

yaml配置文件开启Feign对sentinel的支持

# Feign开启sentinel支持
feign:
  sentinel:
    enabled: true

启动类添加@EnableFeignClients

创建带@FeignClient的接口

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient(value = "nacos-ribbon-provider", fallback = EchoFallbackService.class)
public interface EchoService {

    @GetMapping(value = "/echo/{id}")
    public String echo(@PathVariable("id") Long id);
}

创建fallback兜底处理

import org.springframework.stereotype.Component;

@Component
public class EchoFallbackService implements EchoService {
    @Override
    public String echo(Long id) {
        return "全局兜底业务异常处理";
    }
}
    public String echo(@PathVariable("id") Long id);
}

创建fallback兜底处理

import org.springframework.stereotype.Component;

@Component
public class EchoFallbackService implements EchoService {
    @Override
    public String echo(Long id) {
        return "全局兜底业务异常处理";
    }
}

以上是关于springcloud笔记十sentinel的主要内容,如果未能解决你的问题,请参考以下文章

SpringCloud 学习笔记总结

sentinel入门相关笔记(springcloud熔断器)

sentinel入门相关笔记(springcloud熔断器)

SpringCloud - Spring Cloud Alibaba 之 Gateway 集成Sentinel

SpringCloud第二季之Nacos,Sentinel,Seata以及雪花算法学习笔记

SpringCloud第二季之Nacos,Sentinel,Seata以及雪花算法学习笔记