8.17日学习打卡
目录:
- 8.17日学习打卡
- 分布式流量防护
- 什么是服务雪崩
- 解决方案
- 内部异常治理
- 外部流量控制
- Sentinel
- Sentinel 基本概念
- Sentinel 的主要特性
- Sentinel 是如何工作的
- Sentinel 与 Hystrix、resilience4j 的对比
- 安装Sentinel控制台
- 将应用接入Sentinel
- 流量控制概述
- 流控模式之直接模式
- 流控模式之关联模式
- 流控效果之预热
- 流控效果之排队等待
- 热点参数限流
- 线程隔离
- 流控测试
- 熔断降级
- 熔断降级策略
- 熔断降级之慢调用
- 熔断降级之异常比例
- 熔断降级之异常数
- 授权规则
- 系统自适应限流
- SentinelResource注解配置详解之只配置fallback
- SentinelResource配置详解之只配置blockHandler
- SentinelResource配置详解之fallback和blockHandler都配置
分布式流量防护
在分布式系统中,服务之间的相互调用会生成分布式流量。如何通过组件进行流量防护,并有效控制流量,是分布式系统的技术挑战之一。
什么是服务雪崩
假设我有一个微服务系统,这个系统内包含了 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 的对比
Sentinel | Hystrix | resilience4j | |
---|---|---|---|
隔离策略 | 信号量隔离(并发线程数限流) | 线程池隔离/信号量隔离 | 线程池隔离/信号量隔离 |
熔断降级策略 | 基于响应时间、异常比率、异常数 | 基于异常比率 | 基于异常比率、响应时间 |
实时统计实现 | 滑动窗口(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 直接抛出。
如果我的内容对你有帮助,请点赞,评论,收藏。创作不易,大家的支持就是我坚持下去的动力