SpringCloud 第八期 Sentinel 熔断限流

sentinel可以作为监控平台使用,下载jar包运行

官网说明文档,有中文 https://gitee.com/rmlb/Sentinel/wikis/Home

sentinel下载地址 https://github.com/alibaba/Sentinel/releases/tag/1.7.0

下载完毕 java -jar sentinel-dashboard-1.7.0.jar 运行客户端

访问http://localhost:8080/ 端口 可以看到sentinel登录界面 默认账号密码都是sentinel

配置被监控的模块

被监控的模块引入sentinel依赖

这次我在9001 模块引入了依赖

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

<?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>cloud2021</artifactId>

        <groupId>com.liuxu</groupId>

        <version>1.0-SNAPSHOT</version>

    </parent>

    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-nacos-provider9001</artifactId>

    <dependencies>

    <dependency>

        <groupId>com.liuxu</groupId>

        <artifactId>cloud-commons</artifactId>

        <version>1.0-SNAPSHOT</version>

    </dependency>

    <!--springboot 必须有的-->

    <dependency>

        <groupId>org.springframework.boot</groupId>

        <artifactId>spring-boot-starter-web</artifactId>

    </dependency>

        <!--使用nacos-->

    <dependency>

        <groupId>org.springframework.boot</groupId>

        <artifactId>spring-boot-starter-actuator</artifactId>

    </dependency>

    <dependency>

        <groupId>com.alibaba.cloud</groupId>

        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>

    </dependency>

        <!--sentinel-->

        <dependency>

            <groupId>com.alibaba.cloud</groupId>

            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>

        </dependency>

    </dependencies>

</project>

yaml中添加sentinel监控相关内容

sentinel:

  transport: #设置sentinel dashboard 监控平台地址

    dashboard: localhost:8080

    port: 8719 # 指定应用与Sentinel控制台交互的端口,应用本地会起一个该端口占用的HttpServer

    #默认8719 端口 假如被占用则从8719+1开始依次向后扫描 直到找到未被占用的端口

server:

  port: 9001

spring:

  application:

    name: nacos-payment-provider

  cloud:

  nacos:

    discovery:

      server-addr: localhost:8848

  sentinel:

    transport: #设置sentinel dashboard 监控平台地址

      dashboard: localhost:8080

      port: 8719 # 指定应用与Sentinel控制台交互的端口,应用本地会起一个该端口占用的HttpServer

      #默认8719 端口 假如被占用则从8719+1开始依次向后扫描 直到找到未被占用的端口

management:

  endpoints:

    web:

      exposure:

        include: '*'

启动注册中心nacos,启动项目9001

登录sentinel

访问9001端口

http://localhost:9001/echo/1

刷新sentinal监控界面, 可以看到sentinal监控了9001 模块

sentinel 流控规则 Qps和线程数流控展示

首先在9001 添加SentinelController 类

package liuxu.controller;

import org.springframework.beans.factory.annotation.Value;

import org.springframework.web.bind.annotation.*;

/**

* @author liuxu

* @date 2021/11/6 17:30

*/

@RestController

@RequestMapping("/myFlow")

public class SentinelController {

    @Value("${server.port}")

    private String serverPort;

    @GetMapping(value = "/testA")

    public String sentinelTestA() {

        return" hello word端口是:"+serverPort;

    }

    @RequestMapping(value = "/testB")

    public String sentinelTestB(@RequestParam("parm") String string) {

        return string+" hello word端口是:"+serverPort;

    }

}

在NacosController 添加testA testB接口

package liuxu.controller;

import org.springframework.beans.factory.annotation.Value;

import org.springframework.web.bind.annotation.*;

import java.sql.Time;

import java.util.concurrent.TimeUnit;

/**

* @author liuxu

* @date 2020/7/13 16:51

*/

@RestController

public class NacosController

{

    @Value("${server.port}")

    private String serverPort;

        @GetMapping(value = "/echo/{String}")

        public String echo(@PathVariable ("String") String string) {

            return string+" hello word端口是:"+serverPort;

        }

    @GetMapping(value = "/testA")

    public String sentinelTestA() {

        return" hello word端口是:"+serverPort;

    }

    @RequestMapping(value = "/testB")

    public String sentinelTestB(@RequestParam("parm") String string) {

        try {

            TimeUnit.SECONDS.sleep(3L);

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

        return string+" hello word端口是:"+serverPort;

    }

}

重启9001 发现监控到的只有 http://localhost:9001/testA  http://localhost:9001/testA这两个请求

http://localhost:9001/myFlow/testA http://localhost:9001/myFlow/testB 是监控不到的

原因是sentinel简单的接口可以直接以路径名作为资源名进行监控,而复杂的接口需要添加

@SentinelResource注解,之后会详细介绍

配置流控规则

testA 配置为QPS 规则 ,testB配置为线程数

点击资源后面"流控+"可以配置流控规则

访问 http://localhost:9001/testA  连续快速点击两次以上就会出现流控异常

访问 http://localhost:9001/testB 连续快速点击两次以上也会出现流控异常

用jemeter 压测可以看出两种配置方式的区别

线程组均设为单线程内的10个请求

testA请求配置

testB请求配置

发送请求后你会发现testA只有一个会成功

而testB全成功,原因是QPS 会把请求挡在服务之外,只要超过阈值就会失败

而线程数会将请求全部放到服务中,超过线程数才会失败

将请求配置为2个线程就会失败。

QBS会将请求挡在服务外,消耗小

线程数流控对于服务消耗大

流控模式有直接 关联(关联资源名,a关联b,b达到流控峰值,a被限流) 链路(关联入口资源)三种方式

只有QBS阈值类型有流控效果,

流控效果有 快速失败(默认)

Warm up(将qbs阈值初3取整进行预热 ,超预热时间才能达到qps阈值流控)

排队等待 (超过阈值不会失败,会进行排队等待)三种效果。

sentinel流控介绍完毕 可自行验证

sentinel降级规则

降级规则分 RT (超时) 异常比例 异常数

在簇点链路新增降级规则 默认1s 时间窗口期为 5,则会有如下效果

5s时间窗口期内请求达到5个(必要条件) 且有 5个请求中有响应时间超过1s的 就会触发降级规则

用jemter压测发现

10个请求中只有前5个成功,第六个开始出现熔断

同样异常比例配置 就会有如下效果 时间窗口期当请求超出5个 且异常比例超出配置异常比例就会熔断,触发降级,熔断后时间窗口期结束 就会关闭降级

异常数配置就是 是将窗口期内请求超出5个 且异常数达到设置的异常个数就会熔断,触发降级, 熔断后时间窗口期结束 就会关闭降级

下面验证

在controller中加入以下代码故意制造异常

@RequestMapping(value = "/testC")

    public String sentinelTestB() {

        int i=10/0;

        return "testC";

    }

重启9001,并配置testC的降级规则

此刻如果每秒访问一次 http://localhost:9001/testC并不会触发降级

而是直接抛出异常

如果用jemeter压力测试,5秒发5次以上请求,就会触发降级

上面提到的降级策略中的达到5个请求这个必要条件,在sentinel官网可以看到,是一个必要的统计起点,只有在请求持续达到5个才会触发降级规则配置的策略。

以上限流调方法返回sentinel默认提示,Blocked by Sentinel (flow limiting)

用@SentinelResource可以配置自定义的热点key和回调方法,类似于@HystrixCommand

修改SentinelController类

重启9001访问 http://localhost:9001/myFlow/testB?parm=11

http://localhost:9001/myFlow/testA?p1="aa"

package liuxu.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;

import com.alibaba.csp.sentinel.slots.block.BlockException;

import com.alibaba.csp.sentinel.slots.block.flow.FlowException;

import org.springframework.beans.factory.annotation.Value;

import org.springframework.web.bind.annotation.*;

/**

* @author liuxu

* @date 2021/11/6 17:30

*/

@RestController

@RequestMapping("/myFlow")

public class SentinelController {

    @Value("${server.port}")

    private String serverPort;

    @SentinelResource(value = "testHostKey",blockHandler = "deal_testHostKey")

    @GetMapping(value = "/testA")

    @ResponseBody

    public String sentinelTestA(@RequestParam(value = "p1",required = false)String p1,

                                @RequestParam(value = "p2",required = false)String p2) {

        return "p1==>"+p1+"p2==>"+p2;

    }

    @SentinelResource(value = "testB",blockHandler = "deal_testB")

    @RequestMapping(value = "/testB")

    @ResponseBody

    public String sentinelTestB(@RequestParam("parm") String string) {

        return string+" hello word端口是:"+serverPort;

    }

public String deal_testHostKey(@RequestParam(value = "p1",required = false)String p1,

                              @RequestParam(value = "p2",required = false)String p2,BlockException e){

        System.out.println(e);

        System.out.println("降级原因是:"+e.getMessage());

        return "热点hostKey触发降级";

}

    public String deal_testB(@RequestParam("parm") String string, BlockException e){

        return "testB热点hostKey触发降级"+e;

    }

}

在sentinel客户端刷新可以看到 @SentinelResource 中value值为资源名的资源

分别给两个接口配置限流规则,和热点限流规则

此时 http://localhost:9001/myFlow/testB?parm=11被限流,超过每秒1次会返回blockHandler指定方法返回值

http://localhost:9001/myFlow/testA?p1="aa"参数0也就是第一个参数被限流,访问超过每秒1次会被限流

http://localhost:9001/myFlow/testA?p2="aa"第二个参数没有被限流

可以超过每秒1次

此时上述controller代码存在逻辑和限流处理方法混杂的现象

我们可以抽取公共限流处理类Coustomer

package liuxu.controller.handler;

import com.alibaba.csp.sentinel.slots.block.BlockException;

import org.springframework.web.bind.annotation.RequestParam;

/**

* @author liuxu

* @date 2021/11/7 17:49

*/

public class CoustomerBlockHandler {

    public static String deal_testHostKey(@RequestParam(value = "p1",required = false)String p1,

                                  @RequestParam(value = "p2",required = false)String p2, BlockException e){

        System.out.println(e);

        System.out.println("降级原因是:"+e.getMessage());

        return "热点hostKey触发降级";

    }

    public static String deal_testB(@RequestParam("parm") String string, BlockException e){

        return "testB热点hostKey触发降级"+e;

    }

}

controller改造

package liuxu.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;

import com.alibaba.csp.sentinel.slots.block.BlockException;

import com.alibaba.csp.sentinel.slots.block.flow.FlowException;

import liuxu.controller.handler.CoustomerBlockHandler;

import org.springframework.beans.factory.annotation.Value;

import org.springframework.web.bind.annotation.*;

/**

* @author liuxu

* @date 2021/11/6 17:30

*/

@RestController

@RequestMapping("/myFlow")

public class SentinelController {

    @Value("${server.port}")

    private String serverPort;

    @SentinelResource(value = "testHostKey",blockHandlerClass = CoustomerBlockHandler.class,blockHandler = "deal_testHostKey")

    @GetMapping(value = "/testA")

    @ResponseBody

    public String sentinelTestA(@RequestParam(value = "p1",required = false)String p1,

                                @RequestParam(value = "p2",required = false)String p2) {

        return "p1==>"+p1+"p2==>"+p2;

    }

    @SentinelResource(value = "testB",blockHandlerClass = CoustomerBlockHandler.class,blockHandler = "deal_testB")

    @RequestMapping(value = "/testB")

    @ResponseBody

    public String sentinelTestB(@RequestParam("parm") String string) {

        return string+" hello word端口是:"+serverPort;

    }

}

此时限流规则依然生效

@SentinelResource 使用需要定下面参数

value 资源名

blockHandlerClass 限流处理的资源类

blockHandler 限流处理的方法名

限流处理的方法必须是public 方法 如果放在blockHandlerClass 里面需要为静态的

而且参数返回值必须和被限流的方法相同 ,参数列表需要被限流方法的参数列表的基础上添加

BlockException 用于捕获限流规则异常

和限流方法类似 ,我们添加一个有异常的接口,用于验证异常熔断

controller层添加testC testD接口

package liuxu.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;

import com.alibaba.csp.sentinel.slots.block.BlockException;

import com.alibaba.csp.sentinel.slots.block.flow.FlowException;

import liuxu.controller.handler.CoustomerBlockHandler;

import liuxu.controller.handler.CoustomerFallBackHandler;

import org.springframework.beans.factory.annotation.Value;

import org.springframework.web.bind.annotation.*;

/**

* @author liuxu

* @date 2021/11/6 17:30

*/

@RestController

@RequestMapping("/myFlow")

public class SentinelController {

    @Value("${server.port}")

    private String serverPort;

    @SentinelResource(value = "testHostKey",blockHandlerClass = CoustomerBlockHandler.class,blockHandler = "deal_testHostKey")

    @GetMapping(value = "/testA")

    @ResponseBody

    public String sentinelTestA(@RequestParam(value = "p1",required = false)String p1,

                                @RequestParam(value = "p2",required = false)String p2) {

        return "p1==>"+p1+"p2==>"+p2;

    }

    @SentinelResource(value = "testB",blockHandlerClass = CoustomerBlockHandler.class,blockHandler = "deal_testB")

    @RequestMapping(value = "/testB")

    @ResponseBody

    public String sentinelTestB(@RequestParam("parm") String string) {

        return string+" hello word端口是:"+serverPort;

    }

    @SentinelResource(value = "testC",fallbackClass = CoustomerFallBackHandler.class,fallback = "testCFallBack")

    @RequestMapping(value = "/testC")

    @ResponseBody

    public String sentinelError(@RequestParam("parm") String string) {

        int i=10/0;

        return string+" hello word端口是:"+serverPort;

    }

    @SentinelResource(value = "testD",fallbackClass = CoustomerFallBackHandler.class,fallback = "testDFallBack")

    @RequestMapping(value = "/testD")

    @ResponseBody

    public String sentinelError01(@RequestParam("parm") String string) {

        int i=10/0;

        return string+" hello word端口是:"+serverPort;

    }

}

异常处理类CoustomerFallBackHandler

package liuxu.controller.handler;

import org.springframework.web.bind.annotation.RequestParam;

/**

* @author liuxu

* @date 2021/11/7 18:13

*/

public class CoustomerFallBackHandler {

    public static String  testCFallBack(@RequestParam("parm") String string,Throwable throwable){

        return "testC"+"入参是"+string+"异常是"+throwable;

    }

    public static String  testDFallBack(@RequestParam("parm") String string,Throwable throwable){

        return "testD"+"入参是"+string+"异常是"+throwable;

    }

}

配置降级规则

访问http://localhost:9001/myFlow/testD?parm=11触发熔断回调

如果在@SentinelResource 添加 exceptionsToIgnore = ArithmeticException.class,

就会忽略该异常, 该异常不会触发降级。

sentinel 有关熔断降级介绍完毕

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,686评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,668评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,160评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,736评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,847评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,043评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,129评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,872评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,318评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,645评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,777评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,861评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,589评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,687评论 2 351

推荐阅读更多精彩内容