SpringCloud Alibaba Sentinel实现熔断与限流(十二)

一、Sentinel概述

1.1 官网

https://github.com/alibaba/Sentinel

中文

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

1.2 Sentinel 是什么

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

Sentinel 具有以下特征:

  • 丰富的应用场景:Sentinel 承接了阿里巴巴近 10
    年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
  • 完备的实时监控:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500
    台以下规模的集群的汇总运行情况。
  • 广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC
    的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。
  • 完善的 SPI 扩展点:Sentinel 提供简单易用、完善的 SPI
    扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。

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

1.3 去哪下

https://github.com/alibaba/Sentinel/releases

在这里插入图片描述

1.4 能干嘛

在这里插入图片描述

1.5 怎么玩

https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html#_spring_cloud_alibaba_sentinel

服务使用中的各种问题

服务雪崩
服务降级
服务熔断
服务限流

二、安装Sentinel控制台

2.1 Sentinel组件由两部分组成

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

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

后台
前台8080

2.2 安装步骤

2.2.1 下载

https://github.com/alibaba/Sentinel/releases

下载到本地sentinel-dashboard-1.7.0.jar
在这里插入图片描述

2.2.2 运行命令

前提

Java8环境OK

8080端口不能被占用

命令

java -jar sentinel-dashboard-1.7.0.jar

在这里插入图片描述

访问sentinel管理界面

http://localhost:8080

登陆账号密码均为sentinel
在这里插入图片描述
在这里插入图片描述

三、初始化演示工程

3.1 启动Nacos8848成功

在这里插入图片描述
http://localhost:8848/nacos/#/login
在这里插入图片描述

3.2 新建Module

cloudalibaba-sentinel-service8401
在这里插入图片描述

3.2.1 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>cloud2020</artifactId>
        <groupId>com.atguigu.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
 
    <artifactId>cloudalibaba-sentinel-service8401</artifactId>
 
    <dependencies>
        <dependency>
            <groupId>com.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
 
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
 
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>
 
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
 
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
 
        <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>
      
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>4.6.3</version>
        </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.2.2 YML

server:
  port: 8401
 
spring:
  application:
    name: cloudalibaba-sentinel-service
  cloud:
    nacos:
      discovery:
#        Nacos服务注册中心地址
        server-addr: localhost:8848
    sentinel:
      transport:
#        配置Sentinel dashboard地址
        dashboard: localhost:8080
        port: 8719  #默认8719,假如被占用了会自动从8719开始依次+1扫描。直至找到未被占用的端口
 
management:
  endpoints:
    web:
      exposure:
        include: '*'
 
 
 
 

3.2.3 主启动

package com.atguigu.springcloud.alibaba;
 
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
 
 
@EnableDiscoveryClient
@SpringBootApplication
public class MainApp8401
{
    public static void main(String[] args) {
        SpringApplication.run(MainApp8401.class, args);
    }
}
 
 

3.2.4 业务类

package com.atguigu.springcloud.alibaba.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";
    }
}
 
 

3.3 启动Sentinel8080

java -jar sentinel-dashboard-1.7.0
在这里插入图片描述
http://localhost:8080/#/dashboard

3.4 启动8401微服务查看sentinel控制台

启动后,访问sentinel控制台,空空如也,啥都没有

3.4.1 Sentinel采用的懒加载说明

执行一次访问即可

http://localhost:8401/testA

http://localhost:8401/testB

效果
在这里插入图片描述

3.4.2 结论

sentinel8080正在监控微服务8401

四、流控规则

4.1 基本介绍

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

4.2 流控模式

4.2.1 直接(默认)

直接->快速失败

系统默认
在这里插入图片描述
在这里插入图片描述
测试

1s一次没毛病
在这里插入图片描述
狂点,限流
在这里插入图片描述
思考

直接调用默认报错信息,技术方面OK,但是,是否应该有我们自己的后续处理?

类似有一个fallback的兜底方法。

4.2.2 关联

是什么

  • 当关联的资源达到阈值时,就限流自己
  • 当与A关联的资源B达到阈值后,就限流自己
  • B惹事,A挂了
    在这里插入图片描述
    用postman模拟并发密集访问testB
    在这里插入图片描述
    访问testB成功

在这里插入图片描述
postman里新建多线程集合组
在这里插入图片描述
将访问地址添加进新线程组
在这里插入图片描述
Run运行后发现testA挂了,大批量线程高并发访问B,导致A失效了

点击访问http://localhost:8401/testA

结果

Blocked by Sentinel (flow limiting)

4.2.3 链路

多个请求调用了同一个微服务

4.2 流控效果

4.2.1 直接->快速失败(默认的流控处理)

直接失败,抛出异常

Blocked by Sentinel(flow limiting)

源码

com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController

4.2.2 预热

说明

公式:阈值除以coldFactor(默认值为3),经过预热时长后才会达到阈值

官网
在这里插入图片描述
在这里插入图片描述
默认coldFactor为3,即请求QPS从threshold/3开始,经预热时长逐渐升至设定的QPS阈值。

限流冷启动

https://github.com/alibaba/Sentinel/wiki/%E9%99%90%E6%B5%81—%E5%86%B7%E5%90%AF%E5%8A%A8

源码
在这里插入图片描述
Warmup配置
在这里插入图片描述
多次点击http://localhost:8401/testB

刚开始不行,后续慢慢OK

应用场景

如:秒杀系统在开启的瞬间,会有很多流量上来,很有可能把系统打死,预热方式就是为了保护系统,可慢慢的把流量放进来,慢慢的把阈值增长到设置的阈值。

4.2.3 排队等待

匀速排队,阈值必须设置为QPS
在这里插入图片描述
在这里插入图片描述
源码

com.alibaba.csp.sentinel.slots.block.flow.controller.RateLimiterController

测试
在这里插入图片描述

五、降级规则

5.1 基本介绍

Sentinel熔断降级会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联错误。

当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断(默认行为是抛出DegradeException)。
在这里插入图片描述

在这里插入图片描述
Sentinel的断路器是没有半开状态的

半开的状态系统自动去检测是否请求有异常,没有异常就关闭断路器恢复使用,有异常则继续打开断路器不可用。具体可以参考Hystrix.
在这里插入图片描述

5.2 降级策略实战

5.2.1 RT

是什么

每秒查询率(QPS,Queries-per-second)是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准。
在这里插入图片描述
在这里插入图片描述
测试

代码

package com.atguigu.springcloud.alibaba.controller;
 
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
 
import java.util.concurrent.TimeUnit;
 
@RestController
@Slf4j
public class FlowLimitController {
    @GetMapping("/testA")
    public String testA() {
        //暂停毫秒
        try {
            TimeUnit.MILLISECONDS.sleep(800);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "------testA";
    }
 
    @GetMapping("/testB")
    public String testB() {
        log.info(Thread.currentThread().getName()+"\t"+"testB");
        return "------testB";
    }
 
    @GetMapping("/testD")
    public String testD() {
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("testD 测试RT");
        return "------testD";
    }
}
 
 

配置
在这里插入图片描述

在这里插入图片描述
jmeter压测
在这里插入图片描述
按照上述配置,永远一秒钟打进来10个线程(大于5个了),调用testD,我们希望200毫秒处理完本次任务,如果超过200毫秒还没处理完,在未来1秒钟的时间窗口内,断路器打开(保险丝跳闸)微服务不可用,保险丝跳闸断电了。后续我停止jmeter,没有这么大的访问量了,断路器关闭(保险丝恢复),微服务恢复OK。

5.2.2 异常比例

是什么
在这里插入图片描述
在这里插入图片描述
测试

代码

@GetMapping("/testD")
    public String testD()
    {
 
        log.info("testD 测试RT");
        int age = 10/0;
        return "------testD";
    }
 
 

配置
在这里插入图片描述
jmeter
在这里插入图片描述
结论
在这里插入图片描述

5.2.3 异常数

是什么

在这里插入图片描述
在这里插入图片描述
异常数是按照分钟统计的

测试

代码

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

配置

http://localhost:8401/testE
在这里插入图片描述
在这里插入图片描述
前四次,报错
在这里插入图片描述
五次以后,降级
在这里插入图片描述

六、热点key限流

6.1 基本介绍

在这里插入图片描述

6.2 官网

https://github.com/alibaba/Sentinel/wiki/热点参数限流

6.3 @SentinelResource

6.3.1 兜底方法

分为系统默认和客户自定义,两种

之前的case,限流出问题后,都是用sentinel系统默认的提示:Blocked by Sentinel(flow limiting)

我们能不能自定?类似hystrix,某个方法出问题了,就找对应的兜底降级方法?

6.3.2 结论

从HystrixCommand到@SentinelResource

6.4 代码

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

@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) {
    //int age = 10/0;
    return "------testHotKey";
}
 
//兜底方法
public String deal_testHotKey (String p1, String p2, BlockException exception){
    return "------deal_testHotKey,o(╥﹏╥)o";  
}
 
 

6.5 配置

在这里插入图片描述
在这里插入图片描述
异常打到了前台用户界面看不到,不友好

@SentinelResource(value = "testHotKey")

在这里插入图片描述
方法testHostKey里面第一个参数,只要QPS超过每秒1次,马上降级处理,用了我们自己定义的

@SentinelResource(value = "testHotKey",blockHandler = "deal_testHotKey")

在这里插入图片描述

6.6 测试

只要不包含热点参数,没有限流规则,所以就不会报错
在这里插入图片描述

6.7 参数例外项

上述案例演示了第一个参数p1,当QPS超过1秒1次点击后马上被限流

6.7.1 特殊情况

普通

超过1秒钟一个后,达到阈值1后马上被限流

特例

我们期望p1参数当它是某个特殊值时,它的限流值和平时不一样。假如,当p1的值等于5时,它的阈值可以达到200.

6.7.2 配置

在这里插入图片描述

6.7.3 测试

前提条件:热点参数的注意点,参数必须是基本类型或者String
在这里插入图片描述

七、系统规则

7.1 是什么

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

7.2 各项配置参数说明

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

7.3 配置全局QPS

全局性的,不具体方法,所有的
在这里插入图片描述

八. @SentinelResource

8.1 按资源名称限流+后续处理

8.1.1 启动Nacos成功

8.1.2 启动Sentinel成功

8.1.3 Module

cloudalibaba-sentinel-service8401

在这里插入图片描述
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>cloud2020</artifactId>
        <groupId>com.atguigu.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
 
    <artifactId>cloudalibaba-sentinel-service8401</artifactId>
 
    <dependencies>
        <dependency>
            <groupId>com.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
 
        <dependency>
            <groupId>com.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
 
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
 
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>
 
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
 
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
 
        <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>
 
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>4.6.3</version>
        </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>
 

YML

server:
  port: 8401
 
spring:
  application:
    name: cloudalibaba-sentinel-service
  cloud:
    nacos:
      discovery:
#        Nacos服务注册中心地址
        server-addr: localhost:8848
    sentinel:
      transport:
#        配置Sentinel dashboard地址
        dashboard: localhost:8080
        port: 8719  #默认8719,假如被占用了会自动从8719开始依次+1扫描。直至找到未被占用的端口
 
management:
  endpoints:
    web:
      exposure:
        include: '*'
 
 
 
 

业务类

package com.atguigu.springcloud.alibaba.controller;
 
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.atguigu.springcloud.entities.CommonResult;
import com.atguigu.springcloud.entities.Payment;
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 CommonResult byResource() {
        return new CommonResult(200, "按资源名称限流测试OK", new Payment(2020L, "serial001"));
    }
 
    public CommonResult handleException(BlockException exception) {
        return new CommonResult(444, exception.getClass().getCanonicalName() + "\t 服务不可用");
    }
}
 

8.1.4 配置流控规则

配置步骤
在这里插入图片描述
表示1秒钟内查询次数大于1,就跑到我们自定义的限流

8.1.5 测试

1秒钟点击1下,OK
在这里插入图片描述
超过上述问题,疯狂点击,返回了自己定义的限流处理信息,限流发送
在这里插入图片描述

8.1.6 额外问题

此时关闭微服务8401看看
在这里插入图片描述
Sentinel控制台,流控规则消失了?
在这里插入图片描述
临时/持久?如何持久化?

8.2 安装Url地址限流+后续处理

通过访问的URL来限流,会返回Sentinel自带默认的限流处理信息

8.2.1 业务类

package com.atguigu.springcloud.alibaba.controller;
 
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.atguigu.springcloud.entities.CommonResult;
import com.atguigu.springcloud.entities.Payment;
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 CommonResult byResource() {
        return new CommonResult(200, "按资源名称限流测试OK", new Payment(2020L, "serial001"));
    }
 
    public CommonResult handleException(BlockException exception) {
        return new CommonResult(444, exception.getClass().getCanonicalName() + "\t 服务不可用");
    }
 
    @GetMapping("/rateLimit/byUrl")
    @SentinelResource(value = "byUrl")
    public CommonResult byUrl()
    {
        return new CommonResult(200,"按url限流测试OK",new Payment(2020L,"serial002"));
    }
}
 

8.2.2 访问一次

http://localhost:8401/rateLimit/byUrl

8.2.3 Sentinel控制台配置

在这里插入图片描述

8.2.4 测试

疯狂点击http://localhost:8401/rateLimit/byUrl

结果
在这里插入图片描述

8.3 上面兜底方法面临的问题

系统默认的,没有体现我们自己的业务要求。
依照现有条件,我们自定义的处理方法又和业务代码耦合在一块,不直观。
每个业务方法都添加一个兜底的,那代码膨胀加剧。
全局统一的处理方法没有体现。

8.4 客户自定义限流处理逻辑

在这里插入图片描述

8.4.1 创建customerBlockHandler类用于自定义限流处理逻辑

package com.atguigu.springcloud.alibaba.myhandler;
 
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.atguigu.springcloud.entities.CommonResult;
import com.atguigu.springcloud.entities.Payment;
 
/**
 * @author by Jak
 * @date 2020/7/3
 */
public class CustomerBlockHandler {
    public static CommonResult handleException(BlockException exception) {
        return new CommonResult(4444, "按客户自定义,global,handlerException----1");
    }
 
    public static CommonResult handleException2(BlockException exception) {
        return new CommonResult(4444, "按客户自定义,global,handlerException----2");
    }
}

8.4.2 RateLimitController

package com.atguigu.springcloud.alibaba.controller;
 
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.atguigu.springcloud.alibaba.myhandler.CustomerBlockHandler;
import com.atguigu.springcloud.entities.CommonResult;
import com.atguigu.springcloud.entities.Payment;
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 CommonResult byResource() {
        return new CommonResult(200, "按资源名称限流测试OK", new Payment(2020L, "serial001"));
    }
 
    public CommonResult handleException(BlockException exception) {
        return new CommonResult(444, exception.getClass().getCanonicalName() + "\t 服务不可用");
    }
 
    @GetMapping("/rateLimit/byUrl")
    @SentinelResource(value = "byUrl")
    public CommonResult byUrl()
    {
        return new CommonResult(200,"按url限流测试OK",new Payment(2020L,"serial002"));
    }
 
    @GetMapping("rateLimit/customerBlockHandler")
    @SentinelResource(value = "customerBlockHandler",
    blockHandlerClass = CustomerBlockHandler.class,
    blockHandler = "handlerException2")
    public CommonResult customerBlockHandler() {
        return new CommonResult(200, "按客户自定义", new Payment(2020L, "serial003"));
    }
}
 

8.4.3 启动微服务后先调用一次

http://localhost:8401/rateLimit/customerBlockHandler
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
handlerException2兜底
在这里插入图片描述
在这里插入图片描述

8.5 更多注解属性说明

在这里插入图片描述

8.5.1 Define Resource

在这里插入图片描述

8.5.2 Sentinel主要有三个核心API

SphU定义资源
Tracer定义统计
ContextUtil定义上下文

九、服务熔断功能

sentinel整合ribbon+openFeign+fallback

9.1 Ribbon系列

9.1.1 启动nacos和Sentinel

9.1.2提供9003/9004

新建cloudalibaba-provider-payment9003/9004
在这里插入图片描述
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>cloud2020</artifactId>
        <groupId>com.atguigu.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
 
    <artifactId>cloudalibaba-provider-payment9003</artifactId>
 
    <dependencies>
        <!--SpringCloud ailibaba nacos -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency><!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
            <groupId>com.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!-- SpringBoot整合Web组件 -->
        <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>

YML

server:
  port: 9003
 
spring:
  application:
    name: nacos-payment-provider
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #配置Nacos地址
 
management:
  endpoints:
    web:
      exposure:
        include: '*'

主启动

package com.atguigu.springcloud.alibaba;
 
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
 
/**
 * @author by Jak
 * @date 2020/7/3
 */
@SpringBootApplication
@EnableDiscoveryClient
public class PaymentMain9003 {
    public static void main(String[] args) {
        SpringApplication.run(PaymentMain9003.class, args);
    }
}

业务类

package com.atguigu.springcloud.alibaba.controller;
 
 
import com.atguigu.springcloud.entities.CommonResult;
import com.atguigu.springcloud.entities.Payment;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
 
import java.util.HashMap;
 
 
@RestController
public class PaymentController
{
    @Value("${server.port}")
    private String serverPort;
 
    public static HashMap<Long, Payment> hashMap = new HashMap<>();
    static{
        hashMap.put(1L,new Payment(1L,"28a8c1e3bc2742d8848569891fb42181"));
        hashMap.put(2L,new Payment(2L,"bba8c1e3bc2742d8848569891ac32182"));
        hashMap.put(3L,new Payment(3L,"6ua8c1e3bc2742d8848569891xt92183"));
    }
 
    @GetMapping(value = "/paymentSQL/{id}")
    public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id){
        Payment payment = hashMap.get(id);
        CommonResult<Payment> result = new CommonResult(200,"from mysql,serverPort:  "+serverPort,payment);
        return result;
    }
 
}
 
 

测试地址

9004同上

http://localhost:9003/paymentSQL/1

http://localhost:9004/paymentSQL/1

9.1.3 消费者84

1.新建cloudalibaba-consumer-nacos-order84
在这里插入图片描述
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>cloud2020</artifactId>
        <groupId>com.atguigu.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
 
    <artifactId>cloudalibaba-consumer-nacos-order84</artifactId>
 
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <dependency>
            <groupId>com.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <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>
        <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: 84
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
 

4.主启动

package com.atguigu.springcloud.alibaba;
 
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
 
 
@EnableDiscoveryClient
@SpringBootApplication
@EnableFeignClients
public class OrderNacosMain84
{
    public static void main(String[] args) {
        SpringApplication.run(OrderNacosMain84.class, args);
    }
}
 
 

5.业务类

package com.atguigu.springcloud.alibaba.config;
 
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
 
/**
 * @author by Jak
 * @date 2020/7/3
 */
@Configuration
public class ApplicationContextConfig {
 
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
}
package com.atguigu.springcloud.alibaba.controller;
 
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
 
import com.atguigu.springcloud.entities.CommonResult;
import com.atguigu.springcloud.entities.Payment;
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 CommonResult<Payment> fallback(@PathVariable Long id) {
        CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/"+id, CommonResult.class,id);
 
        if (id == 4) {
            throw new IllegalArgumentException ("IllegalArgumentException,非法参数异常....");
        }else if (result.getData() == null) {
            throw new NullPointerException ("NullPointerException,该ID没有对应记录,空指针异常");
        }
 
        return result;
    }
 
    //fallback
    public CommonResult handlerFallback(@PathVariable  Long id,Throwable e) {
        Payment payment = new Payment(id,"null");
        return new CommonResult<>(444,"兜底异常handlerFallback,exception内容  "+e.getMessage(),payment);
    }
 
    //blockHandler
    public CommonResult blockHandler(@PathVariable  Long id,BlockException blockException) {
        Payment payment = new Payment(id,"null");
        return new CommonResult<>(445,"blockHandler-sentinel限流,无此流水: blockException  "+blockException.getMessage(),payment);
    }
 
 
}
 
 

修改后请重启微服务

  • 热部署对java代码级生效及时
  • 对@SentinelResource注解内属性,有时效果不好

目的

  • fallback管运行异常
  • blockHandler管配置违规

测试地址

依次开启9003、9004、84

访问http://localhost:84/consumer/fallback/1

先出现9003,再出现9004,有轮询负载均衡算法
在这里插入图片描述
在这里插入图片描述
没有任何配置

即没有熔断,也没有降级
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
fallback/4,给客户error页面,不友好

只配置fallback
在这里插入图片描述
访问http://localhost:84/consumer/fallback/4,不再有错误页面,返回友好提示
在这里插入图片描述
只配置blockHandler
在这里插入图片描述
在这里插入图片描述
访问一次直接java报错
在这里插入图片描述
快速点,满足Sentinel规则
在这里插入图片描述
fallback和blockHandler都配置
在这里插入图片描述
在这里插入图片描述
测试

一秒钟1个没问题
在这里插入图片描述
超过1个,即使正确的也会走到限流
在这里插入图片描述
一秒一个,有错,java异常找fallback
在这里插入图片描述
超过1个,找blockHandler
在这里插入图片描述
忽略属性

IllegalArgumentException异常忽略,不走兜底。NullPointerException没有配置,走兜底
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

9.2 Feign系列

9.2.1 修改84模块

在这里插入图片描述

9.2.2 POM

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

9.2.3 YML

server:
  port: 84
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

9.2.4 主启动

添加@EnableFeignClients启动Feign的功能

package com.atguigu.springcloud.alibaba;
 
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
 
 
@EnableDiscoveryClient
@SpringBootApplication
@EnableFeignClients
public class OrderNacosMain84
{
    public static void main(String[] args) {
        SpringApplication.run(OrderNacosMain84.class, args);
    }
}
 
 

9.2.5 业务类

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
带@FeignClient注解的业务接口

package com.atguigu.springcloud.alibaba.service;
 
import com.atguigu.springcloud.entities.CommonResult;
import com.atguigu.springcloud.entities.Payment;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
 
/**
 * @author by Jak
 * @date 2020/7/3
 */
@FeignClient(value = "nacos-payment-provider", fallback = PaymentFallbackService.class)
public interface PaymentService {
 
    @GetMapping(value = "/paymentSQL/{id}")
    public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id);
}

Controller

package com.atguigu.springcloud.alibaba.controller;
 
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
 
import com.atguigu.springcloud.alibaba.service.PaymentService;
import com.atguigu.springcloud.entities.CommonResult;
import com.atguigu.springcloud.entities.Payment;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
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") //两个都配,则被限流降级而抛出BlockException时,只会进入blockHandler
    @SentinelResource(value = "fallback", fallback = "handlerFallback", blockHandler = "blockHandler",
            exceptionsToIgnore = {IllegalArgumentException.class})
    public CommonResult<Payment> fallback(@PathVariable Long id) {
        CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/" + id, CommonResult.class, id);
 
        if (id == 4) {
            throw new IllegalArgumentException("IllegalArgumentException,非法参数异常....");
        } else if (result.getData() == null) {
            throw new NullPointerException("NullPointerException,该ID没有对应记录,空指针异常");
        }
 
        return result;
    }
    //blockHandler
    public CommonResult blockHandler(@PathVariable Long id, BlockException blockException) {
        Payment payment = new Payment(id, "null");
        return new CommonResult<>(445, "blockHandler-sentinel限流,无此流水: blockException  " + blockException.getMessage(), payment);
    }
 
    //fallback
    public CommonResult handlerFallback(@PathVariable Long id, Throwable e) {
        Payment payment = new Payment(id, "null");
        return new CommonResult<>(444, "兜底异常handlerFallback,exception内容  " + e.getMessage(), payment);
    }
 
    // OpenFeign
    @Resource
    private PaymentService paymentService;
 
    @GetMapping(value = "/consumer/paymentSQL/{id}")
    public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id) {
        return paymentService.paymentSQL(id);
    }
}
 
 

9.2.6 测试

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

9.3 熔断框架比较

在这里插入图片描述

十、规则持久化

10.1 是什么

一旦我们重启应用,sentinel规则将消失,生产环境需要将配置规则进行持久化。

10.1.1 开启8401

在这里插入图片描述

在这里插入图片描述

10.1.2 配置流控

在这里插入图片描述
在这里插入图片描述
此时重启8401,刚才的配置已经没有了
在这里插入图片描述

10.2 怎么玩

将限流配置规则持久化进Nacos保存,只要刷新8401某个rest地址,sentinel控制台的流控规则就能看到,只要Nacos里面的配置不删除,针对8401上sentinel上的流控规则持续有效。

10.3 步骤

10.3.1 修改cloudalibaba-sentinel-service8401

10.3.2 POM

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
 

10.3.3 YML

server:
  port: 8401
 
spring:
  application:
    name: cloudalibaba-sentinel-service
  cloud:
    nacos:
      discovery:
#        Nacos服务注册中心地址
        server-addr: localhost:8848
    sentinel:
      transport:
#        配置Sentinel dashboard地址
        dashboard: localhost:8080
        port: 8719  #默认8719,假如被占用了会自动从8719开始依次+1扫描。直至找到未被占用的端口
        datasource:
          ds1:
            nacos:
              server-addr: localhost:8848
              dataId: cloudalibaba-sentinel-service
              groupId: DEAFAULT_GROUP
              data-type: json
              rule-type: flow
 
management:
  endpoints:
    web:
      exposure:
        include: '*'
spring:
   cloud:
    sentinel:
    datasource:
     ds1:
      nacos:
        server-addr:localhost:8848
        dataid:${spring.application.name}
        groupid:DEFAULT_GROUP
        data-type:json
            rule-type:flow
 

10.3.4 添加Nacos业务规则配置

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

[
    {
         "resource": "/retaLimit/byUrl",
         "limitApp": "default",
         "grade":   1,
         "count":   1,
         "strategy": 0,
         "controlBehavior": 0,
         "clusterMode": false    
    }
]

在这里插入图片描述

10.3.5 启动8401后刷新sentinel发现业务规则有了

在这里插入图片描述

10.3.6 快速访问测试接口

http://localhost:8401/rateLimit/byUrl
在这里插入图片描述

10.3.7 停止8401再看sentinel

在这里插入图片描述

10.3.8 重新启动8401再看sentinel

乍一看还是没有,稍等一会儿

多次调用,http://localhost:8401/rateLimit/byUrl

重新配置出现了,持久化验证通过
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值