SpringCloud Alibaba Sentinel实现熔断和限流

一、Sentinel介绍:

在这里插入图片描述

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

Sentinel和hystrix的比较:
在这里插入图片描述

1.官网:https://github.com/alibaba/Sentinel

2.Sentinel 是什么:

随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。

3.Sentinel 具有以下特征:

  • 丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。

  • 完备的实时监控:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。

  • 广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Apache Dubbo、gRPC、Quarkus 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。同时 Sentinel 提供 Java/Go/C++ 等多语言的原生实现。

  • 完善的 SPI 扩展机制:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。

Sentinel 的主要特性:
在这里插入图片描述
4.Sentinel 的开源生态:

在这里插入图片描述

Sentinel 分为两个部分:

  • 核心库(Java 客户端)不依赖任何框架/库,能够运行于所有 Java 运行时环境,同时对 Dubbo / Spring Cloud等框架也有较好的支持。

  • 控制台(Dashboard)基于 Spring Boot 开发,打包后可以直接运行,不需要额外的 Tomcat 等应用容器。

二、Sentinel下载安装运行:

1.下载地址链接: github.com/alibaba/Sentinel/releases.

将下载好的jar包放到一个任意目录下,如e/f盘下任意路径。

在这里插入图片描述

在这里插入图片描述

2.Sentinel安装运行:(免安装,直接运行即可)

在这里插入图片描述

2.1 运行的前提环境:需要java8和8080端口不能被占用:

2.2 在存放sentinel-dashboard-1.8.1.jar 的目录下输入cmd,然后输入如下运行命令(这里都是在windows下运行的):

java -jar sentinel-dashboard-1.8.1.jar

在这里插入图片描述

在这里插入图片描述

3.登录Sentinel控制台:
登录控制台网址:http://localhost:8080/#/login
注意:后台sentinel要一直启动着
用户名和密码都是:sentinel

在这里插入图片描述

登录成功:
在这里插入图片描述

三、案例演示:

在这里插入图片描述
先启动服务注册中心8848:这里省略
(1)创建模块:cloudalibaba-sentinel-service8401
(2)改pom:

<dependencies>
        <!---alibaba-nacos-discovery-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--sentinel-datasource-nacos-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>
        <!--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>
        <!--spring-boot-starter-web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--spring-boot-starter-actuator-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency><!--热部署-->
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

在这里插入图片描述
(3)写yml:

server:
  port: 8401
spring:
  application:
    name: cloudalibaba-sentinel-service
  cloud:
    nacos:
      discovery:
        #nacos服务注册中心地址
        server-addr: 192.168.211.205:1111

    sentinel:
      transport:
        #配置sentinel 仪表盘地址
        dashboard: localhost:8080
        #默认8719端口,假如被占用会自动从8719开始依次+1扫描找端口
        port: 8719
management:
  endpoints:
    web:
      exposure:
        include: '*'

在这里插入图片描述
(4)主启动类:com.fan.springcloud.SentinelMainApp8401

package com.fan.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

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

在这里插入图片描述

(5)业务类controller:controller.FlowLimitController

package com.fan.springcloud.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class FlowLimitController {
    @GetMapping("/testA")
    public String testA(){
        return "--------testA";
    }
    @GetMapping("/testB")
    public String testB(){
        return "--------testB";
    }
}

在这里插入图片描述

然后后台启动哨兵sentinel :这里我们在我们的windows主机后台启动。然后前台查看仪表盘:
在这里插入图片描述
启动微服务测试:widows测试网址:localhost:8080
在这里插入图片描述

然后执行一次访问:访问测试网址:
localhost:8401/testA
localhost:8401/testB
在这里插入图片描述

测试结果:sentinel8080正在监控微服务8401
在这里插入图片描述

四、流控规则:

1.基本介绍:

在这里插入图片描述

2.流控模式:

在这里插入图片描述

2.1 直接快速失败

设置流控的两种方式:

在这里插入图片描述

在这里插入图片描述
一、QPS直接失败:(QPS:每秒的请求数):
在这里插入图片描述

测试是否流控设置成功:
在这里插入图片描述
二、线程数接失败:

在这里插入图片描述

在这里插入图片描述

多个线程访问,测试:

在这里插入图片描述

2.2 关联:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
上图说明:当A领导关联了B下属,当B的惹事数达到每秒1个后,A则要被牵扯限流,不能使用。

在这里插入图片描述

模拟并发访问:
1.GET请求,http://localhost:8401/testB
在这里插入图片描述
2.
在这里插入图片描述
3.给线程组添加访问地址

在这里插入图片描述
跑线程组:
在这里插入图片描述

当正在跑线程组的时候,访问测试testA发现A被限流:
在这里插入图片描述

2.3 链路:

在这里插入图片描述

3.流控效果:

在这里插入图片描述

3.1 直接快速失败(默认的流控处理)效果:

在这里插入图片描述

3.2 预热 :Warm Up

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
这里我们使用testB来新增一个流控:
在这里插入图片描述

预热的应用场景:

在这里插入图片描述

3.3 排队等待:

原理:
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
上图说明:即testB的请求只能一秒钟一个,超过了一个只能让多于的请求排队。

测试:
增加如下内容;

log.info(Thread.currentThread().getName()+"\t"+"----testB");

在这里插入图片描述
postman压力测试:

在这里插入图片描述

测试结果:排队进行:
在这里插入图片描述

五、降级:

1.官网:
https://github.com/alibaba/Sentinel/wiki/%E7%86%94%E6%96%AD%E9%99%8D%E7%BA%A7

2.概述:

除了流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。一个服务常常会调用别的模块,可能是另外的一个远程服务、数据库,或者第三方 API 等。例如,支付的时候,可能需要远程调用银联提供的 API;查询某个商品的价格,可能需要进行数据库查询。然而,这个被依赖服务的稳定性是不能保证的。如果依赖的服务出现了不稳定的情况,请求的响应时间变长,那么调用服务的方法的响应时间也会变长,线程会产生堆积,最终可能耗尽业务自身的线程池,服务本身也变得不可用。

现代微服务架构都是分布式的,由非常多的服务组成。不同服务之间相互调用,组成复杂的调用链路。以上的问题在链路调用中会产生放大的效果。复杂链路上的某一环不稳定,就可能会层层级联,最终导致整个链路都不可用。因此我们需要对不稳定的弱依赖服务调用进行熔断降级,暂时切断不稳定调用,避免局部不稳定因素导致整体的雪崩。熔断降级作为保护自身的手段,通常在客户端(调用端)进行配置。

注意:本文档针对 Sentinel 1.8.0 及以上版本。1.8.0 版本对熔断降级特性进行了全新的改进升级,请使用最新版本以更好地利用熔断降级的能力

1. 降级-RT:

在这里插入图片描述

上图说明:
在这里插入图片描述

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

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

注意Sentinel默认统计的RT上限是4900ms,超出此阈值的都会算作4900ms,若需要变更此上限可以通过启动配置项-Dcsp.sentinel.statistic.max.rt=xxx来配置

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

  2. 异常数 (ERROR_COUNT):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。

注意异常降级仅针对业务异常,对 Sentinel 限流降级本身的异常(BlockException)不生效。为了统计异常比例或异常数,需要通过 Tracer.trace(ex) 记录业务异常

在这里插入图片描述

熔断降级实战:

在这里插入图片描述

添加pom工具包:

<dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-core</artifactId>
            <version>5.6.5</version>
 </dependency>

controller添加如下映射方法:
导入的包:import java.util.concurrent.TimeUnit;

 @GetMapping("/testD")
    public String testD(){
        try {
            TimeUnit.SECONDS.sleep(1);

        }catch (InterruptedException e){
            e.printStackTrace();
        }
        log.info("testD,测试 rt");
        return "--------testD";
    }

配置:
在这里插入图片描述

在这里插入图片描述
达到熔断的额两个条件:最大响应时间,和最小请求数,都超过才熔断。

压力测试:jmeter:
在这里插入图片描述

在这里插入图片描述
线程组下add一个http请求:然后绿色三角运行
在这里插入图片描述

测试结果:
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2. 降级-异常比例:

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

案例:

代码:
在这里插入图片描述

配置:
在这里插入图片描述
1.8.1版本配置:
在这里插入图片描述

压力测试:
在这里插入图片描述

在这里插入图片描述
结论:

在这里插入图片描述

3 . 降级-异常数:

异常数 (ERROR_COUNT):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

代码:
在这里插入图片描述

 @GetMapping("/testE")
    public String testE(){
        log.info("testE  测试异常数");
        int age = 10 / 0;
        return "test  ee  测试异常数的";
    }

配置:
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

六、热点key:

官网:https://github.com/alibaba/Sentinel/wiki/%E7%83%AD%E7%82%B9%E5%8F%82%E6%95%B0%E9%99%90%E6%B5%81

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

商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制
用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制

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

Sentinel 利用 LRU 策略统计最近最常访问的热点参数,结合令牌桶算法来进行参数级别的流控。热点参数限流支持集群模式。
在这里插入图片描述

在这里插入图片描述

代码:

 //热点参数限流测试
    @GetMapping("/testHotKey")
    @SentinelResource(value = "testHotKey" ,blockHandler = "deal_testHotKey")
    public String testHotKey(@RequestParam(value = "p1",required = false) String p1,
                             @RequestParam(value = "p2",required = false) String p2){
        return "----------testHotKey ";
    }
    //兜底方法
    public String deal_testHotKey (String p1, String p2, BlockException exception){
        return "----兜底的处理方法----testHotKey,哭脸";
    }

在这里插入图片描述
在这里插入图片描述

说明:@sentinelresource注解是和sentinel网页控制台关联的,@sentinelresource注解关联的规则是在sentinel网页控制台上的。

测试1:没有做热点参数做限流的测试: http://localhost:8401/testHotKey
在这里插入图片描述
测试2:没有做热点参数做限流的测试: http://localhost:8401/testHotKey?p1=a&p2=b

在这里插入图片描述
测试3:
在这里插入图片描述

测试3(多次快速点击):http://localhost:8401/testHotKey?p1=a&p2=b
在这里插入图片描述

当我们没超过1次/s 的点击数的时候,我们能正常访问,但是当2次以上点击/s ,则走兜底的方法。打印如下:

在这里插入图片描述

其他测试:
http://localhost:8401/testHotKey?p1=abc
http://localhost:8401/testHotKey?p1=abc&p2=33

http://localhost:8401/testHotKey?p2=33

在这里插入图片描述

参数例外项:

在这里插入图片描述

在这里插入图片描述

测试:
http://localhost:8401/testHotKey?p1=5
在这里插入图片描述

扩展测试:
在这里插入图片描述

在这里插入图片描述

七、 系统自适应限流:

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

背景:

在开始之前,我们先了解一下系统保护的目的:

保证系统不被拖垮
在系统稳定的前提下,保持系统的吞吐量
长期以来,系统保护的思路是根据硬指标,即系统的负载 (load1) 来做系统过载保护。当系统负载高于某个阈值,就禁止或者减少流量的进入;当 load 开始好转,则恢复流量的进入。这个思路给我们带来了不可避免的两个问题:

load 是一个“结果”,如果根据 load 的情况来调节流量的通过率,那么就始终有延迟性。也就意味着通过率的任何调整,都会过一段时间才能看到效果。当前通过率是使 load 恶化的一个动作,那么也至少要过 1 秒之后才能观测到;同理,如果当前通过率调整是让 load 好转的一个动作,也需要 1 秒之后才能继续调整,这样就浪费了系统的处理能力。所以我们看到的曲线,总是会有抖动。
恢复慢。想象一下这样的一个场景(真实),出现了这样一个问题,下游应用不可靠,导致应用 RT 很高,从而 load 到了一个很高的点。过了一段时间之后下游应用恢复了,应用 RT 也相应减少。这个时候,其实应该大幅度增大流量的通过率;但是由于这个时候 load 仍然很高,通过率的恢复仍然不高。
TCP BBR 的思想给了我们一个很大的启发。我们应该根据系统能够处理的请求,和允许进来的请求,来做平衡,而不是根据一个间接的指标(系统 load)来做限流。最终我们追求的目标是 在系统不被拖垮的情况下,提高系统的吞吐率,而不是 load 一定要到低于某个阈值。如果我们还是按照固有的思维,超过特定的 load 就禁止流量进入,系统 load 恢复就放开流量,这样做的结果是无论我们怎么调参数,调比例,都是按照果来调节因,都无法取得良好的效果。

Sentinel 在系统自适应保护的做法是,用 load1 作为启动自适应保护的因子,而允许通过的流量由处理请求的能力,即请求的响应时间以及当前系统正在处理的请求速率来决定。

系统规则:

系统保护规则是从应用级别的入口流量进行控制,从单台机器的 load、CPU 使用率、平均 RT、入口 QPS 和并发线程数等几个维度监控应用指标,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。

系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量生效。入口流量指的是进入应用的流量(EntryType.IN),比如 Web 服务或 Dubbo 服务端接收的请求,都属于入口流量。

系统规则支持以下的模式:

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

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

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

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

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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值