SpringCloud 之 Sentinel

本文详细介绍了如何在Spring Cloud应用中集成Sentinel流量控制和熔断降级,包括初始监控配置、流控规则、熔断策略、热点参数限流和@SentinelResource注解的使用。通过实例演示了QPS限流、线程数控制和微服务熔断,以及持久化规则的配置过程。
摘要由CSDN通过智能技术生成

1、下载安装Sentinel
下载地址:https://github.com/alibaba/Sentinel/releases/tag/1.7.1
下载完成之后就可以出现sentinel-dashboard-1.7.1.jar安装包,到安装包的目录下运行 java -jar sentinel-dashboard-1.7.1.jar就可以运行成功。
在这里插入图片描述
浏览器输入localhost:8080即可访问sentinel控制面板
在这里插入图片描述

一、初始化监控

在监控之前需要开启 Nacos 和 Sentinel 两个服务

1、 值pom中添加坐标

		<!--SpringCloud ailibaba nacos -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--SpringCloud ailibaba sentinel-datasource-nacos 后续做持久化用到-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>
        <!--SpringCloud ailibaba 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>
        <!-- SpringBoot整合Web组件+actuator -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

2、 编写application.yml配置文件

server:
  port: 8401

spring:
  application:
    name: cloudalibaba-sentinel-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #Nacos服务注册中心地址
    sentinel:
      transport:
        dashboard: localhost:8080 #配置Sentinel dashboard地址
        port: 8719
#      datasource:
#        ds1:
#          nacos:
#            server-addr: localhost:8848
#            dataId: cloudalibaba-sentinel-service
#            groupId: DEFAULT_GROUP
#            data-type: json
#            rule-type: flow


#监控【图形化展现】
management:
  endpoints:
    web:
      exposure:
        include: '*'

feign:
  sentinel:
    enabled: true # 激活Sentinel对Feign的支持



3、 主启动类

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@EnableDiscoveryClient
public class AliSentinerMain8401 {

    public static void main(String[] args) {
        SpringApplication.run(AliSentinerMain8401.class, args);
    }

}

4、 编写控制器类

@RestController
public class FlowLimitController {

    @GetMapping("/testA")
    public String testA() {
        return "=================testA";
    }

    @GetMapping("/testB")
    public String testB() {
        return "=================testB";
    }

}

展示效果如下:
在这里插入图片描述
注意:Sentinel默认使用了懒加载,需要执行一次 localhost:8401/testA请求才会产生监控。

二、流控规则

基本介绍
在这里插入图片描述
在这里插入图片描述

1、 QPS直接失败
表示每秒只接收一次【/testA】请求,当超过的时候实现限流不允许访问。比如:每次银行只接受一个客户,其余的所有客户都在银行外面等待,直到前面一个客户办理完毕才轮到第二个。【拒之门外】
在这里插入图片描述

2、 线程数直接失败
表示允许接收所有的请求,但是只有一个线程进行消费。比如:银行的前台只有一个,但是有多个客户到了银行,银行接受所有的客户,但是只能每次对一个客户办理业务。【关门打狗】
在这里插入图片描述
3、关联
例如:当支付接口出现高并发快要宕机的时候,将不在允许下单接口的使用。
在这里插入图片描述
这里使用Postman实现多线程发送请求
在这里插入图片描述当多次调用 /testB 的时候,就限制 /testA 请求的访问
显示效果如下:
在这里插入图片描述

4、链路
表示只记录指定访问路径的流量,其它的路径一旦达到访问阈值就实现限流。
例如:只允许 /testB 的访问,一旦 /testA 达到阈值就产生限流。
在这里插入图片描述
5、 Warm Up(预热)

默认使用的是【快速失败】,一旦限流成功就会出现【Blocked by Sentinel (flow limiting)】。当QPS超过任意规则的阈值后,新的请求就会被立即拒绝,拒绝方式为抛出FlowException。这种方式适用于对系统处理能力确切已知的情况下,比如通过压测确定了系统的准确水位时。

预热表示:Warm Up(RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式,即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。例如:5S之前只允许访问10/3个请求,慢慢的5S之后就可以访问,就好比给服务器一个缓冲的时间来反应,避免服务器一下接收过多的请求从而导致服务器崩溃。应用场景:秒杀系统在开启的瞬间,会有好多的流量上来,很有可能把系统打死,预热的方式就是为了保护系统,慢慢地把流量放进来。源码: com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController
在这里插入图片描述
6、 排队等待
匀速排队(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)方式会严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法。
在这里插入图片描述
表示每隔3S才允许通过下一个访问的请求。

三、熔断降级

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

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

在这里插入图片描述表示200ms以内要处理完成,如果未完成,在未来的1S时间窗口内就会熔断降级,微服务不可用。

2、降级策略之异常比例
异常比例 (ERROR_RATIO):当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。
在这里插入图片描述
表示允许异常的比例为20%,异常之后再3S之内进行熔断降级,微服务不可用。

使用Postman进行发布的话,可以看到每秒发送的请求数>5,并且异常比例数>阈值就会出现熔断降级。
在这里插入图片描述
3、降级策略之异常数
异常数 (ERROR_COUNT):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。
在这里插入图片描述
表示当访文异常次数>3次,就会实现熔断降级,如果再61S内访问正常则结束熔断。

四、热点规则

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

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

热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效
在这里插入图片描述表示请求的第一个参数p1的QPS每秒超过1次马上进行降级处理

控制器代码如下:

	/**
     * 测试热点Key
     * @param p1
     * @param p2
     * @return
     */
    @GetMapping("/testHotKey")
    /*
    value:表示唯一ID
    blockHandler:表示违背了Sentinel的配置规则就使用兜底的方法
     */
    @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" + p1 + ";" + p2;
    }
    public String deal_testHotKey(String p1, String p2, BlockException e) {
        //sentinel的默认规则为:Blocked By Sentinel(flow limited)
        return "兜底方法";
    }

注意:一定要加上 @SentinelResource 注解,同时定义兜底方法【使用了自定义的兜底方法,而不是Bloed By Sentinel】
注意:@SentinelResource处理的是Sentinel控制台配置的违规情况,有blockHandler方法配置的兜底方法;但是RuntimeException中【int a = 10/0】这个是java运行时报出的运行时异常,@SentinelResource不管

显示效果如下:
在这里插入图片描述
例如存在这种情况:当参数的值为我们指定的数,那么我们进行特殊的限流使用。
在这里插入图片描述表示:平时我们根据QPS每秒接收一个请求,但是当参数的值=5的时候,就放大限流阈值为200【每秒接收200个请求】

五、@SentinelResource注解

1、blockHandler
blockHandler 对应处理 BlockException 的函数名称,可选项。
blockHandler 函数访问范围需要是 public,返回类型需要与原方法相匹配,
参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为 BlockException。

2、blockHandlerClass
blockHandler 函数默认需要和原方法在同一个类中,如果希望使用其他类的函数,
则需要指定 blockHandlerClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。

3、fallback
fallback 函数名称,可选项,用于在抛出异常的时候提供 fallback 处理逻辑。
fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。

4、fallbackClass
fallbackClass的应用和blockHandlerClass类似,fallback 函数默认需要和原方法在同一个类中。
若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。

5、defaultFallback(since 1.6.0)
如果没有配置defaultFallback方法,默认都会走到这里来。
默认的 fallback 函数名称,可选项,通常用于通用的 fallback 逻辑。
默认 fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。
若同时配置了 fallback 和 defaultFallback,则只有 fallback 会生效。

6、exceptionsToIgnore(since 1.6.0)
用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。

当我们未定义异常处理方法的时候,那么系统会使用默认的兜底方法;如果定义了兜底方法,则会采用兜底方法。为了避免耦合,采用将兜底方法和业务方法分离。

业务类方法如下:

@RestController
public class RateLimitController
{
    /**
     * 定义了兜底方法,采用handleException兜底方法
     * @return
     */
    @GetMapping("/byResource")
    @SentinelResource(value = "byResource",blockHandler = "handleException")
    public String byResource()
    {
        return "按资源名称限流测试OK";
        //return new CommonResult(200,"按资源名称限流测试OK", new Payment(2020,"serial001"));
    }
    public String handleException(BlockException exception)
    {
        return "服务不可用" + exception.getClass().getCanonicalName();
        //return new CommonResult(444,exception.getClass().getCanonicalName()+"\t 服务不可用");
    }


    /**
     * 未采用兜底方法,采用系统默认【Blocked By Sentinel】
     * @return
     */
    @GetMapping("/rateLimit/byUrl")
    @SentinelResource(value = "byUrl")
    public String byUrl()
    {
        return "按url限流测试OK";
        //return new CommonResult(200,"按url限流测试OK",new Payment(2020L,"serial002"));
    }


    /**
     * 避免耦合,将兜底方法进行重新定义在一个类中
     * @return
     */
    @GetMapping("/rateLimit/customerBlockHandler")
    @SentinelResource(value = "customerBlockHandler",
            blockHandlerClass = CustomerBlockHandler.class,
            blockHandler = "handlerException2")
    public String customerBlockHandler()
    {
        return "按客戶自定义处理兜底方法";
        //return new CommonResult(200,"按客戶自定义",new Payment(2020L,"serial003"));
    }

}

兜底方法类如下:

public class CustomerBlockHandler {

    public static String handlerException(BlockException e) {
        return "客户自定义GLOBAL-----------1";
    }
    
    public static String handlerException2(BlockException e) {
        return "客户自定义GLOBAL------------2";
    }

}

六、服务熔断

1、pom坐标导入

<!--SpringCloud ailibaba nacos -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--SpringCloud ailibaba sentinel -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>

2、application.yml配置文件

server:
  port: 83


spring:
  application:
    name: nacos-order-consumer
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    sentinel:
      transport:
        #配置Sentinel dashboard地址
        dashboard: localhost:8080
        #默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
        port: 8719

3、业务类

  • @SentinelResource(value = “fallback”) //没有配置出现的则是【Error Page】
  • @SentinelResource(value = “fallback”, fallback = “handlerFallback”) //配置[fallback]出现的则是【兜底定义的方法】
  • @SentinelResource(value = “fallback”, blockHandler = “blockHandler”) //配置[blockHandler]只负责sentinel控制台配置违规
  • @SentinelResource(value = “fallback”, fallback = “handlerFallback”, blockHandler = “blockHandler”) //同时生效
@GetMapping(value = "/consumer/nacos/{id}")
    //@SentinelResource(value = "fallback") //没有配置出现的则是【Error Page】
    //@SentinelResource(value = "fallback", fallback = "handlerFallback") //配置[fallback]出现的则是【兜底定义的方法】
    //@SentinelResource(value = "fallback", blockHandler = "blockHandler") //配置[blockHandler]只负责sentinel控制台配置违规
    @SentinelResource(value = "fallback", fallback = "handlerFallback", blockHandler = "blockHandler") //同时生效
    public String paymentInfo(@PathVariable("id") Long id)
    {
        String result = restTemplate.getForObject(serverURL+"/nacosAli/" + id, String.class);
        if (id == 2) {
            throw new IllegalArgumentException("非法参数异常");
        } else if (result == null) {
            throw new NullPointerException("空指针异常");
        }
        return result;
    }
    public String handlerFallback(@PathVariable  Long id,Throwable e) {
        return "兜底异常handlerFallback,exception内容  "+e.getMessage();
    }
    //本例是blockHandler
    public String blockHandler(@PathVariable  Long id, BlockException blockException) {
        return "blockHandler-sentinel限流,无此流水: blockException  "+blockException.getMessage();
    }

七、服务熔断【openFeign】

1、pom坐标

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

2、application.yml配置文件
注意:一定要加上下面的配置才会开启OpenFeign

feign:
  sentinel:
    enabled: true

全部配置如下:

server:
  port: 83


spring:
  application:
    name: nacos-order-consumer
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    sentinel:
      transport:
        #配置Sentinel dashboard地址
        dashboard: localhost:8080
        #默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
        port: 8719

#消费者将要去访问的微服务名称(注册成功进nacos的微服务提供者)
service-url:
  nacos-user-service: http://nacos-payment-provider
  

# 激活Sentinel对Feign的支持
feign:
  sentinel:
    enabled: true

3、主启动类上加上@EnableFeignClients
4、业务类

  • 带有@FeignClient注解的业务接口
  • fallback=PaymentFallbackService.class
@Component
//定义作为Feign组件的一个接口
@FeignClient(value = "nacos-payment-provider", fallback = PaymentFallbackService.class)
public interface PaymentService {
    
    /**
     * 通过ID查询
     * @param id
     * @return
     */
    @GetMapping("/nacosAli/{id}")
    String paymentSQL(@PathVariable("id") Integer id);
}

@Component
public class PaymentFallbackService implements PaymentService {
    @Override
    public String paymentSQL(Integer id) {
        return "服务降级";
    }
}
  • Controller
	@Resource
    private PaymentService paymentService;

    @GetMapping(value = "/consumer/paymentSQL/{id}")
    public String paymentSQL(@PathVariable("id") Integer id)
    {
        return paymentService.paymentSQL(id);
    }

当我们把服务消费者服务停止之后,就会实现熔断降级【运行兜底的方法】。
在这里插入图片描述

八、持久化规则

1、在sentinel的初始化的时候加入pom坐标

		<!--SpringCloud ailibaba sentinel-datasource-nacos 后续做持久化用到-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>

2、编写application.yml配置文件

datasource:
        ds1:
          nacos:
            server-addr: localhost:8848
            dataId: cloudalibaba-sentinel-service
            groupId: DEFAULT_GROUP
            data-type: json
            rule-type: flow

3、Nacos控制截面配置
在这里插入图片描述JSON属性代表的含义如下:
在这里插入图片描述可以在Sentinel控制界面看到已经配置了流控规则
在这里插入图片描述当我们关闭当前的服务,那么流控就会取消;但是下一次开启服务的时候,上一次存在的流控规则仍然存在,并且可以调用。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值