接上:
SpringCloud 之 feign_初涉人事。。。-优快云博客
什么是Sentinel?
是阿里开源的一套用于服务容错的总和性解决方案,它以流量为切入点。
从流量控制、熔断降级、系统负载保护等多个纬度来保护服务的稳定性。
容错的思想:
1、保证自己不被上游服务压垮 例如: 限流,减少单位时间内的访问量
2、保证自己不被下游服务拖垮 例如:熔断降级,减少或者不访问下游,等下游正常再访问
3、保证外界环境良好 例如:服务器、cpu、内存
Sentinel特征:介绍 · alibaba/Sentinel Wiki · GitHub
1、丰富的应用场景
如秒杀(突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等
2、完备的实时监控
sentinel提供了实时监控功能。通过控制台可以看到接入应用的单台机器秒级数据,甚至500台一下规模的集群的汇总运行情况
3、广泛的开源生态
提供了开箱即用与其他开源库/框架的整合,如:SpringCloud、dubbo、grpcdeng
只要引入相应的依赖进行简单的配置即可快读的接入
4、完善的SPI扩展
提供了简单、易用、完善的SPI扩展接口,可以通过实现扩展接口来快速定值逻辑。
如定值规则管理、适配动态数据源等
Sentinel分为两个部分:
核心库: 不依赖任何框架/库能够运行与所有java运行时环境,同时对Dubbo/SpringCloud等框架也有较好的支持
控制台:基于springboot开发,打包后可直接运行,不需要额外的Tomcat等应用容器
控制台:
Releases · alibaba/Sentinel · GitHub
直接下载jar包运行即可
或者git下载项目找到sentinel-dashboard 添加端口 直接运行
访问:localhost:端口
用户名密码默认都是:sentinel
集成:
在项目中引入依赖:
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency>
配置文件:
spring:
cloud:
sentinel:
transport:
port: 8081 #可随意指定一个不冲突的端口,用于跟控制台交流的端口
dashboard: localhost:8080 # 指定控制台服务
重启服务:如果刷新还是没有数据,那就访问一下对应的服务,跟sentinel的加载机制有关
刷新sentinel控制台
sentinel 基本概念和功能
资源:
资源就是sentinel要保护的东西。
资源是sentinel的关键概念,它可以是java应用程序中的任何内容,可以是一个服务、一个方法、一段代码
规则:
作用在资源之上,定义以什么样的方式保护资源,主要包括:
流量控制规则、熔断降级规则、系统保护规则
sentinel 主要功能
sentinel的主要功能就是容错,主要提现在下面三种方式
1、流量控制:
sentinel可以根据需要把随机的请求调整成合适的形式
2、熔断降级:
检测到调用链路中某个资源出现不稳定的表现(如:请求响应时间长或者异常比例升高),则对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源导致级联故障
sentient对熔断提供了两种方案:
1:通过并发线程数进行限制
2:通过响应时间对资源进行降级。通过响应时间来快速降级不稳定的资源,当依赖的资源出现响应故障后,所有对该资源的访问都会被直接拒绝,直到符合指定的时间窗口之后才会重新回复
与hystrix:
相同点:原则是一致的,当一个资源出现问题时快速让其失败,不波及到其他服
区别:
hystrix采用的是线程池的隔离方式,优点是做到了资源之间的隔离,缺点是增加了线程切换成本
sentinel 采用的是通过并发线程的数量和响应时间来对资源做限制
3、系统负载保护
当系统负载较高的时候,还持续进行访问,可能导致系统崩溃,无法响应,在集群环境下,会把本应当前机器成灾的流量转发到其他的机器上去,如果其他机器也处于一个边缘状态,sentinel会提供对应的保护机制,让系统的入口流量和系统的负载达到一个平衡,保证系统在能力范围内处理最多的请求
总之对sentinel的使用最多的就是对sentinel的资源上进行各种规则配置,来实现各种容错的功能
sentinel规则
1、流控规则
流量控制,原理是监控应用流量的QPS(每秒查询频率)或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用
1.1、点击簇点链路---》流控
规则设置:
资源名:唯一名称,默认是请求路径,可自定义
针对来源:指定对哪个服务进行限流,默认是不区分,全部限制。(A、B 服务对C服务访问,可设置A的流量是多少,B又是多少,可分开限制,如果默认,则全部限制)
阈值类型/单机阈值:
QPS:(每秒请求数量),当该接口QPS达到阈值时,进行限流
线程数据:当调用接口的线程达到阈值的时候,进行限流
流控模式:
直接:默认,接口达到限流条件时,开启限流
关联:当关联的资源达到限流条件时,开启限流
例:接口a关联接口b当接口b达到限流时a接口开启限流
适合用于查询和更新接口关联,当更新接口达到阈值时,限制查询
链路:当从某个接口过来的资源达到限流条件时,开启限流,针对的是上级接口/微服务
链路需要在业务层添加注解,控制其中多个方法访问该接口
实际测试:
链路不生效
解决方式:
配置文件添加配置:
cloud: sentinel: filter: enabled: false添加filter配置:
package wdz.order.config; import com.alibaba.csp.sentinel.adapter.servlet.CommonFilter; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class SentinelFilterContextConfig { @Bean public FilterRegistrationBean sentinelFilterRegistration(){ FilterRegistrationBean filter = new FilterRegistrationBean(); filter.setFilter(new CommonFilter()); filter.addUrlPatterns("/*"); // 入口资源关闭聚合 filter.addInitParameter(CommonFilter.WEB_CONTEXT_UNIFY,"false"); filter.setName("sentinelFilter"); filter.setOrder(1); return filter; } }
生效结果:如果测试阈值超过了设置的阈值则快速报错
流控效果:
快速失败:
在阈值以外的数据,直接失败,抛出异常,不做任何额外的处理
Warm Up:
它从开始阈值到最大QPS有一个缓冲阶段,一开始的阈值时最大QPS的1/3,然后慢慢增长到最大阈值,适用于将突然增大的流量转换为缓步增长的场景
排队等待:
让请求均匀的通过,超过阈值的请求排队等待,当请求超过预设超时时间还未处理的,则会被丢弃
熔断规则:
降级策略:
RT:平均响应时间:当资源的平均响应时间超过阈值(单位:ms)之后,资源进入准降级状态。在之后的时间窗口内(单位:s)就会对这个资源进行服务降级. 最大RT值:4900ms,如果超过这个值默认读取这个参数,如果要配置该参数,通过启动配置项来更改:-Dscp.sentinel.statistic.max.rt=******* 来配置
例如:当平均响应时间>1ms的时候,接下来的10s内服务降级,10s之后服务恢复,进行下一轮的判断
异常比例:
挡子源的每秒异常总数占通过量的比值超过阈值之后,资源进行降级状态。即在接下的时间窗口(单位:s)之内,对这个方法的调用都会自动返回,异常比率的阈值范围是[0,0,1,0]
异常数:
在统计的时间内有超过当前设置的异常数时,并且最小请求为5个,降级5秒,5秒之后恢复正常,进行新的一轮判断
热点规则:
注意热点规则必须在方法上添加资源注解
热点必须添加在资源注解上,否则不生效,如下配置只对接口参数索引为0的(param1)也就是请求中包含第一个参数的接口在阈值之外进行限制,而不包含索引0param1)参数的请求正常访问
以上是对参数进行熔断的,下面的是直接对参数值进行熔断,当参数值为123时超过阈值进行熔断,其他参数则根据上边的熔断规则进行熔断
授权规则:
流控应用:
该参数自定义即可,请求时可存放于request中,方便获取即可
后台代码:
package wdz.order.config; import com.alibaba.csp.sentinel.adapter.servlet.callback.RequestOriginParser; import org.apache.commons.lang3.StringUtils; import org.springframework.context.annotation.Configuration; import javax.servlet.http.HttpServletRequest; /** * sentinel 授权规则配置 */ @Configuration public class SentinelOriginAuthConfig implements RequestOriginParser { /** * 定义区分来源 * 本职作用是通过request域来获取来源标识 * 所以这个来源标识和自定义进行配置,存放与请求头/请求体 */ @Override public String parseOrigin(HttpServletRequest request) { // 如果使用授权方式,则该参数必须传递,否则无效 String applicationName = request.getParameter("applicationName"); if (StringUtils.isEmpty(applicationName)){ throw new RuntimeException("applicationName不能为空"); } return applicationName; } }
配置之后 黑白名单相反,符合条件的直接通过,否则抛出异常
以上的流控、热点、熔断、授权都是对上游/下游的配置,满足容错思想的1和2
系统授权规则
该规则则是满足于容错思想的3,系统环境的影响
系统保护规则是从应用级别的入口流量进行控制。从单台机器的总体Load、RT、入口QPS、CPU使用率和线程数五个纬度监控应用数据。让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
系统保护规则是应用整体维度的,不是上边的资源纬度的,并且仅对入口流量(进入应用的流量)生效。
Load:仅对Linux/Unix-like机器生效,当系统load1超过阈值,且系统当前的并发线程超过系统容量时才会触发系统保护,系统容量有系统的maxQPS*minRT计算得出,设定参考值一般是CPU cores*2.5
RT:当单台机器上所有入口流量的平均RT达到阈值即触发系统保护,单位是毫秒。
线程数:当单台机器上所有入口流量的并发线程数达到阈值及触发系统保护
入口QPS:当单台机器上所有入口流量的QPS达到阈值,即触发系统保护
CPU使用率:单台机器上所有入口流量的CPU使用率达到阈值即触发系统保护
自定义触发保护时的异常返回:
package wdz.order.config;
import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlBlockHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import com.alibaba.csp.sentinel.slots.system.SystemBlockException;
import com.alibaba.fastjson.JSONObject;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* sentinel 触发保护之后返回信息处理
*/
@Component
public class SentinelExceptionPage implements UrlBlockHandler {
@Override
public void blocked(HttpServletRequest request, HttpServletResponse response, BlockException e) throws IOException {
// 中文乱码问题
response.setContentType("application/json;charset=utf-8");
ResponseData data = null;
if (e instanceof FlowException) {
data = new ResponseData(-1,"资源限流异常");
}else if (e instanceof DegradeException) {
data = new ResponseData(-1,"资源降级异常");
}else if (e instanceof ParamFlowException) {
data = new ResponseData(-1,"资源参数限流异常");
}else if (e instanceof AuthorityException) {
data = new ResponseData(-1,"资源授权异常");
}else if (e instanceof SystemBlockException) {
data = new ResponseData(-1,"系统负载异常");
}
response.getWriter().write(JSONObject.toJSONString(data));
}
}
@Data
@AllArgsConstructor // 全参构造
@NoArgsConstructor // 无参构造
class ResponseData {
private int code;
private String message;
}
测试结果:
@SentinelResource作用
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.alibaba.csp.sentinel.annotation;
import com.alibaba.csp.sentinel.EntryType;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface SentinelResource {
// 资源名称
String value() default "";
EntryType entryType() default EntryType.OUT;
int resourceType() default 0;
// 定义当资源内部发生了BlockException 应该进入的方法,捕获的是Sentinel定义的异常
String blockHandler() default "";
// 定义当资源内部发生了BlockException 应该进入的公用handler类
Class<?>[] blockHandlerClass() default {};
// 定义当资源内部发生了Throwable 应该进入的方法
String fallback() default "";
String defaultFallback() default "";
// 定义当资源内部发生了Throwable 应该进入的类 用于
Class<?>[] fallbackClass() default {};
Class<? extends Throwable>[] exceptionsToTrace() default {Throwable.class};
Class<? extends Throwable>[] exceptionsToIgnore() default {};
}
1:定义一个资源
2:定义当资源内部发生异常时的处理逻辑,建议使用
fallback处理指定方法的所有异常处理@RequestMapping("heart") @SentinelResource(value = "heart-sentinel", blockHandler = "blockHandler", fallback = "fallback") public String heart(String param1, String param2) { return param1 + param2; } /** * 处理的是SentinelResource中定义的5个异常 * 要求: * 1:返回参数必须与SentinelResource注解所在的方法返回值一致,接收的参数一致 * 2:方法名必须与注解中blockHandler属性值一致 * <p> * 允许参数在参数列表的最后加入一个参数BlockExceprion,用来接收原方法中发生的异常 * * @return */ public String blockHandler(String param1, String param2, BlockException exceprion) { // 自定义异常业务处理 log.info("-----异常BlockException----:{}", exceprion); return "BlockException"; } /** * 处理的是所有的异常 * 要求: * 1:返回参数必须与SentinelResource注解所在的方法返回值一致,接收的参数一致 * 2:方法名必须与注解中blockHandler属性值一致 * <p> * 允许参数在参数列表的最后加入一个参数Throwable,用来接收原方法中抛出的异常 * * @return */ public String fallback(String param1, String param2, Throwable throwable) { // 自定义异常业务处理 log.info("-----异常Throwable----:{}", throwable); return "throwable"; }
通过抽取独立处理方式
package wdz.order.config; import com.alibaba.csp.sentinel.slots.block.BlockException; import lombok.extern.slf4j.Slf4j; @Slf4j public class SentinelHandler { /** * 处理的是SentinelResource中定义的5个异常 * 要求: * 1:返回参数必须与SentinelResource注解所在的方法返回值一致,接收的参数一致 * 2:方法名必须与注解中blockHandler属性值一致 * <p> * 允许参数在参数列表的最后加入一个参数BlockExceprion,用来接收原方法中发生的异常 * 注意:方法抽取后需要static,否则不生效 * @return */ public static String blockHandler(String param1, String param2, BlockException exceprion) { // 自定义异常业务处理 log.info("-----异常BlockException----:{}", exceprion); return "BlockException"; } }
package wdz.order.config; import com.alibaba.csp.sentinel.slots.block.BlockException; import lombok.extern.slf4j.Slf4j; @Slf4j public class SentinelFallback { /** * 处理的是所有的异常 * 要求: * 1:返回参数必须与SentinelResource注解所在的方法返回值一致,接收的参数一致 * 2:方法名必须与注解中blockHandler属性值一致 * <p> * 允许参数在参数列表的最后加入一个参数Throwable,用来接收原方法中抛出的异常 * 注意:方法抽取后需要static,否则不生效 * @return */ public static String fallback(String param1, String param2, Throwable throwable) { // 自定义异常业务处理 log.info("-----异常Throwable----:{}", throwable); return "throwable"; } }
@RequestMapping("heart") @SentinelResource(value = "heart-sentinel", blockHandlerClass = SentinelHandler.class, blockHandler = "blockHandler", // 成对出现的方式配置抽取 fallbackClass = SentinelFallback.class, fallback = "fallback" ) public String heart(String param1, String param2) { return param1 + param2; }
Sentinel 持久化
sentinel 规则默认是在内存中的,重启服务后规则全部清空,
持久化:当设置规则之后在存储内存的同时发送一份到所依赖的服务中,进行持久化
1、代码:
package wdz.order.config; import com.alibaba.csp.sentinel.command.handler.ModifyParamFlowRulesCommandHandler; import com.alibaba.csp.sentinel.datasource.*; import com.alibaba.csp.sentinel.init.InitFunc; import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule; import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRuleManager; import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule; import com.alibaba.csp.sentinel.slots.block.flow.FlowRule; import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager; import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule; import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRuleManager; import com.alibaba.csp.sentinel.slots.system.SystemRule; import com.alibaba.csp.sentinel.slots.system.SystemRuleManager; import com.alibaba.csp.sentinel.transport.util.WritableDataSourceRegistry; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.TypeReference; import org.springframework.beans.factory.annotation.Value; import java.io.File; import java.io.IOException; import java.util.List; import static com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager.*; public class FilePersistence implements InitFunc { @Value("spring.application:name") private String appcationName; @Override public void init() throws Exception { //指定文件生成目录 String ruleDir = System.getProperty("user.home") + "/sentinelrules/" + appcationName; String flowRulePath = ruleDir + "/flow-rule.json"; String degradeRulePath = ruleDir + "/degrade-rule.json"; String systemRulePath = ruleDir + "/system-rule.json"; String authorityRulePath = ruleDir + "/authority-rule.json"; String paramFlowRulePath = ruleDir + "/param-flow-rule.json"; this.mkdirIfNotExits(ruleDir); this.createFileIfNotExits(flowRulePath); this.createFileIfNotExits(degradeRulePath); this.createFileIfNotExits(systemRulePath); this.createFileIfNotExits(authorityRulePath); this.createFileIfNotExits(paramFlowRulePath); // 流控规则 ReadableDataSource<String, List<FlowRule>> flowRuleRDS = new FileRefreshableDataSource<>(flowRulePath, flowRuleListParser); FlowRuleManager.register2Property(flowRuleRDS.getProperty()); WritableDataSource<List<FlowRule>> flowRuleWDS = new FileWritableDataSource<>( flowRulePath, this::encodeJson ); WritableDataSourceRegistry.registerFlowDataSource(flowRuleWDS); // 降级规则 ReadableDataSource<String, List<DegradeRule>> degradeRuleRDS = new FileRefreshableDataSource<>( degradeRulePath, degradeRuleListParser ); register2Property(degradeRuleRDS.getProperty()); WritableDataSource<List<DegradeRule>> degradeRuleWDS = new FileWritableDataSource<>( degradeRulePath, this::encodeJson ); WritableDataSourceRegistry.registerDegradeDataSource(degradeRuleWDS); // 系统规则 ReadableDataSource<String, List<SystemRule>> systemRuleRDS = new FileRefreshableDataSource<>( systemRulePath, systemRuleListParser); SystemRuleManager.register2Property(systemRuleRDS.getProperty()); WritableDataSource<List<SystemRule>> systemRuleWDS = new FileWritableDataSource<>( systemRulePath, this::encodeJson); WritableDataSourceRegistry.registerSystemDataSource(systemRuleWDS); // 授权规则 ReadableDataSource<String, List<AuthorityRule>> authorityRuleRDS = new FileRefreshableDataSource<>( authorityRulePath, authorityRuleListParser ); AuthorityRuleManager.register2Property(authorityRuleRDS.getProperty()); WritableDataSource<List<AuthorityRule>> authorityRuleWDS = new FileWritableDataSource<>( authorityRulePath, this::encodeJson ); WritableDataSourceRegistry.registerAuthorityDataSource(authorityRuleWDS); // 热点参数规则 ReadableDataSource<String, List<ParamFlowRule>> paramFlowRuleRDS = new FileRefreshableDataSource<>( paramFlowRulePath, paramFlowRuleListParser ); ParamFlowRuleManager.register2Property(paramFlowRuleRDS.getProperty()); WritableDataSource<List<ParamFlowRule>> paramFlowRuleWDS = new FileWritableDataSource<>(paramFlowRulePath, this::encodeJson ); ModifyParamFlowRulesCommandHandler.setWritableDataSource(paramFlowRuleWDS); } private Converter<String, List<FlowRule>> flowRuleListParser = source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() { }); private Converter<String, List<DegradeRule>> degradeRuleListParser = source -> JSON.parseObject( source, new TypeReference<List<DegradeRule>>() { }); private Converter<String, List<SystemRule>> systemRuleListParser = source -> JSON.parseObject( source, new TypeReference<List<SystemRule>>() { }); private Converter<String, List<AuthorityRule>> authorityRuleListParser = source -> JSON.parseObject( source, new TypeReference<List<AuthorityRule>>() { }); private Converter<String, List<ParamFlowRule>> paramFlowRuleListParser = source -> JSON.parseObject( source, new TypeReference<List<ParamFlowRule>>() { }); private void mkdirIfNotExits(String filePath) throws IOException { File file = new File(filePath); if (!file.exists()) { file.mkdirs(); } } private void createFileIfNotExits(String filePath) throws IOException { File file = new File(filePath); if (!file.exists()) { file.createNewFile(); } } private <T> String encodeJson(T t) { return JSON.toJSONString(t); } }
2、配置:
在resources下创建文件夹:META-INF.services
创建文件:com.alibaba.csp.sentinel.init.InitFunc # 上边代码实现类全路径
写入内容:wdz.order.config.FilePersistence # 上边代码全路径
sentinel 网关限流 gateway
1.6版本开始,提供了gateway 适配模块,提供两种资源纬度的限流
1:route维度:在spring配置文件的路由条目,资源名对应的routeId
2:自定义API维度:利用sentinel提供的API来定义自己的一些API分组
route维度方式:
引入依赖
<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-spring-cloud-gateway-adapter</artifactId> </dependency>添加配置代码:
package com.wdz.cloud.gateway.config; import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule; import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager; import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter; import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler; import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager; import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler; import org.springframework.beans.factory.ObjectProvider; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.codec.ServerCodecConfigurer; import org.springframework.web.reactive.function.BodyInserter; import org.springframework.web.reactive.function.BodyInserters; import org.springframework.web.reactive.function.server.ServerResponse; import org.springframework.web.reactive.result.view.ViewResolver; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; import javax.annotation.PostConstruct; import java.util.*; @Configuration public class SentinelGatewayConfig { private final List<ViewResolver> viewResolvers; private final ServerCodecConfigurer serverCodecConfigurer; public SentinelGatewayConfig(ObjectProvider<List<ViewResolver>> viewResolverProvider, ServerCodecConfigurer serverCodecConfigurer) { this.viewResolvers = viewResolverProvider.getIfAvailable(); this.serverCodecConfigurer = serverCodecConfigurer; } // 初始化限流过滤器 @Bean @Order(Ordered.HIGHEST_PRECEDENCE) public GlobalFilter sentinelGatewayFilter() { return new SentinelGatewayFilter(); } // 配置初始化限流参数 @PostConstruct public void initGatewayRules() { Set<GatewayFlowRule> rules = new HashSet<>(); rules.add( new GatewayFlowRule("wdz_product") // 路由中的id .setCount(1) // 限流阈值 .setIntervalSec(1) // 统计时间窗口(多长时间为单位进行统计),单位是秒,默认1秒 ); GatewayRuleManager.loadRules(rules); } // 配置限流异常处理类 @Bean @Order(Ordered.HIGHEST_PRECEDENCE) public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() { return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer); } // 自定义限流异常处理 @PostConstruct public void initBlockHandlers() { BlockRequestHandler blockRequestHandler = new BlockRequestHandler() { @Override public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) { Map map = new HashMap(); map.put("code", "303"); map.put("message", "流量超载,暂时限流"); return ServerResponse.status(HttpStatus.OK) .contentType(MediaType.APPLICATION_JSON_UTF8) .body(BodyInserters.fromObject(map)); } }; GatewayCallbackManager.setBlockHandler(blockRequestHandler); } }
当访问配置限流的路由时,超出阈值返回异常配置
自定义维度:将下面代码更新到上面代码即可
// 配置初始化限流参数 @PostConstruct public void initGatewayRules() { // 使用路由限流初始化设置 // Set<GatewayFlowRule> rules = new HashSet<>(); // rules.add( // new GatewayFlowRule("wdz_product") // .setCount(1) // 限流阈值 // .setIntervalSec(1) // 统计时间窗口(多长时间为单位进行统计),单位是秒,默认1秒 // // ); // GatewayRuleManager.loadRules(rules); // 使用自定义限流设置 Set<GatewayFlowRule> rules = new HashSet<>(); rules.add(new GatewayFlowRule("api001").setCount(1).setIntervalSec(1)); rules.add(new GatewayFlowRule("api002").setCount(1).setIntervalSec(1)); GatewayRuleManager.loadRules(rules); } // 自定义API分组 @PostConstruct private void initCustomeizedApis() { Set<ApiDefinition> definitions = new HashSet<>(); // HashSet<ApiPredicateItem> predicateItems = new HashSet<ApiPredicateItem>(); // ApiPathPredicateItem e = new ApiPathPredicateItem().setPattern("/prudect/**"); // e.setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX); // predicateItems.add(e); // ApiDefinition apiDefinition = new ApiDefinition("").setPredicateItems(predicateItems); // apiName 可随意设置,不重复即可 ApiDefinition apiDefinition = new ApiDefinition("api001") .setPredicateItems(new HashSet<ApiPredicateItem>() {{ ApiPathPredicateItem e = new ApiPathPredicateItem().setPattern("/product/query/api_1/**"); e.setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX); add(e); }}); ApiDefinition apiDefinition2 = new ApiDefinition("api002") .setPredicateItems(new HashSet<ApiPredicateItem>() {{ // 配置规则,域名后的uri ApiPathPredicateItem e = new ApiPathPredicateItem().setPattern("/product/query/api2/**"); e.setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX); add(e); }}); definitions.add(apiDefinition); definitions.add(apiDefinition2); GatewayApiDefinitionManager.loadApiDefinitions(definitions); }