Sentinel核心功能实战

一、Sentinel简介

1、流量控制简介

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

在这里插入图片描述

2、熔断降级简介

在调用系统的时候,如果调用链路中的某个资源出现了不稳定,最终会导致请求发生堆积,进而导致级联错误

在这里插入图片描述

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

3、Sentinel的相关概念

资源:资源是Sentinel的关键概念。它可以是Java应用程序中的任何内容,例如,由应用程序提供的服务,或由应用程序调用的其他应用提供的服务,甚至可以是一段代码。只要通过Sentinel API定义的代码,就是资源,能够被Sentinel保护起来。大部分情况下,可以使用方法签名、URL甚至是服务名称作为资源名来标示资源

规则:规则指的是围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则。所有规则可以动态实时调整

二、Sentinel控制台搭建与应用接入

1、本地应用创建

1)、引入Sentinel核心依赖

		<dependency>
			<groupId>com.alibaba.csp</groupId>
			<artifactId>sentinel-core</artifactId>
			<version>1.8.0</version>
		</dependency>

2)、定义使用限流规则

@RestController
public class TestController {
    
    

    @GetMapping("/hello")
    public String hello() {
    
    
        //使用限流规则
        try (Entry entry = SphU.entry("HelloWorld")) {
    
    
            return "Hello Sentinel!";
        } catch (BlockException e) {
    
    
            e.printStackTrace();
            return "系统繁忙,请稍候";
        }
    }

    /**
     * 定义限流规则
     *
     * @PostConstruct:当前类的构造函数执行之后执行
     */
    @PostConstruct
    public void initFLowRules() {
    
    
        //1.创建限流规则
        List<FlowRule> rules = new ArrayList<>();
        FlowRule rule = new FlowRule();
        //定义资源,表示Sentinel会对哪个资源生效
        rule.setResource("HelloWorld");
        //定义限流规则类型,QPS限流类型
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        //定义QPS每秒能通过的请求个数
        rule.setCount(2);
        rules.add(rule);
        //2.加载限流规则
        FlowRuleManager.loadRules(rules);
    }
}

3)、运行测试

访问http://localhost:8080/hello,返回Hello Sentinel!;如果快速刷新,会出现系统繁忙,请稍候

2、搭建Sentinel控制台

1)、下载jar包

下载地址:https://github.com/alibaba/Sentinel/releases/download/v1.8.0/sentinel-dashboard-1.8.0.jar

2)、启动Sentinel控制台

java -Dserver.port=9000 -jar sentinel-dashboard-1.8.0.jar

3)、访问Sentinel控制台

访问http://localhost:9000/,默认用户名和密码都是sentinel

在这里插入图片描述

3、本地应用接入Sentinel控制台

1)、引入依赖

        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-transport-simple-http</artifactId>
            <version>1.8.0</version>
        </dependency>

2)、添加配置

启动时加入JVM参数-Dcsp.sentinel.dashboard.server=localhost:9000 -Dproject.name=SentinelDemo

-Dcsp.sentinel.dashboard.server=consoleIp:port:指定控制台地址和端口

-Dproject.name=SentinelDemo:设置本地应用在Sentinel控制台中的名称

3)、运行测试

重启应用后,访问http://localhost:8080/hello,多刷新几次,查看控制台中的实时监控情况

在这里插入图片描述

4)、控制台中设置限流规则

注释掉代码中的限流规则,重启应用,访问http://localhost:8080/hello,如果快速刷新,也是显示返回Hello Sentinel!

在控制台中设置限流规则

在这里插入图片描述

如果快速刷新http://localhost:8080/hello,会出现系统繁忙,请稍候

三、Sentinel注解方式定义资源

Sentinel支持通过@SentinelResource注解定义资源并配置blockHandler函数来进行限流之后的处理

1)、引入依赖

Sentinel中使用AspectJ的扩展用于自定义资源、处理BlockException等

        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-annotation-aspectj</artifactId>
            <version>1.8.0</version>
        </dependency>

2)、创建Aspect配置类

@Configuration
public class SentinelAspectConfiguration {
    
    

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

3)、实现限流控制

@RestController
public class TestAnnController {
    
    
    //定义资源 value:设置资源的名称 blockHandler:设置限流或降级的处理函数
    @SentinelResource(value = "Sentinel_Ann", blockHandler = "exceptionHandler")
    @GetMapping("/ann")
    public String hello() {
    
    
        return "Hello Sentinel!";
    }

    //被限流的处理函数
    public String exceptionHandler(BlockException ex) {
    
    
        ex.printStackTrace();
        return "系统繁忙,请稍候";
    }
}

4)、设置限流规则

5)、运行测试

如果快速刷新http://localhost:8080/ann,会出现系统繁忙,请稍候

四、Sentinel对主流框架的支持

1、Sentinel与SpringMVC整合

1)、引入依赖

        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-spring-webmvc-adapter</artifactId>
            <version>1.8.0</version>
        </dependency>

2)、注册SentinelWebInterceptor拦截器

@Configuration
public class GlobalSentinelWebMvcConfiguration implements WebMvcConfigurer {
    
    

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
    
    
        SentinelWebMvcConfig sentinelWebMvcConfig = new SentinelWebMvcConfig();
        //指定请求方法:GET、POST等等
        sentinelWebMvcConfig.setHttpMethodSpecify(true);
        //默认使用统一Web上下文 如果希望支持链路关系的流控策略则应该设置为false
        sentinelWebMvcConfig.setWebContextUnify(true);
        //用来标识来源 可针对性的对特定客户端的请求进行流控
        sentinelWebMvcConfig.setOriginParser(request -> request.getHeader("X-Client-Id"));
        registry.addInterceptor(new SentinelWebInterceptor(sentinelWebMvcConfig)).addPathPatterns("/**");
    }

}

如果限流规则中针对来源为default,则对所有来源请求生效;如果不为default,则根据请求头中的X-Client-Id进行判断,只对X-Client-Id和针对来源一致的生效

流控规则的编写形式为:http请求方式:/请求路径和参数

3)、全局异常处理

@Slf4j
@ControllerAdvice
@Order(0)
public class SentinelControllerAdvice {
    
    
    @ExceptionHandler(BlockException.class)
    @ResponseBody
    public ResponseEntity<?> sentinelBlockHandler(HttpServletRequest request, BlockException e) {
    
    
        log.warn("Blocked by Sentinel: {}", e.getRule());
        HashMap<String, Object> map = new HashMap<>();
        map.put("path", request.getServletPath());
        map.put("msg", "limited by sentinel");
        return ResponseEntity.status(HttpStatus.TOO_MANY_REQUESTS).body(map);
    }

}

4)、编写测试Controller

@RestController
@RequestMapping("/api")
public class TestMvcController {
    
    
    @GetMapping("/hello")
    public String hello() {
    
    
        return "Hello Sentinel!";
    }
}

5)、在控制台中设置限流规则

首先将针对来源设置为default

如果快速刷新http://localhost:8080/api/hello,会出现Http状态码429,响应如下:

{
    
    
    "msg": "limited by sentinel",
    "path": "/api/hello"
}

修改针对来源为demo:

如果快速刷新http://localhost:8080/api/hello,还是显示Hello Sentinel!

使用PostMan增加请求头X-Client-Id:demo,如果快速刷新http://localhost:8080/api/hello,会出现Http状态码429,证明根据请求头判断针对来源生效

2、Sentinel与SpringCloud整合

1)、创建SpringBoot项目,引入spring-cloud-starter-alibaba-sentinel依赖

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

2)、创建TestController,实现限流控制

@RestController
public class TestController {
    
    
    //定义资源 value:设置资源的名称 blockHandler:设置限流或降级的处理函数
    @SentinelResource(value = "Sentinel_SpringCloud", blockHandler = "exceptionHandler")
    @GetMapping("/hello")
    public String hello() {
    
    
        return "Hello Sentinel!";
    }

    //被限流的处理函数
    public String exceptionHandler(BlockException ex) {
    
    
        ex.printStackTrace();
        return "系统繁忙,请稍候";
    }
}

3)、在application.properties中配置本地项目接入控制台

#设置应用的名称
spring.application.name=SpringCloudSentinel
#设置Sentinel连接控制台的主机地址和端口
spring.cloud.sentinel.transport.dashboard=localhost:9000

4)、在控制台中设置限流规则

如果快速刷新http://localhost:8080/hello,会出现系统繁忙,请稍候

3、Sentinel对Feign的支持

需求:实现sentinel_feign_consumer微服务通过Feign访问sentinel_feign_provider微服务的流量控制

主要包含以下几个工程:sentinel_springcloud、eureka_server、sentinel_feign_provider、sentinel_feign_consumer

项目GitHub地址:https://github.com/hxt970311/sentinel_springcloud

在实现了sentinel_feign_consumer微服务通过Feign访问sentinel_feign_provider微服务之后,引入Sentinel实现对sentinel_feign_consumer的流量控制:

1)、引入依赖

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

2)、application.properties中开启Sentinel对Feign的支持

spring.application.name=sentinel-feign-consumer
server.port=8090
eureka.client.register-with-eureka=false
eureka.client.service-url.defaultZone=http://localhost:7001/eureka/
#设置Sentinel控制台的主机地址和端口
spring.cloud.sentinel.transport.dashboard=localhost:9000
#打开Sentinel对Feign的支持
feign.sentinel.enabled=true

3)、创建FallbackService,作为限流降级回调类,并在FeignAgent进行流控降级回调配置

@Component
public class FallbackService implements FeignAgent {
    
    
    //限流和降级的处理
    @Override
    public String hello() {
    
    
        return "系统繁忙,请稍候";
    }
}
@FeignClient(value = "sentinel-feign-provider", fallback = FallbackService.class)
public interface FeignAgent {
    
    

    @GetMapping("/api/v1/hello")
    String hello();
}

4)、设置限流规则

Sentinel与Feign整合时,流控规则的编写形式为:http请求方式:协议://服务名/请求路径和参数(请求路径和参数为@FeignClient中的请求路径,也就是本服务调用下游服务的URL)

5)、运行测试

如果快速刷新http://localhost:8090/api/v1/consumer/hello,会出现系统繁忙,请稍候

6)、请求地址中包含参数的资源名配置

如果是多个@RequestParam,资源名不需要带上@RequestParam

如果请求路径中包含@PathVariable,案例如下:

@FeignClient(value = "sentinel-feign-provider", fallback = FallbackService.class)
public interface FeignAgent {
    
    

    @GetMapping("/api/v1/hello/{hello}")
    String hello(@PathVariable(value = "hello") String hello);
}

限流规则如下:

五、流量控制

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

流量控制主要有两种方式:

  • 并发线程数:并发线程数限流用于保护业务线程数不被耗尽
  • QPS:当QPS超过某个阈值的时候,则采取措施进行流量控制

一条限流规则主要由下面几个因素组成,可以组合这些元素来实现不同的限流效果:

  • resource:资源名,即限流规则的作用对象
  • count:限流阈值
  • grade:限流阈值类型(QPS或并发线程数)
  • limitApp:流控针对的调用来源,若为default则不区分调用来源
  • strategy:调用关系限流策略
  • controlBehavior:流量控制效果(直接拒绝、Warm Up、匀速排队)
    • 直接拒绝RuleConstant.CONTROL_BEHAVIOR_DEFAULT)方式是默认的流量控制方式,当QPS超过任意规则的阈值后,新的请求就会被立即拒绝,拒绝方式为抛出FlowException。这种方式适用于对系统处理能力确切已知的情况下,比如通过压测确定了系统的准确水位时
    • Warm UpRuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式,即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过冷启动,让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮
    • 匀速排队RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)方式会严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法

同一个资源可以同时有多个限流规则,检查规则时会依次检查

六、熔断降级

熔断降级会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联错误。当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断(默认行为跑出DegradeException

熔断降级规则(DegradeRule)包含下面几个重要的属性:

Field 说明 默认值
resource 资源名,即规则的作用对象
grade 熔断策略,支持慢调用比例/异常比例/异常数策略 慢调用比例
count 慢调用比例模式下为慢调用临界 RT(超出该值计为慢调用);异常比例/异常数模式下为对应的阈值
timeWindow 熔断时长,单位为s
minRequestAmount 熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断 5
statIntervalMs 统计时长(单位为ms),如60*1000代表分钟级 1000ms
slowRatioThreshold 慢调用比例阈值,仅慢调用比例模式有效

同一个资源可以同时有多个降级规则,检查规则时会依次检查

Sentinel提供以下几种熔断策略:

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

慢调用比例案例

@RestController
public class DegradeController {
    
    
    @SentinelResource(value = "Sentinel_Rule", blockHandler = "exceptionHandler")
    @GetMapping("/hello")
    public String hello() throws InterruptedException {
    
    
        Random random = new Random();
        Thread.sleep(random.nextInt(1000));
        return "Hello Sentinel!";
    }

    public String exceptionHandler(BlockException ex) {
    
    
        ex.printStackTrace();
        return "系统繁忙,请稍候";
    }
}

如果每秒请求响应大于500ms的比例超过0.5,则熔断10s,熔断期间请求都会返回系统繁忙,请稍候

七、开源版本Sentinel改造点

1、规则管理及推送

如果不做任何修改,SentinelDashboard的推送规则方式是通过API将规则推送至客户端并直接更新到内存中,应用重启规则就会消失

在这里插入图片描述

Push模式

Push模式的数据源,如远程配置中心(ZooKeeper、Nacos、Apollo等等),由Sentinel控制台统一进行管理,直接进行推送,数据源仅负责获取配置中心推送的配置并更新到本地。数据流向为:Sentinel控制台→配置中心→Sentinel数据源(存储)→Sentinel客户端

在这里插入图片描述

2、监控

Sentinel控制台中监控数据聚合后直接存在内存中,未进行持久化,且仅保留最近5分钟的监控数据,默认的监控数据包含应用名称、时间戳、资源名称、异常数、请求通过数、请求拒绝数、平均响应时间等信息,可以结合一些时序数据库存储监控信息,如InfluxDB

实验项目GitHub地址

Sentinel Dashboard接入,与SpringMVC、SpringCloud进行整合:https://github.com/hxt970311/sentinel-demo

Sentinel对Feign的支持:https://github.com/hxt970311/sentinel_springcloud

推荐资料

视频教程:https://www.bilibili.com/video/BV12A411E7aX

Sentinel文档:https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D

SpringCloud Alibaba Sentinel文档:https://github.com/alibaba/spring-cloud-alibaba/wiki/Sentinel

在生产环境中使用Sentinel:https://github.com/alibaba/Sentinel/wiki/%E5%9C%A8%E7%94%9F%E4%BA%A7%E7%8E%AF%E5%A2%83%E4%B8%AD%E4%BD%BF%E7%94%A8-Sentinel

猜你喜欢

转载自blog.csdn.net/qq_40378034/article/details/111413497