个人收款码 facebook primefaces webkit Parsley bootstrap后台管理 oracle一键卸载工具 linux查看mysql进程 iot系统 java解析json数组 hash怎么下载 js原生点击事件 linux撤销 mysql连接 python生成随机数 python包 java覆盖 java运行环境配置 java的random java的for循环 java获取当前ip java线程中断 java定义变量 linuxgrep linuxshell编程 渐变事件 方正兰亭字体下载 摩斯密码翻译器 自动答题软件 流程图工具 苹果放大镜 apihook 虚拟声卡驱动 fireworks下载 计划任务软件 geartrax hedit maya骨骼绑定教程 nonetype origin怎么画图
当前位置: 首页 > 学习教程  > 编程语言

三、Sentinel实现熔断与限流

2020/11/24 9:50:03 文章标签: 测试文章如有侵权请发送至邮箱809451989@qq.com投诉后文章立即删除

一、概述 1、Sentinel介绍 随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。 2、Sentinel特征 丰富的应用场景:Sentinel 承接了阿里巴巴近…

一、概述

1、Sentinel介绍

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

2、Sentinel特征

在这里插入图片描述

3、Sentinel的开源生态

在这里插入图片描述

4、相关地址

1、官网地址
2、中文官网
3、参考文档

二、启动Sentinel控制台

1、组成

Sentinel组件由两部分组成:

2、下载地址

下载地址,推荐使用自带浏览器下载,下载速度会很快

在这里插入图片描述

3、启动

1、启动前提
2、cmd进入安装包位置并执行启动命令
nohup java -jar -Xms256m -Xmx256m -XX:PermSize=512M -XX:MaxPermSize=512m sentinel-dashboard-1.7.0.jar &
3、访问Sentinel管理界面

在这里插入图片描述

三、Sentinel快速上手

1、新建一个Module

项目名:cloudalibaba-sentinel-service8401

2、pom配置

<dependencies>
    <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>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>

    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
    </dependency>

    <dependency>
        <groupId>com.itan</groupId>
        <artifactId>cloud-api-commons</artifactId>
        <version>1.0-SNAPSHOT</version>
        <scope>compile</scope>
    </dependency>
</dependencies>

3、yml配置

server:
  port: 8401

spring:
  application:
    name: cloudalibaba-sentinel-service
  cloud:
    nacos:
      discovery:
        # server-addr: 192.168.241.135:8848/ #配置Nacos地址
        # 由于nacos配置成集群了,因此需要换成nginx监听的1111端口
        server-addr: 192.168.241.135:1111
    sentinel:
      transport:
        # sentinel 仪表盘地址
        dashboard: localhost:8080
        # 默认8719,假如被占用了会自动从8719开始依次+1扫描。直至找到未被占用的端口
        port: 8719
      # eager: true # 取消延迟加载(默认是延迟加载的)

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

4、启动类

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

5、业务类

@RestController
@RequestMapping("sentinel")
public class Sentinel8401Controller {
    @GetMapping("getA")
    public String testA(){
        return "--------testA";
    }

    @GetMapping("getB")
    public String testB(){
        return "--------testB";
    }
}

6、测试

1、启动nacos集群
2、启动sentinel
3、启动Sentinel8401
4、查看sentinel控制台,发现什么也没有,说明Sentinel采用的是懒加载,多执行几次请求,刷新控制台

在这里插入图片描述

注:sentinel的监控台一开始是没有东西的,需要对监控的服务发起请求后才会出现。

四、流控规则

1、流控规则说明

在这里插入图片描述

1、资源名:唯一名称,默认请求路径。
2、针对来源:Sentinel可以针对调用者进行限流,填写微服务名,默认是default(不区分来源)。
3、阀值类型/单机阀值
4、是否集群:不需要集群。
5、流控模式
6、流控效果

2、流控模式之直接模式

默认方式,当达到阈值直接快速失败
1、配置

在这里插入图片描述

说明:表示在1秒钟内调用一次/sentinel/getB接口就OK,若超过1次,就直接失败,报默认错误

在这里插入图片描述

2、调用/sentinel/getB接口慢一点,发现正常返回。
3、快速调用接口,超过阈值,接口返回了Blocked by Sentinel (flow limiting),代表被限流了。

在这里插入图片描述

在这里插入图片描述

3、流控模式之关联模式

当关联的资源达到阈值时,就限流自己。当与A关联的资源B达到阈值后,就限流自己,B惹事了,但是A挂了,B没事。
1、配置

在这里插入图片描述

说明:当关联资源/sentinel/getB的QPS阈值超过1时,就限制访问/sentinel/getA,当关联资源达到阈值就限制配置的资源名
2、单独postman调用/sentinel/getB接口,再调用getA接口发现正常
3、多线程下模拟并发密集访问getB接口,再访问getA接口,发现报错Blocked by Sentinel (flow limiting),代表被限流了。

在这里插入图片描述

在这里插入图片描述

4、流控模式之链路模式

只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就进行限流,api级别的针对来源)
1、进入簇点链路下,查看/sentinel/getA的资源入口是sentinel_web_servlet_context

在这里插入图片描述

2、添加流控,配置链路入口资源为sentinel_web_servlet_context

在这里插入图片描述

3、当频繁访问接口/sentinel/getA时,发现报错Blocked by Sentinel (flow limiting),代表被限流了。

在这里插入图片描述

5、流控效果之快速失败

上述使用的都是快速失败,当QPS达到阈值就直接抛出异常Blocked by Sentinel (flow limiting)
源码:com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController

6、流控效果之预热

1、官网解释sentinel限流-冷启动-预热
2、公式:阈值除以coldFactor(默认值为3),即请求QPS从threshold/3开始,经预热时长逐渐升至设定的QPS阈值。
3、源码:com.alibaba.csp.sentinel.slots.block.flow.controller.WarmUpController

在这里插入图片描述

4、添加流控,选择Warm Up,设置预热时长

在这里插入图片描述

说明:设置阈值为10,系统初始化的QPS阈值为10/3≈3,即阈值刚开始为3,经过预热时长5秒钟后,阈值才会慢慢上升到10
5、快速刷新,刚开始发现抛出异常,后续没有抛出异常信息了,正常了

在这里插入图片描述

6、引用场景:秒杀系统在开启的瞬间,会有很多流量上来,很有可能会让系统宕机,预热方式是为了保护系统,慢慢的把流量放进来,慢慢把阈值增涨到设定的阈值。

7、流控效果之排队等待

1、官网解释流量控制

在这里插入图片描述

2、源码:com.alibaba.csp.sentinel.slots.block.flow.controller.RateLimiterController
3、删除之前配置的流控,防止出现干扰,再新建流控

在这里插入图片描述

说明:/sentinel/getA每秒一次请求,超过阈值的话,就排队等待,等待的超时时间为20000ms
4、密集访问/sentinel/getA接口,发现每一次访问都没有抛出异常,说明在排队等待

在这里插入图片描述

5、将超时时间设置为2ms,连续访问接口,发现抛出异常信息

在这里插入图片描述

五、降级规则

1、概述

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

在这里插入图片描述

现代微服务架构都是分布式的,由非常多的服务组成。不同服务之间相互调用,组成复杂的调用链路。以上的问题在链路调用中会产生放大的效果。复杂链路上的某一环不稳定,就可能会层层级联,最终导致整个链路都不可用。因此我们需要对不稳定的弱依赖服务调用进行熔断降级,暂时切断不稳定调用,避免局部不稳定因素导致整体的雪崩。熔断降级作为保护自身的手段,通常在客户端(调用端)进行配置。
简述:Sentinel熔断降级会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联错误。当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断(默认行为是抛出DegradeException)。
Sentinel的断路器是没有半开状态的,半开的状态系统自动去检测是否请求有异常,没有异常就关闭断路器恢复使用,有异常则继续打开断路器不可用。具体可以参考Hystrix

2、基本介绍

在这里插入图片描述

RT(平均响应时间,秒级):
异常比例(秒级):
  • QPS >= 5且异常比例(秒级统计)超过阈值时,触发降级,时间窗口结束后,关闭降级。
异常数(分钟级):
  • 异常数(分钟统计)超过阈值时,触发降级,时间窗口结束后,关闭降级。

3、降级策略之RT

1、平均响应时间(DEGRADE_GRADE_RT)说明

当1s内持续进入5个请求,对应时刻的平均响应时间(秒级)均超过阈值(count 以ms为单位),那么在接下来的时间窗口(DegradeRule中的timeWindow,以s为单位)之内,对这个方法的调用都会自动地熔断(【抛出DegradeException)。

2、业务类中新加textC方法

@GetMapping("getC")
public String testC(){
    try {
        TimeUnit.SECONDS.sleep(1);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    log.info("testC 测试RT");
    return "------testC";
}

3、配置降级规则

在这里插入图片描述

4、jmeter压测

1、创建线程组

在这里插入图片描述

2、创建HTTP请求

在这里插入图片描述

3、执行测试并在浏览器访问getC接口,接口返回了Blocked by Sentinel (flow limiting),代表被限流了。

在这里插入图片描述

4、说明
按照上面的配置,在一秒钟内起10个线程(满足每秒QPS大于5个了)调用getC接口,如果响应时间超出(希望200ms能够处理完)还没有处理完,在未来1秒钟的时间窗口内,断路器打开,微服务不可用;后续停止jmeter,没有这么大的访问量了,断路器关闭,微服务恢复,可以访问。

4、降级策略之异常比例

1、异常比例(DEGRADE_GRADE_EXCEPTION_RATIO)说明

当资源的每秒请求量 >= 5,并且每秒异常总数占通过量的比值超过阈值(DegradeRule中的count)之后,资源进入降级状态,即在接下来的时间窗口(DegradeRule中的timeWindow,以s为单位)之内,对这个方法的调用都会自动地返回。异常比率的阈值范围[0.0,1.0],代表0%~100%。

2、在上述testC方法中制造一个异常

@GetMapping("getC")
public String testC(){
    log.info("testC 测试异常比例");
    int i = 10 / 0;
    return "------testC";
}

3、配置降级规则

在这里插入图片描述

说明:异常比例超过20%,并且每秒钟 >=5 个请求的时候,在接下来的时间窗口3内服务不可用了。

4、jmeter压测

1、配置同上不变
2、执行测试并在浏览器访问getC接口,接口返回了Blocked by Sentinel (flow limiting),代表被限流了。

在这里插入图片描述

3、当停止jmeter后,再次访问,发现报错Error

在这里插入图片描述

4、说明
按照上面的配置,当单独访问接口的时候,报错(by zero),并且是调用一次报错一次,开启jmeter后,直接高并发发送请求,1秒钟内起10个线程(满足QPC每秒大于5个了)调用getC接口,并且异常比例也超过0.2,断路器打开,微服务不可用了,不再报错error而是服务降级了。

5、降级策略之异常数

1、异常数(DEGRADE_GRADE_EXCEPTION_COUNT)说明

当资源近1分钟的异常数目超过阈值之后会进行熔断,注意由于统计时间窗口是分钟级别的。若timeWindow小于60s,则结束熔断状态后仍可能再进入熔断状态。因此时间窗口一定要大于等于60秒

2、业务类中新加一个getD方法

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

3、配置降级规则

在这里插入图片描述

4、测试

1、访问次数小于设置的异常数阈值,发现报错Error

在这里插入图片描述

2、访问次数大于设置的异常数阈值,接口返回了Blocked by Sentinel (flow limiting),代表被限流了。

在这里插入图片描述

六、热点规则

1、概述

1、官网:热点参数限流
2、解释热点:即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。比如:
热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。

2、兜底方法

3、@SentinelResource注解介绍

作用:用于定义资源,并提供了AspectJ的扩展用于自动定义资源、处理BlockException等
属性名是否必填说明
value资源名称。(必填项,需要通过 value 值找到对应的规则进行配置)
entryTypeentry类型,标记流量的方向,取值IN/OUT,默认是OUT
blockHandler处理BlockException的函数名称(可以理解为对Sentinel的配置进行方法兜底)。函数要求:
1.必须是 public 修饰
2.返回类型与原方法一致
3. 参数类型需要和原方法相匹配,并在最后加 BlockException 类型的参数。
4. 默认需和原方法在同一个类中。若希望使用其他类的函数,可配置 blockHandlerClass ,并指定blockHandlerClass里面的方法。
blockHandlerClass存放blockHandler的类
对应的处理函数必须public static修饰,否则无法解析,其他要求:同blockHandler。
fallback用于在抛出异常的时候提供fallback处理逻辑(可以理解为对Java异常情况方法兜底)
fallback函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。函数要求:
1.返回类型与原方法一致
2.参数类型需要和原方法相匹配,Sentinel 1.6开始,也可在方法最后加 Throwable 类型的参数。
3.默认需和原方法在同一个类中。若希望使用其他类的函数,可配置 fallbackClass ,并指定fallbackClass里面的方法。
fallbackClass存放fallback的类
对应的处理函数必须static修饰,否则无法解析,其他要求:同fallback。
defaultFallback用于通用的 fallback 逻辑
默认 fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。若同时配置了 fallback 和 defaultFallback,以fallback为准。函数要求:
1.返回类型与原方法一致
2.方法参数列表为空,或者有一个 Throwable 类型的参数。
3.默认需要和原方法在同一个类中。若希望使用其他类的函数,可配置 fallbackClass ,并指定 fallbackClass 里面的方法。
exceptionsToIgnore指定排除掉哪些异常。
排除的异常不会计入异常统计,也不会进入fallback逻辑,而是原样抛出。
exceptionsToTrace需要trace的异常

4、配置热点key规则

1、业务类新建一个方法

在这里插入图片描述

2、sentinel配置热点规则

在这里插入图片描述

说明:第一个参数的阈值超过每秒钟一个,就会违背配置规则,就会由sentinel方法兜底。

3、测试

1、接口传入p1参数且每秒点击一次的时候能正常返回接口的内容,连续点击多次,返回的是兜底方法的内容

在这里插入图片描述

2、接口参数都传且每秒点击一次的时候能正常返回接口的内容,连续点击多次,返回的是兜底方法的内容

在这里插入图片描述

3、接口不传p1参数,无论点击多少次都能正常返回接口内容

在这里插入图片描述

说明:按照上面配置,当资源的第一个参数的阈值超过每秒钟一个,就会违背配置规则,就会由sentinel方法兜底。

5、参数例外项

1、说明

1、通过上面案例可知,当参数索引为0(也就是第一个参数p1)的QPS超过1秒1次点击后马上被限流。
2、通常情况下,超过1秒钟后达到阈值1后马上就被限流。如果是期望p1参数当它是某一个特殊值时,它的限流和平时不一样,比如说当p1的值为66时,它的阈值可以达到200,那么这个时候它就要用到参数例外项。

2、配置参数例外项

在这里插入图片描述

说明:参数索引下标为0(也就是第一个参数p1),通常QPS超过1马上就被限流,但是结合例外项,当参数值为66时,QPS阈值会达到200
注意:参数必须是基本类型或者String

3、测试

1、当p1参数值不为66时,1秒访问1次接口返回正常,但是快速访问接口,就会被限流。返回兜底方法内容。
2、当p1参数值为66时,无论1秒钟访问多少次接口,都能拿到正常内容,因为QPS阈值是200。

在这里插入图片描述

4、补充说明

倘若我们在代码中手动制造一个异常,比如:int i = 10 / 0,发现就会报错,这是因为@SentinelResource处理的是Sentinel控制台配置的违规情况,才会有blockHandler方法配置的兜底处理,int i = 10 / 0这个是java运行时报出的运行时异常RunTimeException,blockHandler不会管,但是可以配置fallback来对程序异常进行兜底。

七、系统规则

1、概述

官网:系统自适应限流
系统自适应限流说明:Sentinel 系统自适应限流从应用整体维度对应用入口流量进行控制(只对入口流量生效),结合应用的 Load、CPU 使用率、总体平均 RT、入口 QPS 和并发线程数等几个维度的监控指标,通过自适应的流控策略,让系统的入口流量和系统的负载达到一个平衡,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
系统保护的目的:
入口流量:指的是进入应用的流量(EntryType.IN),比如 Web 服务或 Dubbo 服务端接收的请求,都属于入口流量。

2、系统规则的模式

3、配置

1、配置一个系统规则

在这里插入图片描述

说明:当整个系统(是全局生效,不再针对某一个接口)的QPS达到阈值1的时候,就会被限流

4、测试

快速访问接口,发现被限流了,访问其他接口也限流了,说明是针对全局的

在这里插入图片描述

八、@SentinelResource

1、按资源名称限流及问题发现

1、在8401中新建一个业务类

@Slf4j
@RestController
public class RateLimitController {
    @GetMapping("/byResource")
    @SentinelResource(value = "byResource",blockHandler = "handleException")
    public CommonResult byResource() {
        return new CommonResult("200","按资源名称限流测试OK",new Payment(2020,"serial001"));
    }
    public CommonResult handleException(BlockException exception) {
        return new CommonResult("444",exception.getClass().getCanonicalName() + ":服务不可用");
    }
}

2、添加流控规则

在这里插入图片描述

说明:表示1秒钟内查询次数大于1,就跑到我们自定义的处流,限流

3、测试

1、一秒钟点击一下OK
2、疯狂点击,返回了自己定义的限流处理信息,限流发送

在这里插入图片描述

4、问题

当关闭8401服务后,发现sentinel控制台没有流控规则了,说明流控规则是临时的

2、按照Url地址限流及问题发现

通过访问的URL来限流,会返回Sentinel自带默认的限流处理信息Blocked by Sentinel (flow limiting)

1、添加流控规则

在这里插入图片描述

2、测试

1、一秒钟点击一下OK
2、疯狂点击,会返回sentinel自带的限流处理结果

在这里插入图片描述

3、上面兜底方法的缺点

1、系统默认的兜底方法,没有体现出自己的业务需求。
2、自定义的兜底方法和业务代码耦合在一起,不直观。
3、每个业务方法都添加一个兜底方法,代码会膨胀。
4、全局统一的处理方法没有体现。

4、自定义限流处理逻辑

1、新建一个类用于自定义限流处理逻辑

package com.itan.handler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.itan.common.CommonResult;

public class CustomerBlockHandler {
    public static CommonResult handlerException1(BlockException exception){
        return new CommonResult("20000","自定义的限流处理类----CustomerBlockHandler----1");
    }
    
    public static CommonResult handlerException2(BlockException exception){
        return new CommonResult("20000","自定义的限流处理类----CustomerBlockHandler----2");
    }
}

2、新建一个controller方法

@GetMapping("/rateLimit/customerBlockHandler")
//当QPS超过阈值,就会找到blockHandlerClass对应的类中blockHandler对应的方法名进行兜底处理
@SentinelResource(value = "customerBlockHandler",
                  blockHandlerClass = CustomerBlockHandler.class, blockHandler = "handlerException2")
public CommonResult customerBlockHandler() {
    return new CommonResult("200","按客戶自定义",new Payment(200,"serial003"));
}

3、配置限流规则

在这里插入图片描述

4、测试

疯狂点击,发现返回自定义的兜底方法的内容

在这里插入图片描述

九、整合Ribbon

1、新建两个服务提供者

cloudalibaba-provider-payment9003和cloudalibaba-provider-payment9004

1、pom配置

<dependencies>
    <!--nacos服务发现-->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </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>
    <!-- 引入自己定义的api通用包 -->
    <dependency>
        <groupId>com.itan</groupId>
        <artifactId>cloud-api-commons</artifactId>
        <version>1.0-SNAPSHOT</version>
        <scope>compile</scope>
    </dependency>
    <!-- 引入fastjson -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
    </dependency>
</dependencies>

2、yml配置

server:
  port: 9003 # 9004服务设置端口为9004

spring:
  application:
    name: nacos-payment-provider
  cloud:
    nacos:
      discovery:
        #server-addr: 192.168.241.135:8848/ #配置Nacos地址
        # 由于之前做了nacos集群,使用nginx做负载均衡,所以换成nginx的1111端口,做集群
        server-addr: 192.168.241.135:1111

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

3、启动类

@SpringBootApplication
@EnableDiscoveryClient //用于服务发现
public class Payment9003 {
    public static void main(String[] args) {
        SpringApplication.run(Payment9003.class, args);
    }
}

4、业务类

package com.itan.controller;

import com.itan.common.CommonResult;
import com.itan.entity.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<Integer, Payment> hashMap = new HashMap<>();
    static{
        hashMap.put(1,new Payment(1,"28a8c1e3bc2742d8848569891fb42181"));
        hashMap.put(2,new Payment(2,"bba8c1e3bc2742d8848569891ac32182"));
        hashMap.put(3,new Payment(3,"6ua8c1e3bc2742d8848569891xt92183"));
    }

    @GetMapping(value = "/payment/{id}")
    public CommonResult getPayment(@PathVariable("id") Integer id){
        Payment payment = hashMap.get(id);
        CommonResult result = new CommonResult("200","from mysql,serverPort:  " + serverPort, payment);
        return result;
    }
}

5、启动测试

接口地址:http://localhost:9003/payment/1

2、新建一个服务消费者

cloudalibaba-consumer-nacos-order82
由于nacos自带Ribbon依赖,所以不需要再添加Ribbon依赖

1、配置pom

<dependencies>
    <!--nacos服务发现-->
    <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>
    <!-- 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>
    <!-- 引入自己定义的api通用包 -->
    <dependency>
        <groupId>com.itan</groupId>
        <artifactId>cloud-api-commons</artifactId>
        <version>1.0-SNAPSHOT</version>
        <scope>compile</scope>
    </dependency>
    <!-- 引入fastjson -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
    </dependency>
</dependencies>

2、配置yml

server:
  port: 82


spring:
  application:
    name: nacos-order-consumer
  cloud:
    nacos:
      discovery:
        #server-addr: 192.168.241.135:8848/ #配置Nacos地址
        # 换成nginx的1111端口,做集群
        server-addr: 192.168.241.135:1111
    sentinel:
      transport:
        # sentinel 控制台地址
        dashboard: localhost:8080
        # 默认8719,假如被占用了会自动从8719开始依次+1扫描。直至找到未被占用的端口
        port: 8720
      eager: true # 取消延迟加载(默认是延迟加载的)

# 服务调用地址
url:
  nacos-user-service: http://nacos-payment-provider

3、主启动类

@EnableDiscoveryClient //用于服务发现
@SpringBootApplication
public class Consumer82 {
    public static void main(String[] args) {
        SpringApplication.run(Consumer82.class,args);
    }
}

4、配置类

@Configuration
public class Consumer82Config {
    @Bean
    @LoadBalanced //负载均衡,轮询方式
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
}

5、业务类

具体测试具体配置

3、测试

1、启动nacos注册中心
2、启动sentinel
3、启动两个服务提供者

1、服务消费者中无任何配置

@RestController
@RequestMapping("consumer")
public class Consumer82Controller {
    @Resource
    private RestTemplate restTemplate;

    @Value("${url.nacos-user-service}")
    private String URL;

    @GetMapping("/fallback/{id}")
    @SentinelResource(value = "fallback") //没有配置其他属性,只为sentinel控制台能够检测出
    public CommonResult fallback(@PathVariable Integer id) {
        CommonResult result = restTemplate.getForObject(URL + "/payment/" + id, CommonResult.class,id);
        if (id == 4) {
            throw new IllegalArgumentException ("IllegalArgumentException,非法参数异常....");
        }else if (result.getData() == null) {
            throw new NullPointerException ("NullPointerException,该ID没有对应记录,空指针异常");
        }
        return result;
    }
}
1、启动服务消费者
2、接口地址:http://localhost:82/consumer/fallback/1
3、发现返回的端口号会交替出现(9003、9004),达到负载均衡的效果

在这里插入图片描述

4、当传入的参数大于等于4,就会让人看到Error页面不友好

在这里插入图片描述

2、只配置fallback

@RestController
@RequestMapping("consumer")
public class Consumer82Controller {
    @Resource
    private RestTemplate restTemplate;

    @Value("${url.nacos-user-service}")
    private String URL;

    @GetMapping("/fallback/{id}")
    @SentinelResource(value = "fallback",fallback = "handlerFallback") //fallback只负责业务异常
    public CommonResult fallback(@PathVariable Integer id) {
        CommonResult result = restTemplate.getForObject(URL + "/payment/" + 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  Integer id,Throwable e) {
        Payment payment = new Payment(id,"null");
        return new CommonResult("444","兜底异常handlerFallback,exception内容  "+e.getMessage(),payment);
    }
}
1、重启服务消费者
2、接口地址:http://localhost:82/consumer/fallback/5
3、当程序运行过程中出现异常,全都由fallback的方法兜底

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

3、只配置blockHandler

@RestController
@RequestMapping("consumer")
public class Consumer82Controller {
    @Resource
    private RestTemplate restTemplate;

    @Value("${url.nacos-user-service}")
    private String URL;

    @GetMapping("/fallback/{id}")
    @SentinelResource(value = "fallback",blockHandler = "blockHandler") //blockHandler只负责sentinel控制台配置违规
    public CommonResult fallback(@PathVariable Integer id) {
        CommonResult result = restTemplate.getForObject(URL + "/payment/" + id, CommonResult.class,id);
        if (id == 4) {
            throw new IllegalArgumentException ("IllegalArgumentException,非法参数异常....");
        }else if (result.getData() == null) {
            throw new NullPointerException ("NullPointerException,该ID没有对应记录,空指针异常");
        }
        return result;
    }
    
    /**
     * blockHandler是针对sentinel配置违规的兜底方法
     */
    public CommonResult blockHandler(@PathVariable  Integer id, BlockException blockException){
        Payment payment = new Payment(id,"null");
        return new CommonResult("445","blockHandler-sentinel限流,无此流水: blockException  " + blockException.getMessage(),payment);
    }
}
1、重启服务消费者
2、接口地址:http://localhost:82/consumer/fallback/5
3、新建一个降级规则

在这里插入图片描述

4、每秒一次就报错Error页面,快速点击,发现服务被限流,不可用

在这里插入图片描述

3、fallback和blockHandler都配置

@RestController
@RequestMapping("consumer")
public class Consumer82Controller {
    @Resource
    private RestTemplate restTemplate;

    @Value("${url.nacos-user-service}")
    private String URL;

    @GetMapping("/fallback/{id}")
    @SentinelResource(value = "fallback",fallback = "handlerFallback",blockHandler = "blockHandler")
    public CommonResult fallback(@PathVariable Integer id) {
        CommonResult result = restTemplate.getForObject(URL + "/payment/" + 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  Integer id,Throwable e) {
        Payment payment = new Payment(id,"null");
        return new CommonResult("444","兜底异常handlerFallback,exception内容  "+e.getMessage(),payment);
    }

    /**
     * blockHandler是针对sentinel配置违规的兜底方法
     */
    public CommonResult blockHandler(@PathVariable  Integer id, BlockException blockException){
        Payment payment = new Payment(id,"null");
        return new CommonResult("445","blockHandler-sentinel限流,无此流水: blockException  " + blockException.getMessage(),payment);
    }
}
1、重启服务消费者
2、新建一个降级规则

在这里插入图片描述

3、疯狂点击:http://localhost:82/consumer/fallback/1,出现限流原因是每秒通过的QPS大于1就降级了

在这里插入图片描述

4、http://localhost:82/consumer/fallback/4,一秒访问一次,发现会调用fallback对应的方法

在这里插入图片描述

5、http://localhost:82/consumer/fallback/4,快速,发现服务降级,调用blockHandler对应的方法

在这里插入图片描述

总结:若fallback和blockHandler都进行了配置,则被限流降级而抛出BlockException时只会进入blockHandler对应的兜底方法。

十、整合Feign

1、修改服务消费者

cloudalibaba-consumer-nacos-order82

1、pom添加Feign支持

<!--feign相关-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

2、yml添加Feign配置

#对Feign的支持
feign:
  sentinel:
    enabled: true

3、Feign接口

通过使用@FeignClient注解调用Provider服务,新建一个feign包,用来存放feign接口
fallback参数:定义容错的处理类,当调用远程接口失败或超时时,会调用对应接口的容错逻辑,fallback指定的类必须是实现@FeignClient标记的接口
@FeignClient(value = "nacos-payment-provider",
        configuration = {ProviderFeignClient.ProviderFeignClientConfigure.class},
        fallback = ProviderFeignClientImpl.class)
public interface ProviderFeignClient {
    @GetMapping(value = "/payment/{id}")
    CommonResult payment(@PathVariable("id") Integer id);

    class ProviderFeignClientConfigure{
        //设置超时时间
        @Bean
        Request.Options options(){
            return new Request.Options(30000,60000);
        }
    }
}

Feign接口实现类

@Service
public class ProviderFeignClientImpl implements ProviderFeignClient {
    @Override
    public CommonResult payment(Integer id) {
        return new CommonResult("44444","服务降级返回,---PaymentFallbackService",new Payment(id,"errorSerial"));
    }
}

4、新建一个controller类

@RestController
public class ProviderFeignController {
    @Resource
    private ProviderFeignClient providerFeignClient;

    @GetMapping(value = "/feign/payment/{id}")
    public CommonResult payment(@PathVariable("id") Integer id) {
        return providerFeignClient.payment(id);
    }
}

5、主启动类添加@EnableFeignClients注解,启动feign功能

6、测试

1、正常访问接口:http://localhost:82/feign/payment/1,返回数据中端口号交替出现,说明实现负载均衡

在这里插入图片描述

2、当关闭一个服务提供者,或者两个都关闭,调用远程接口失败或超时时,会调用对应接口的容错逻辑,也就是feign接口实现类中的对应方法

在这里插入图片描述

2、熔断框架比较

在这里插入图片描述

十一、规则持久化

1、概述

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

2、实现方案

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

3、实现步骤

1、修改cloudalibaba-sentinel-service8401

2、添加依赖

<!--引入sentinel使用nacos存储规则的依赖-->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>

3、yml添加Nacos数据源配置

server:
  port: 8401

spring:
  application:
    name: cloudalibaba-sentinel-service
  cloud:
    nacos:
      discovery:
        # server-addr: 192.168.241.135:8848/ #配置Nacos地址
        # 由于nacos配置成集群了,因此需要换成nginx监听的1111端口
        server-addr: 192.168.241.135:1111
    sentinel:
      transport:
        # sentinel 控制台地址
        dashboard: localhost:8080
        # 默认8719,假如被占用了会自动从8719开始依次+1扫描。直至找到未被占用的端口
        port: 8720
      eager: true # 取消延迟加载(默认是延迟加载的)
      datasource:
        ds1:
          nacos:
          	# 配置nacos地址
            server-addr: 192.168.241.135:1111
            dataid: ${spring.application.name}
            groupid: DEFAULT_GROUP
            data-type: json
            rule-type: flow

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

4、添加Nacos配置规则

在这里插入图片描述

参数说明:

5、测试

1、启动8401服务后刷新sentinel,发现流控规则有了

在这里插入图片描述

2、快速访问接口http://localhost:8401/byResource,发现报默认的错误

在这里插入图片描述

3、停止8401服务,发现sentinel中没有流控规则了

在这里插入图片描述

4、再次启动服务,发现流控规则又出现了,说明实现了规则持久化

本文链接: http://www.dtmao.cc/news_show_400160.shtml

附件下载

相关教程

    暂无相关的数据...

共有条评论 网友评论

验证码: 看不清楚?