Sentinel服务限流、降级、热点规则

Sentinel服务限流、降级、热点规则

git地址: https://github.com/alibaba/Sentinel 

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

   sentinel实际和hystrix的作用一样,实现服务降级、熔断等。但是hystrix的不足之处大概有:1.需要程序员手工搭建监控平台;2.没有一套web界面可以给我们进行细粒度化的配置。Sentinel也是实现流量控制、速率控制、服务熔断、服务降级。Sentinel有的优点如下:1.单独的组件,可以独立出来。2.直接界面化的细粒度统一配置。

1.下载安装

1.下载jar包

 到git https://github.com/alibaba/Sentinel/releases  下载即可。例如我下载的是:

sentinel-dashboard-1.8.0.jar

2. 启动

直接以jar包的方式运行即可。

java -jar ./sentinel-dashboard-1.8.0.jar

3.访问即可

 默认的端口是8080,启动后访问,登录:  sentinel/sentinel

 2. 新建项目使用sentinel初始化监控

  新建一个项目,注册中心为nacos,端口8848; 熔断流量监控使用sentinel,端口8080.

1.新建项目cloudalibaba-sentinel-service8401

2.修改pom

复制代码

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>cloud</artifactId>
        <groupId>cn.qz.cloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloudalibaba-sentinel-service8401</artifactId>

    <dependencies>
        <!--引入自己抽取的工具包-->
        <dependency>
            <groupId>cn.qz.cloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!--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>
        <!--日常通用jar包配置-->
        <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>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

    </dependencies>

</project>

复制代码

3.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地址
        # 默认就是8719端口,如果占用会依次+1开始扫描
        port: 8719

management:
  endpoints:
    web:
      exposure:
        include: '*'

复制代码

4.主启动类

复制代码

package cn.qz.cloud.alibaba;

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

/**
 * @Author: qlq
 * @Description
 * @Date: 22:06 2020/11/25
 */
@EnableDiscoveryClient
@SpringBootApplication
public class MainApp8401 {

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

复制代码

5.测试Controller

复制代码

package cn.qz.cloud.alibaba.controller;

import cn.qz.cloud.utils.JSONResultUtil;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @Author: qlq
 * @Description
 * @Date: 22:07 2020/11/25
 */
@RestController
public class FlowLimitController {

    @GetMapping("/testA")
    public JSONResultUtil<String> testA() {
        return JSONResultUtil.successWithData("testA");
    }

    @GetMapping("/testB")
    public JSONResultUtil<String> testB() {
        return JSONResultUtil.successWithData("testB");
    }
}

复制代码

6.启动后到nacos查看服务列表

 7. 访问sentinel

需要注意sentinel采用的是懒加载,如果直接启动服务没有访问,sentinel是不会拦截到请求的。所以需要访问几次服务然后到sentinel中查看。sentinel控制台如下:

3. sentinel流控

1.实时监控

 可以实时的查看每个请求的访问QPS情况。

2.簇点链路

  和上面1差不多。展示最近的访问情况。

3.流控规则

新增流控规则的时候,界面如下:

 概念性问题:

  • 资源名:唯一名称,默认请求路径
  • 针对来源:Sentinel可以针对调用者进行限流,填写微服务名,默认default(不区分来源)
  • 阈值类型/单机阈值

(1)QPS(每秒钟的请求数):当掉该api达到阈值的时候,进行限流

(2)线程数: 当调用该API的线程数达到阈值时,进行限流

  • 是否集群:不需要集群
  • 流控模式

(1)直接:直接限流

(2)关联:当关联的资源达到阈值时,限流自己

(3)链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就进行限流)【api级别的针对来源】

  • 流控效果

(1)快速失败:直接失败,抛异常

(2)Warm up:根据code Factor(冷加载印子,默认3)的值,从阈值/cedeFactor,经过预热时长,才达到预设的QPS

(3)排队等待: 匀速排队,让请求匀速的通过,阈值类型必须设置QPS。否则无效。

4. 流控模式使用

1. QPS 快速失败

多次访问查看结果如下:

 2. 线程数直接失败

 这个是接收请求,但是当处理的线程数超过1的时候报上面的【Blocked by Sentinel (flow limiting)】。和上面不同的是这个允许请求进去,上面是达到阈值就不让请求进去。

3.关联流控

  关联流控就是关联的资源达到阈值,限流自己。比如如下:当B超过QPS为1之后,A限流:

 测试方法:

(1) 使用postman或者jmeter并发访问testB,如下:加到collections中,然后没300ms访问一次,访问30次

(2)访问A发现A阻塞

 4. 链路流控规则

(1)查看簇点链路,/testA的资源入口是sentinel_web_servlet_context

 (2) 对A进行链路流控

 (3)频繁访问会报Blocked by Sentinel (flow limiting)

5. 流控效果

 1.直接快速失败

默认的就是快速失败,抛出阻塞信息。实现类是 com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController

2.warm up预热: com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController.WarmUpController

根据code Factor(冷加载印子,默认3)的值,从阈值/cedeFactor,经过预热时长,才达到预设的QPS。比如下面规则表示:初始的时候阈值是10/3 = 3 ;5s的预热时间达到10。

 这种模式的应用场景是秒杀系统,开启瞬间会有很多流量上来,很有可能把系统打死,预热就是为了保护系统,让流量缓慢的进来。

3. 排队等待

匀速排队,让请求匀速的通过。这种很好理解,就是每秒钟放行多少个请求。如下:每秒钟处理1个,超过的话进行排队;排队时长超过2s报阻塞错误。源码是com.alibaba.csp.sentinel.slots.block.flow.controller.RateLimiterController。采用的算法是令牌桶算法。

 4.sentinel熔断降级

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

提供以下几种熔断策略:

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

1. 慢调用比例模式

满足两个条件会触发熔断:

1》单位统计时长请求数大于设置的最小值。下面是每秒钟5个。

2》慢请求达到设置的比例。

 

 (1)新增方法

    @GetMapping("/testD")
    public JSONResultUtil<String> testD() throws InterruptedException {
        TimeUnit.SECONDS.sleep(1);
        return JSONResultUtil.successWithData("testD");
    }

 

 

(2)jmeter 以每秒钟10次请求访问

(3)curl访问

$ curl http://localhost:8401/testD
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    35    0    35    0     0    249      0 --:--:-- --:--:-- --:--:--   280Blocked by Sentinel (flow limiting)

 

(4)上面jmeter每秒钟10次请求大于最小值5;每个请求处理时长超过200ms,满足第二个条件,因此触发降级。

 2. 异常比例模式

如下:这个也是需要两个条件。

1》每秒钟请求超过五个

2》异常比例超过50%触发熔断

 (1)新增方法

    @GetMapping("/testE")
    public JSONResultUtil<String> testE() {
        int i = 1 / 0;
        return JSONResultUtil.successWithData("testE");
    }

 

(2)jmeter每秒钟十个访问

(3)curl访问:发现触发降级

$ curl http://localhost:8401/testE
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    35    0    35    0     0    140      0 --:--:-- --:--:-- --:--:--   149Blocked by Sentinel (flow limiting)

 

 (4)停掉jmeter再次curl,直接爆程序错误。也就是没触发sentinel熔断

$ curl http://localhost:8401/testE
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0{"timestamp":"2020-12-01T14:41:15.196+0000","status":500,"error":"Internal Server Error","message":"/ by zero","trace":"java.lang.ArithmeticException: / by zero\r\n\tat cn.qz.cloud.alibaba.controller.FlowLimitController.testE(FlowLimitController.java:43)\r\n\tat sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\r\n\tat sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\r\n\tat sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\r\n\tat java.lang.reflect.Method.invoke(Method.java:498)\r\n\tat org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)\r\n\tat org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)\r\n\tat org.springframework.web.servl

 

3.异常数模式

和上面的区别是根据异常数判断是否需要进行熔断。

 

 5. 热点规则

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

  这个和hystrix挺像的。@SentinelResource代替@HystrixCommand。

1.新增方法

复制代码

    @GetMapping("/testHotKey")
    @SentinelResource(value = "testHotKey", blockHandler = "deal_testHotKey")
    public JSONResultUtil<String> testHotKey(@RequestParam(value = "p1", required = false) String p1,
                                             @RequestParam(value = "p2", required = false) String p2) {
        return JSONResultUtil.successWithData("testHotKey");
    }

    public JSONResultUtil<String> deal_testHotKey(String p1, String p2, BlockException exception) {
        return JSONResultUtil.successWithData("deal_testHotKey");  //sentinel系统默认的提示:Blocked by Sentinel (flow limiting)
    }

复制代码

 

解释:

@SentinelResource注解的value是便于唯一标识,在后面sentinel限流配置的时候可以使用 /testHotKey ,也可以使用 testHotKey唯一标识

blockHandler  类似于hystrixCommand注解的兜底方法。

2.sentinel增加如下配置:

 上面的配置规则是:

(1)如果 testHotKey 方法不带p1 参数不进行限流

(2)如果待了p1参数且值不为"1",阈值为2;如果值为"1", 阈值可达到20。 (这里需要注意例外项的参数类型只支持8种基本数据类型和String类型)

(3)p2参数不参数限流

 6. 系统规则

参考:https://github.com/alibaba/Sentinel/wiki/%E7%B3%BB%E7%BB%9F%E8%87%AA%E9%80%82%E5%BA%94%E9%99%90%E6%B5%81

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

  • Load 自适应(仅对 Linux/Unix-like 机器生效):系统的 load1 作为启发指标,进行自适应系统保护。当系统 load1 超过设定的启发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护(BBR 阶段)。系统容量由系统的 maxQps * minRt 估算得出。设定参考值一般是 CPU cores * 2.5
  • CPU usage(1.5.0+ 版本):当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0),比较灵敏。
  • 平均 RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
  • 并发线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
  • 入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。

可以理解为系统规则是全局的限流配置,可以针对服务的全局QPS、机器的CPU等参数进行限流。

7.@SentinelResource

  这个注解类似于HystrixCommand注解,可以用于方法的降级处理。

1.常规用法

复制代码

package cn.qz.cloud.alibaba.controller;

import cn.qz.cloud.utils.JSONResultUtil;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class RateLimitController {

    @GetMapping("/byResource")
    @SentinelResource(value = "byResource", blockHandler = "handleException")
    public JSONResultUtil<String> byResource() {
        return JSONResultUtil.successWithData("byResource");
    }

    public JSONResultUtil<String> handleException(BlockException exception) {
        return JSONResultUtil.successWithData("handleException");
    }

    @GetMapping("/rateLimit/byUrl")
    @SentinelResource(value = "byUrl")
    public JSONResultUtil<String> byUrl() {
        return JSONResultUtil.successWithData("byUrl");
    }
}

复制代码

(1)新建两条限流规则:

第一条: 资源名是@SentinelResource 的value属性

 第二条: 资源名是URL,等价于上面的@SentinelResource的value属性

 (2)测试:

1》 byResource 超出会走自己指定的方法

 2》byUrl 超出后走默认的限流方法

 (3)存在的问题:

1》系统默认限流,满足不了业务要求。

2》自定义的处理方法和业务代码耦合在一起,不直观。

3》每个方法都添加一个兜底的,代码膨胀加剧。

4》全局统一的处理方法没有体现。

 2. 自定义异常处理器

(1)新建异常处理器

复制代码

package cn.qz.cloud.alibaba.myhandler;

import cn.qz.cloud.utils.JSONResultUtil;
import com.alibaba.csp.sentinel.slots.block.BlockException;

public class CustomerBlockHandler {

    public static JSONResultUtil<Object> handlerException(BlockException exception) {
        return JSONResultUtil.errorWithMsg("-1", "error");
    }

    public static JSONResultUtil<Object> handlerException2(BlockException exception) {
        return JSONResultUtil.errorWithMsg("-1", "error2");
    }
}

复制代码

(2)Controller使用@SentinelResource注解指明异常处理器以及方法

复制代码

    @GetMapping("/rateLimit/cusError")
    @SentinelResource(value = "cusError", blockHandlerClass = CustomerBlockHandler.class, blockHandler = "handlerException2")
    public JSONResultUtil<String> cusError() {
        return JSONResultUtil.successWithData("cusError");
    }

复制代码

(3)新建流控

 (3) 测试超出限制

8.@SentnelResource 补充

主要属性 fallback和blockHandler。fallback管运行异常,blockHandler管配置违规,包括流量超限等。IllegalArgumentException 可以指定忽略的异常。例如:

复制代码

package cn.qz.cloud.alibaba.controller;

import cn.qz.cloud.bean.Payment;
import cn.qz.cloud.utils.JSONResultUtil;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

@RestController
@Slf4j
public class CircleBreakerController {
    public static final String SERVICE_URL = "http://nacos-payment-provider";

    @Resource
    private RestTemplate restTemplate;

    @RequestMapping("/consumer/fallback/{id}")
    //@SentinelResource(value = "fallback") //没有配置
    //@SentinelResource(value = "fallback",fallback = "handlerFallback") //fallback只负责业务异常
    //@SentinelResource(value = "fallback",blockHandler = "blockHandler") //blockHandler只负责sentinel控制台配置违规
    @SentinelResource(value = "fallback", fallback = "handlerFallback", blockHandler = "blockHandler",
            exceptionsToIgnore = {IllegalArgumentException.class})
    public JSONResultUtil<Payment> fallback(@PathVariable Long id) {
        JSONResultUtil<Payment> result = restTemplate.getForObject(SERVICE_URL + "/list/" + id, JSONResultUtil.class, id);
        if (id == 4) {
            throw new IllegalArgumentException("IllegalArgumentException,非法参数异常....");
        } else if (result.getData() == null) {
            throw new NullPointerException("NullPointerException,该ID没有对应记录,空指针异常");
        }

        return result;
    }

    //本例是fallback
    public JSONResultUtil<Payment> handlerFallback(@PathVariable Long id, Throwable e) {
        JSONResultUtil<Payment> objectJSONResultUtil = JSONResultUtil.successWithData(null);
        objectJSONResultUtil.setMsg("handlerFallback: " + e);
        return objectJSONResultUtil;
    }

    //本例是blockHandler
    public JSONResultUtil<Payment> blockHandler(@PathVariable Long id, BlockException blockException) {
        JSONResultUtil<Payment> objectJSONResultUtil = JSONResultUtil.successWithData(null);
        objectJSONResultUtil.setMsg("blockHandler : " + blockException);
        return objectJSONResultUtil;
    }
}

复制代码

nacos-payment-provider服务只有1、2、3 ID返回数据。测试:

(1)ID为4抛出非法参数异常,这种异常exceptionsToIgnore 忽略兜底

 (2)ID为4以后的走fallback

9.sentinel持久化 

  持久化需要借助nacos,就相当于配置信息存到nacos,然后后nacos读取配置。

1.应用的yml增加如下配置:

复制代码

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
        datasource:
          ds1:
            nacos:
              server-addr: localhost:8848
              dataId: nacos-order-consumer
              groupId: DEFAULT_GROUP
              data-type: json
              rule-type: flow

复制代码

2.到nacos新建配置

这里需要注意,data Id 和 上面应用中配置的一样。

 

 内容如下:

复制代码

[
    {
        "resource": "/consumer/fallback/2",
        "limitApp": "default",
        "grade": 1,
        "count": 5,
        "strategy": 0,
        "controlBehavior": 0,
        "clusterMode": false
    }
]

复制代码

解释:

resource:资源名称
limitApp:来源应用
grade:阈值类型,0表示线程数,1表示QPS
count:单击阈值
strategy:流控模式,0表示直接,1表示关联,2表示链路
controlBehavior:流控效果,0表示快速失败,1表示Warm up,2表示排队等待

 

【当你用心写完每一篇博客之后,你会发现它比你用代码实现功能更有成就感!】

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值