目录
分布式流量防护_授权规则
分布式流量防护_系统自适应限流
分布式流量防护_SentinelResource注解配置详解之只配 置fallback
分布式流量防护_SentinelResource配置详解之只配置 blockHandler
授权规则
授权规则可以对调用方的来源做控制,有白名单和黑名单两种方式。
1、白名单:来源(origin)在白名单内的调用者允许访问
2、黑名单:来源(origin)在黑名单内的调用者不允许访问
点击左侧菜单的授权,可以看到授权规则:
资源名:就是受保护的资源,例如/payment/{query}
流控应用:是来源者的名单,
如果是勾选白名单,则名单中的来源被许可访问。
如果是勾选黑名单,则名单中的来源被禁止访问。
注意: 我们允许请求从gateway到payment服务,不允许浏览器访问 payment,那么白名单中就要填写网关的来源名称 (origin)。
案列实现
创建网关工程cloud-gateway9090
POM文件引入依赖
org.springframework.boot
spring-boot-starter
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
org.springframework.cloud
spring-cloud-starter-gateway
org.projectlombok
lombok
org.springframework.cloud
spring-cloud-starter-loadbalancer
编写主启动类
@EnableDiscoveryClient
@SpringBootApplication
@Slf4j
public class Gateway9090 {
public static void main(String[] args) {
SpringApplication.run(Gateway9090.class,args);
log.info("********** Gateway9090 启动成功 *********");
}
}
创建配置文件
server:
port: 9090
spring:
application:
name: gateway
cloud:
nacos:
discovery:
server-addr: 192.168.66.100:8848
gateway:
routes:
- id: payment
uri: lb://payment-provider-sentinel
predicates:
- Path=/payment/*
测试网关服务
发送请求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头。
spring:
cloud:
gateway:
default-filters:
- AddRequestHeader=origin,gateway
注意: 这样,从gateway路由的所有请求都会带上origin头,值为 gateway。而从其它地方到达微服务的请求则没有这个头。
配置授权规则
接下来,我们添加一个授权规则,放行origin值为gateway的请求。
配置规则
测试网关请求
请求localhost:9090/payment/query
测试非网关请求
实时效果反馈
1.Sentinel是通过_______这个接口的parseOrigin来获取请求的来源的。
A Origin
B RequestOrigin
C RequestOriginParser
D 以上都是错误
引入系统自适应限流的主要的目的
1、保证系统不被拖垮
2、在系统稳定的前提下保证系统的吞吐量。目前我们接触的限流的防护思路都是设定一个指标(阈 值),例如系统的负载 load 超过某个阔值后就阻止或减少流量的继续进入,当系统负载降低到某 一水平后则恢复流量的进入。通常都是被动的,其实际效果取决于阈值设置是否合理,但往往设置 合理不是一件容易的事情。
系统规则
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 达到阈值即触发系统保护。
配置系统规则
添加规则
实时效果反馈
1.Sentinel中系统自适应限流主要目的是____。
A 在保证稳定的前提下,保持系统的最大吞吐量
B 减少响应时间
C 解决高并发问题
D 解决服务雪崩
2.Sentinel系统保护规则是___整体维度的,而不是__维度的,并且 仅对入口流量生效。
A 资源、接口
B 接口、方法
C 应用、资源
D 应用、接口
服务降级功能,但是只是限制后,返回不可控的结果肯定是不行的,我们还要保证调用者在调用那些被限制的服务时候,不管是不是被限制,都要让他们拿到一个合理的结果,而不是扔回去一个异常就完事了。
Sentinel提供了这样的功能,让我们可以另外定义一个方法来代替 被限制或异常服务返回数据,这就是fallback和blockHandler。
1、fallback:若本接口出现未知异常,则调用fallback指定的接口。
2、blockHandler:若本次访问被限流或服务降级,则调用blockHandler指定的接口。
@SentinelResource注解用于定义资源,并提供可选的 BlockException 异常处理(仅处理Sentinel控制台配置相关异常) 和fallback 配置项(运行时异常以及自定义异常)。
注解属性
1、value :资源名称,必需项(不能为空)
2、entryType :entry 类型,可选项(默认为 EntryType.OUT )
3、blockHandler / blockHandlerClass : blockHandler 对应处理 BlockException 的函数名称,可选 项。blockHandler 函数访问范围需要是 public ,返回类型需要与原方法相匹配,参数类型需要和 原方法相匹配并且最后加一个额外的参数,类型为 BlockException 。blockHandler 函数默认需要 和原方法在同一个类中。若希望使用其他类的函数,则可以指定 blockHandlerClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
4、fallback / fallbackClass :fallback 函数名称,可选项,通常用于通用的 fallback 逻辑(即可以用于 很多服务或方法)。默认 fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面 排除掉的异常类型)进行处理。若同时配置了 fallback 和 defaultFallback,则只有 fallback 会生效。
5、defaultFallback (since 1.6.0):默认的 fallback 函数名称
6、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);
}
实时效果反馈
1.Sentinel中SentinelResource注解属性falllback处理____异常。
A 热点异常
B 限流异常
C 权限异常
D 接口异常
超出流量限制的部分是否会进入到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 "限流降级处理";
}
总结
1、流控的blockHandler自定义资源必须为public static 函数 @SentinelResource注解的value与@RequestMapping的value不一样
2、流控规则配置的资源名与@SentinelResource注解的value保持一致,才会执行 @SentinelResource注解里定义的兜底方法
3、注意blockHandler 是对应处理 BlockException 的函数,而不是BlockedException
实时效果反馈
1.Sentinel中SentinelResource注解属性blackHeader处理____异 常。
A 热点异常
B 限流异常
C 权限异常
D Sentinel控制台配置相关异常