8.17日学习打卡---Spring Cloud Alibaba(四)

8.17日学习打卡

在这里插入图片描述

分布式流量防护

在这里插入图片描述
在分布式系统中,服务之间的相互调用会生成分布式流量。如何通过组件进行流量防护,并有效控制流量,是分布式系统的技术挑战之一。

什么是服务雪崩

假设我有一个微服务系统,这个系统内包含了 ABCD 四个微服务,这四个服务都是以集群模式构建的。
在这里插入图片描述

雪崩问题
微服务之间相互调用,因为调用链中的一个服务故障,引起整个链路都无法访问的情况。

解决方案

在这里插入图片描述
服务保护技术

  • Hystrix
  • Sentinel
  • Resilience4J

Sentinel 服务容错的思路

Sentinel 是 Spring Cloud Alibaba 的⼀款服务容错组件,我们也经常把它叫做“防流量哨 兵”。它是阿里巴巴双十一促核心场景的保护神,内置了丰富的服务容错应用场景。它以流 量作为切入点,通过各种内外防控手段达到维持服务稳定性的目的。
在这里插入图片描述

内部异常治理

在 Sentinel 中,我们可以采用降级和熔断的方式处理内部的异常。 所谓降级,是指当服务调用发生了响应超时、服务异常等情况时,我们在服务内部可以执行一段“降级逻辑”。
在这里插入图片描述
而所谓熔断,是指当异常调用量达到一定的判定条件,比如在异常降级和慢调用请求的比例达到⼀个阈值、窗口时间内降级请求达到⼀定数量的情况下,微服务在一段时间内停止对⽬标服务发起调用,所有来访请求直接执行降级逻辑。所以,熔断是“多次服务调用异常”累积的结果。
在这里插入图片描述

外部流量控制

限流是流量整形流控方案的一种。在 Sentinel 中我们可以根据集群的处理能力,为每个服务设置⼀个限流规则,从 QPS 维度或者并发线程数的维度控制外部的访问流量。⼀旦访问量超过阈值,后续的请求就会被 “fast fail”,这是最为常用的⼀种限流手段。
在这里插入图片描述

Sentinel

在这里插入图片描述
Sentinel是阿里开源的项目,提供了流量控制、熔断降级、系统负载保护等多个维度来保障服务之间的稳定性。

Sentinel 基本概念

资源

资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何内容,例如,由应用程序提供的服务,或由应用程序调用的其它应用提供的服务,甚至可以是一段代码。只要通过 Sentinel API 定义的代码,就是资源,能够被 Sentinel 保护起来。大部分情况下,可以使用方法签名,URL,甚至服务名称作为资源名来标示资源。

规则
围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则。所有规则可以动态实时调整。

Sentinel 的主要特性

在这里插入图片描述
特性:

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

Sentinel 分为两个部分

  • 控制台(Dashboard):Dashboard 主要负责管理推送规则、监控、管理机器信息等。
  • 核心库(Java 客户端):不依赖任何框架/库,能够运行于 Java 8 及以上的版本的运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。

在这里插入图片描述

注意:

Sentinel 可以简单的分为 Sentinel 核心库和 Dashboard。核心库不依赖 Dashboard,但是结合Dashboard 可以取得最好的效果。

Sentinel 是如何工作的

Sentinel 的主要工作机制如下:

  • 对主流框架提供适配或者显示的 API,来定义需要保护的资源,并提供设施对资源进行实时统计和调用链路分析。
  • 根据预设的规则,结合对资源的实时统计信息,对流量进行控制。同时,Sentinel 提供开放的接口,方便您定义及改变规则。
  • Sentinel 提供实时的监控系统,方便您快速了解目前系统的状态。

Sentinel 与 Hystrix、resilience4j 的对比

SentinelHystrixresilience4j
隔离策略信号量隔离(并发线程数限流)线程池隔离/信号量隔离线程池隔离/信号量隔离
熔断降级策略基于响应时间、异常比率、异常数基于异常比率基于异常比率、响应时间
实时统计实现滑动窗口(LeapArray)滑动窗口(基于 RxJava)Ring Bit Buffer
动态规则配置支持多种数据源支持多种数据源有限支持
扩展性多个扩展点插件的形式接口的形式
基于注解的支持支持支持支持
限流基于 QPS,支持基于调用关系的限流有限的支持Rate Limiter
流量整形支持预热模式、匀速器模式、预热排队模式不支持简单的 Rate Limiter 模式
系统自适应保护支持不支持不支持
控制台提供开箱即用的控制台,可配置规则、查看秒级监控、机器发现等简单的监控查看不提供控制台,可对接其它监控系统

安装Sentinel控制台

Sentinel 提供一个轻量级的开源控制台,它提供机器发现以及健康情况管理、监控(单机和集群),规则管理和推送的功能。

Sentinel 控制台包含如下功能

  • 查看机器列表以及健康情况:收集 Sentinel 客户端发送的心跳包,用于判断机器是否在线。
  • 监控 (单机和集群聚合):通过 Sentinel 客户端暴露的监控 API,定期拉取并且聚合应用监控信息,最终可以实现秒级的实时监控。
  • 规则管理和推送:统一管理推送规则。
  • 鉴权:生产环境中鉴权非常重要。这里每个开发者需要根据自己的实际情况进行定制。

注意:

Sentinel 控制台目前仅支持单机部署。Sentinel 控制台项目提供 Sentinel功能全集示例,不作为开箱即用的生产环境控制台,若希望在生产环境使用请根据文档自行进行定制和改造。

获取 Sentinel 控制台
您可以从https://github.com/alibaba/Sentinel/releases下载最新版本的控制台 jar 包。

启动 Sentinel 控制台

注意:

启动 Sentinel 控制台需要 JDK 版本为 1.8 及以上版本。

#前台运行
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=192.168.47.100:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.6.jar
#后台运行
nohup java -server -Xms64m -Xmx256m -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=192.168.47.100:8080-Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.3.jar >> /opt/sentinel.log 2>&1 &

访问 Sentinel 控制台
在浏览器输入http://192.168.47.100:8080即可,登录用户名密码都是sentinel。
在这里插入图片描述

将应用接入Sentinel

创建工程jjy-payment-sentinel

POM引入依赖

  <dependencies>
    <!--     sentinel依赖-->
    <dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-starter-alibaba-sentinel</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.projectlombok</groupId>
      <artifactId>lombok</artifactId>
    </dependency>
  </dependencies>

编写主启动类

@SpringBootApplication
@Slf4j
public class PaymentSentinelMain8001 {
  public static void main(String[] args) {
    SpringApplication.run(PaymentSentinelMain8001.class,args);
    log.info("************ PaymentSentinelMain8001 启动成功 **********");
   }
}

编写YML配置文件

server:
  port: 8001
spring:
  application:
  #应用名字
   name: cloud-sentinel-payment
  cloud:
   sentinel:
    transport:
    # Sentinel 控制台地址
     dashboard: 192.168.47.100:8080

编写测试controller

@RestController
public class FlowLimitController {

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

查看Sentinel控制层
在这里插入图片描述

注意:

Sentinel采用懒加载,发送一次请求即可。

流量控制概述

在这里插入图片描述
监控应用流量的 QPS 或并发线程数,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。
在这里插入图片描述
流量控制设计理念
流量控制有以下几个角度:

  • 资源的调用关系:例如资源的调用链路,资源和资源之间的关系;
  • 运行指标:例如 QPS、线程池、系统负载等;
  • 控制的效果:例如直接限流、冷启动、排队等。

注意:
Sentinel 的设计理念是让您自由选择控制的角度,并进行灵活组合,从而达到想要的效果。

流控规则
在这里插入图片描述

参数:

  • 资源名 其实就是我们请求的资源路径

  • 针对来源 这个是此流控规则对应那些微服务进行流控管理,一般填写调用方的微服务名称,多个用","分割

  • 阈值类型 一般有2中类型,QPS(每秒的最大请求数2)和线程数(并发线程数)

  • 单机阈值 单机状态下的最大限制值

  • 是否集群 根据实际情况选择

流控模式
在这里插入图片描述

参数:

  • 直接:直接作用于当前资源,如果访问压力大于某个阈值,后续请求将被直接拦下来;
  • 关联:统计与当前资源相关的另一个资源,触发阈值时,对当前资源限流
  • 链路:当指定链路上的访问量⼤于某个阈值时,对当前资源进⾏限流,这⾥的“指定链 路”是细化到 API 级别的限流维度。

流控效果

在这里插入图片描述

参数:

  • 快速失败
    默认的流量控制方式,当QPS超过任意规则的阈值后,新的请求就会被立即拒绝,拒绝方式为抛出FlowException。

  • Warm Up
    即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压。

  • 排队等待
    匀速排队方式会严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法 。这种方式主要用于处理间隔性突发的流量。

流控模式之直接模式

在这里插入图片描述

当 QPS 超过某个阈值的时候,则采取措施进行流量控制。

注意:

若使用除了直接拒绝之外的流量控制效果,则调用关系限流策略(strategy)会被忽略。配置QPS流控规则

在这里插入图片描述

注意:

表示1秒钟内查询1次就ok,若超过1次,就直接快速失败,报默认错误。

在这里插入图片描述

流控模式之关联模式

什么是关联
当关联的资源达到阈值时,就限流自己。

配置关联规则
在这里插入图片描述
预期效果
由于对/update的限流控制采用QPS关联,所以直接访问不会被限流,会发现一直刷新/update不会出现限流,如图:
在这里插入图片描述
但是访问/query设置来QPS直接的策略进行限流,则频繁访问/query会出现限流提示:

在这里插入图片描述
流控模式之链路模式

链路流控模式指的是,当从某个接口过来的资源达到限流条件时,开启限流。它的功能有点类似于针对来源配置项,区别在于:针对来源是针对上级微服务,而链路流控是针对上级接口,也就是说它的粒度更细。

配置示例:

例如有两条请求链路:

/test1 --> /common
/test2 --> /common

如果只希望统计从/test2进入到/common的请求,则可以这样配置:
在这里插入图片描述
实战案例
需求:有查询订单和创建订单业务,两者都需要查询商品。针对从查询订单进入到查询商品的请求统计,并设置限流。
在这里插入图片描述

实现
添加查询商品方法
在支付服务中,给PaymentService类添加一个queryGoods方法:

public void queryGoods(){
  System.err.println("查询商品");
}

查询订单时,查询商品

@GetMapping("/query")
public String queryOrder() {
  // 查询商品
  orderService.queryGoods();
  // 查询订单
  System.out.println("查询订单");
  return "查询订单成功";
}

新增订单
在支付服务的PaymentController中,修改/order/save端点,模拟新增订单:

@GetMapping("/save")
public String saveOrder() {
  // 查询商品
  orderService.queryGoods();
  // 查询订单
  System.err.println("新增订单");
  return "新增订单成功";
}

给查询商品添加资源标记
默认情况下,OrderService中的方法是不被Sentinel监控的,需要我们自己通过注解来标记要监控的方法。

给OrderService的queryGoods方法添加@SentinelResource注解:

@SentinelResource("goods")
public void queryGoods(){ 
  System.err.println("查询商品");
}

簇点链路
链路模式中,是对不同来源的两个链路做监控。但是sentinel默认会给进入SpringMVC的所有请求设置同一个root资源,会导致链路模式失效。我们需要关闭这种对SpringMVC的资源聚合,修改application.yml文件。

spring:
  application:
   name: payment-provider-sentinel
   sentinel:
    transport:
    # Sentinel控制台地址
     dashboard: 192.168.47.100:8480
    # sentnel api端口号 默认 8719
     port: 8719
    # 关闭context整合 
    web-context-unify: false

重启服务,访问query和save,可以查看到sentinel的簇点链路规则中,出现了新的资源。
在这里插入图片描述

添加流控规则
点击goods资源后面的流控按钮,在弹出的表单中填写下面信息
在这里插入图片描述

流控效果之预热

在这里插入图片描述
warm up也叫预热模式,是应对服务冷启动的一种方案。

案例实战
需求:给/payment/index这个资源设置限流,最大QPS为10,利用warm up效果,预热时长为5秒。
在这里插入图片描述
Jmeter测试
在这里插入图片描述
查看结果树
在这里插入图片描述

注意:

QPS为10.刚刚启动时,大部分请求失败,成功的只有3个,说明QPS被限定在3,随着时间推移,成功比例越来越高。

流控效果之排队等待

排队等待则是让所有请求进入一个队列中,然后按照阈值允许的时间间隔依次执行。后来的请求必须等待前面执行完成,如果请求预期的等待时间超出最大时长,则会被拒绝。

工作原理
例如:QPS阈值为5,意味着每200ms处理一个队列中的请求,超时时间2s,现在有100个请求过来,服务器最多处理 5 个,其他慢慢排队,timeout = 2S,意味着预期等待时长超过2S的请求会被拒绝并抛出异常。
在这里插入图片描述
假如不使用排队等待模式,现在有12个请求过来,第1秒同时接收到10个请求,但第2秒只有1个请求,此时QPS的曲线这样的。
在这里插入图片描述
如果使用队列模式做流控,所有进入的请求都要排队,以固定的200ms的间隔执行,QPS会变的很平滑。
在这里插入图片描述

注意:

平滑的QPS曲线,对于服务器来说是更友好的。

应用场景
在这里插入图片描述

注意:

这种方式主要用于处理间隔性突发的流量,例如消息队列。想象一下这样的场景,在某一秒有大量的请求到来,而接下来的几秒则处于空闲状态,我们希望系统能够在接下来的空闲期间逐渐处理这些请求,而不是在第一秒直接拒绝多余的请求。

案例
需求:给/payment/queue这个资源设置限流,最大QPS为10,利用排队的流控效果,超时时长设置为5s。
在这里插入图片描述
Jmeter测试
在这里插入图片描述
QPS为15,已经超过了我们设定的10。如果是之前的快速失败、warmup模式,超出的请求应该会直接报错。但是我们看看队列模式的运行结果:
在这里插入图片描述

热点参数限流

在这里插入图片描述

什么是热点
热点即经常访问的数据。

热点参数限流
给/findById这个资源添加热点参数限流,规则如下:

  • 默认的热点参数规则是每1秒请求量不超过2
  • 给102这个参数设置例外:每1秒请求量不超过4
  • 给103这个参数设置例外:每1秒请求量不超过10

注意事项:

热点参数限流对默认的SpringMVC资源无效,需要利用@SentinelResource注解标记资源

@RestController
public class GoodsController {
/**
   * 热点key限流
   * @param id
   * @return
   */
  @SentinelResource("hot")
  @GetMapping("findById")
  public Long getGoods(Long id){
    return id;
   }
}

热点参数限流规则
在这里插入图片描述
Jmeter测试

在这里插入图片描述

线程隔离

限流是一种预防措施,虽然限流可以尽量避免因高并发而引起的服务故障,但服务还会因为其它原因而故障。而要将这些故障控制在一定范围,避免雪崩,就要靠线程隔离(舱壁模式)和熔断降级手段了。

线程隔离(舱壁模式)

  • 线程池隔离
  • 信号量隔离(Sentinel默认采用)
    在这里插入图片描述

注意:

  • 线程池隔离:给每个服务调用业务分配一个线程池,利用线程池本身实现隔离效果
  • 信号量隔离:不创建线程池,而是计数器模式,记录业务使用的线程数量,达到信号量上限时,禁止新的请求。

sentinel的线程隔离
在添加限流规则时,可以选择两种阈值类型:
在这里插入图片描述

注意:

  • QPS:每秒的请求数
  • 线程数:该资源能使用用的Tomcat线程数的最大值。也就是通过限制线程数量,实现线程隔离(舱壁模式)。

流控测试

新建线程组
我们新建一个线程组,在启动的时候同时发送10个请求,如下所示:
在这里插入图片描述
新建HTTP请求
在这里插入图片描述
创建查看结果树
在这里插入图片描述

熔断降级

熔断降级是解决雪崩问题的重要手段。其思路是由断路器统计服务调用的异常比例、慢请求比例,如果超出阈值则会熔断该服务。即拦截访问该服务的一切请求;而当服务恢复时,断路器会放行访问该服务的请求。

断路器控制熔断和放行是通过状态机来完成的:
在这里插入图片描述

状态机包括三个状态:

  • closed:关闭状态,断路器放行所有请求,并开始统计异常比例、慢请求比例。超过阈值则切换到open状态
  • open:打开状态,服务调用被熔断,访问被熔断服务的请求会被拒绝,快速失败,直接走降级逻辑。Open状态5秒后会进入half-open状态
  • half-open:半开状态,放行一次请求,根据执行结果来判断接下来的操作。 请求成功:则切换到closed状态 请求失败:则切换到open状态

熔断降级策略
慢调用
业务的响应时长(RT)大于指定时长的请求认定为慢调用请求。在指定时间内,如果请求数量超过设定的最小数量,慢调用比例大于设定的阈值,则触发熔断。

异常比例、异常数
统计指定时间内的调用,如果调用次数超过指定请求数,并且出现异常的比例达到设定的比例阈值(或超过指定异常数),则触发熔断。

熔断降级策略

慢调用
业务的响应时长(RT)大于指定时长的请求认定为慢调用请求。在指定时间内,如果请求数量超过设定的最小数量,慢调用比例大于设定的阈值,则触发熔断。

异常比例、异常数
统计指定时间内的调用,如果调用次数超过指定请求数,并且出现异常的比例达到设定的比例阈值(或超过指定异常数),则触发熔断。

熔断降级之慢调用

在这里插入图片描述
平均响应时间当1s内持续进入5个请求,对应时刻的平均响应时间(秒级)均超过阈值,那么在接下的时间窗口之内,对这个方法的调用都会自动地熔断(抛出DegradeException )。

新增接口

  @GetMapping("/testC")
  public String testC(Integer id){
    if (id = 1){
     try {
      TimeUnit.SECONDS.sleep(1);
     } catch (InterruptedException e) {
      e.printStackTrace();
     } 
     }
    return "------------testC";
   }

新增RT配置
在这里插入图片描述

参数:

超过50ms的请求都会被认为是慢请求,当异常比例达到百分之40,断路器打开(保险丝跳闸)微服务不可用,保险丝跳闸断电了。过5秒钟由断路器又打开状态变为半开状态放一部分请求进来。

Jemeter压力测试
创建线程组
在这里插入图片描述
设置HTTP请求路径
在这里插入图片描述
测试
未使用Jemeter情况下测试/testC接口
在这里插入图片描述
使用Jemeter情况下测试/testC接口。
在这里插入图片描述
结果访问失败
在这里插入图片描述

注意:

后续我停止Jmeter,没有这么大的访问量了,断路器关闭(保险丝恢复),微服务恢复OK。

熔断降级之异常比例

在这里插入图片描述
概述
当资源每秒异常总数占通过量的比值超过阈值之后,资源进入降级状态。异常比率的阈值范围是 [0.0,1.0]。

新增接口

/**
   * 测试异常比例
   * RT 平均响应时间
   * @return
   */
  @GetMapping("testD")
  public String testD(Integer id)  {
    if (id == 1){
      throw new RuntimeException("故意抛出异常,触发异常比例熔断。");
     }
    return "testD";
   }

设置熔断规则
在这里插入图片描述

注意:

在5次请求中,只要异常比例超过0.4,也就是有2次以上的异常,就会触发熔断。

Jemeter压力测试

创建线程组
在这里插入图片描述
配置HTTP请求
在这里插入图片描述
测试接口
发送请求localhost:8001/testD?id=2
在这里插入图片描述

熔断降级之异常数

在这里插入图片描述
概念
异常数:当资源近1分钟的异常数目超过阈值之后会进行熔断。

新增接口

  /*
   * 测试异常数
   */
  @GetMapping("/testF")
  public String testF()
   {
    int age = 10/0;
    return "------testF 测试异常数";
   }

配置异常数规则
在这里插入图片描述

注意:

设置异常数5。

测试
请求http://localhost:8001/testF,第一次访问绝对报错,因为除数不能为零, 我们看到error窗口
在这里插入图片描述
但是达到5次报错后,进入熔断后降级。
在这里插入图片描述

授权规则

在这里插入图片描述
授权规则
授权规则可以对调用方的来源做控制,有白名单和黑名单两种方式。

  • 白名单:来源(origin)在白名单内的调用者允许访问
  • 黑名单:来源(origin)在黑名单内的调用者不允许访问
    点击左侧菜单的授权,可以看到授权规则:

在这里插入图片描述

  • 资源名:就是受保护的资源,例如/payment/{query}

  • 流控应用:是来源者的名单,

  • 如果是勾选白名单,则名单中的来源被许可访问。

  • 如果是勾选黑名单,则名单中的来源被禁止访问。

  • 在这里插入图片描述

注意:

我们允许请求从gateway到payment服务,不允许浏览器访问payment,那么白名单中就要填写网关的来源名称(origin)。

案列实现
POM文件引入依赖

<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">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>com.itbaizhan</groupId>
    <artifactId>itbaizhan_cloud2</artifactId>
    <version>1.0-SNAPSHOT</version>
  </parent>


  <artifactId>itbaizhan-payment-sentinel</artifactId>
  <packaging>jar</packaging>


  <name>itbaizhan-payment-sentinel</name>
  <url>http://maven.apache.org</url>


  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>


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


启动Higress网关服务

创建配置文件
添加naocs连接配置。

server:
 # 端口号
  port: 8787
spring:
  application:
  # 应用名字
   name: payment-sentinel
  cloud:
   nacos:
    discovery:
     # Nacos注册中心的地址
     server-addr: 192.168.47.100:8848
   sentinel:
    transport:
    # sentinel 控制台得地址
     dashboard: 192.168.47.100:8480
    # 关闭context整合
    web-context-unify: false


测试网关服务

发送请求http://localhost:9090/payment/query
在这里插入图片描述
如何获取origin
在这里插入图片描述
Sentinel是通过RequestOriginParser这个接口的parseOrigin来获取请求的来源的。

public interface RequestOriginParser {
  /**
   * 从请求request对象中获取origin,获取方式自定义
   */
  String parseOrigin(HttpServletRequest request);
}

注意:

这个方法的作用就是从request对象中,获取请求者的origin值并返回。默认情况下,sentinel不管请求者从哪里来,返回值永远是default,也就是说一切请求的来源都被认为是一样的值default。因此,我们需要自定义这个接口的实现,让不同的请求,返回不同的origin。

支付微服务定义一个RequestOriginParser的实现类

package cn.itcast.order.sentinel;


import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;


import javax.servlet.http.HttpServletRequest;


@Component
public class HeaderOriginParser implements RequestOriginParser {
  @Override
  public String parseOrigin(HttpServletRequest request) {
    // 1.获取请求头
    String origin = request.getHeader("origin");
    // 2.非空判断
    if (StringUtils.isEmpty(origin)) {
      origin = "blank";
     }
    return origin;
   }
}


给网关添加请求头
既然获取请求origin的方式是从reques-header中获取origin值,我们必须让所有从gateway路由到微服务的请求都带上origin头。

在这里插入图片描述
头,值为gateway。而从其它地方到达微服务的请求则没有这个头。

配置授权规则
接下来,我们添加一个授权规则,放行origin值为gateway的请求。
在这里插入图片描述
配置规则
在这里插入图片描述
测试网关请求
请求localhost:9090/payment/query
在这里插入图片描述
测试非网关请求

在这里插入图片描述

系统自适应限流

引入系统自适应限流的主要的目的

  • 保证系统不被拖垮
  • 在系统稳定的前提下保证系统的吞吐量。
    系统规则

Sentinel的系统保护规则是从应用级别的入口流量进行控制,从单台机器的 load、CPU 使用率、平均 RT、入口 QPS 和并发线程数等几个维度监控应用指标,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
在这里插入图片描述
系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量生效。入口流量指的是进入应用的流量(EntryType.IN),比如 Web 服务或 Dubbo 服务端接收的请求,都属于入口流量。
在这里插入图片描述
系统规则支持以下的模式

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

配置系统规则

在这里插入图片描述
添加规则
在这里插入图片描述

查看cpu核数

cat /proc/cpuinfo | grep “processor” | wc -l

SentinelResource注解配置详解之只配置fallback

服务降级功能,但是只是限制后,返回不可控的结果肯定是不行的,我们还要保证调用者在调用那些被限制的服务时候,不管是不是被限制,都要让他们拿到一个合理的结果,而不是扔回去一个异常就完事了。

Sentinel提供了这样的功能,让我们可以另外定义一个方法来代替被限制或异常服务返回数据,这就是fallback和blockHandler

  • fallback:针对Java本身出现的异常进行处理的对应属性。
  • blockHandler:针对违反Sentinel控制台配置规则时触发BlockException异常时对应处理的属性
    @SentinelResource注解用于定义资源,并提供可选的 BlockException 异常处理(仅处理Sentinel控制台配置相关异常) 和 fallback 配置项(运行时异常以及自定义异常)。

注解属性

  • value:资源名称,必需项(不能为空)
  • entryType:entry 类型,可选项(默认为 EntryType.OUT
  • blockHandler / blockHandlerClass: blockHandler 对应处理 BlockException 的函数名称,可选项。blockHandler 函数访问范围需要是 public,返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为 BlockException。blockHandler 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 blockHandlerClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
  • fallback / fallbackClass :fallback 函数名称,可选项,通常用于通用的 fallback 逻辑(即可以用于很多服务或方法)。默认 fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。若同时配置了 fallback 和 defaultFallback,则只有 fallback 会生效。
  • defaultFallback(since 1.6.0):默认的 fallback 函数名称
  • exceptionsToIgnore(since 1.6.0):用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。

只配置fallback
此回调是针对接口出现异常了,就进入此fallback方法。

  /**
   * 根据id查询支付信息
   * @param id
   * @return
   */
  @SentinelResource(value = "testfallback",fallback = "testFallback")
  @GetMapping("findById")
  public String findById(String id){
    if (id.equals("1")){
      throw new RuntimeException("出异常了。");
     }
    return iPaymentFeginService.findById(id);
   }
// 降级
  public String testFallback(String id,Throwable e){
    return "系统异常了";
   }

代码看出,只要请求http://localhost:80/order/findById?id=1 ,接口就会报异常,继而会调用fallback中的方法,走到了testFallback方法中。

外置类
fallback 函数位置是有要求的,必须和原方法在同一个类中,但在实际需求中,我们需要放在其他类中。@SentinelResource提供了通过fallbackClass指定对应的类的Class对象,添加一个static,否则无法解析。

@Component
public class PaymentServiceFallback  {
  /**
   * 降级方法
   * @return
   */
  public static String findByIdFallBalk(String id,Throwable e) {
    return "支付系统服务繁忙稍等一会~~~~";
   }
}

修改注解

  @SentinelResource(value = "testfallback",fallbackClass = PaymentServiceFallback.class,fallback = "findByIdFallBalk")
  @GetMapping("findById")
  public String findById(String id){
    if (id.equals("1")){
      throw new RuntimeException("出异常了。");
     }
    return iPaymentFeginService.findById(id);
   }

SentinelResource配置详解之只配置blockHandler

超出流量限制的部分是否会进入到blockHandler的方法,要注意是超出流量限制的请求调用,会进入blockHandler方法。

  /**
   * 根据id查询支付信息
   * @param id
   * @return
   */
  @SentinelResource(value = "testfallback",blockHandler = "testblockHandler")
  @GetMapping("findById")
  public String findById(String id){
    if (id.equals("1")){
      throw new RuntimeException("出异常了。");
     }
    return iPaymentFeginService.findById(id);
  

降级处理

  /**
   * 降级处理
   * @param id
   * @param e
   * @return
   */
  public String testblockHandler(String id,BlockException e){
    return "限流降级处理";
   }

外置类

  /**
   * 降级处理
   * @param id
   * @param e
   * @return
   */
   public Static String testblockHandler(String id,BlockException e){
     return "限流降级处理";
   }

总结

  • 流控的blockHandler自定义资源必须为public static 函数 @SentinelResource注解的value与@RequestMapping的value不一样
  • 流控规则配置的资源名与@SentinelResource注解的value保持一致,才会执行@SentinelResource注解里定义的兜底方法
  • 注意blockHandler 是对应处理 BlockException 的函数,而不是BlockedException

SentinelResource配置详解之fallback和blockHandler都配置

  /**
   * 根据id查询支付信息
   * 测试fallback
   * @param id
   * @return
   */
  @SentinelResource(value = "orderfindById",
//       fallback = "testFallBack",fallbackClass = PaymentServiceFallback.class)
      fallback = "testFallBack",fallbackClass = PaymentServiceFallback.class,
      blockHandler = "testBlockHeader",blockHandlerClass = PaymentServiceFallback.class)
  @GetMapping("findById")
  public String test(String id){
    if (id.equals("1")){
      throw new RuntimeException("制造接口异常.");
     }


    return iPaymentFeginService.findById(id);
   }

总结

  • fallback是针对方法出现异常了,则会进入fallback方法。
  • blockhandler是针对流控设置,超出规则,则会进入blockhandler方法。
  • blockHandler 和 fallback 都进行了配置,则被限流降级而抛出BlockException时只会进入 blockHandler 处理逻辑。
  • 若未配置 blockHandler、fallback 和 defaultFallback,则被限流降级时会将 BlockException 直接抛出。

如果我的内容对你有帮助,请点赞,评论,收藏。创作不易,大家的支持就是我坚持下去的动力
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

中北萌新程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值