概述
在 Sentinel 中资源定义和规则配置是分离的。先通过 Sentinel API 给对应的业务逻辑定义资源(埋点),然后可以在需要的时候配置规则。
1,引入依赖包
com.alibaba.csp
sentinel-core
1.8.0
com.alibaba.csp
sentinel-annotation-aspectj
1.8.0
使用方式一:Java原生编码方式
步骤1:定义需要保护的资源
public String test(){
Entry entry = null;
try {
//定义资源保护的入口,同时指定资源名(用于与规则匹配)
entry = SphU.entry("sentinelApi");
//业务逻辑(这了调用了另一个方法)
return getMsg() ;
} catch (BlockException e) {
if(e instanceof FlowException){
//限流控制逻辑处理
return "限流了" ;
}
if(e instanceof DegradeException){
//熔断控制逻辑处理
return "降级了" ;
}
return "none" ;
} catch (Exception e){
//记录业务异常数
Tracer.trace(e) ;
return "exe" ;
}finally {
if (entry != null) {
entry.exit();
}
}
}
步骤2:定义资源保护规则
@Component
public class SentinelRuleConfiguration {
@PostConstruct
public void init() {
//限流规则
initFlowRule("sentinelApi") ;
//熔断降级规则
initDegradeRule("sentinelApi") ;
//添加时间监听
addEventObserver() ;
}
/**
*
* 流量控制(flow control),其原理是监控应用流量的 QPS 或并发线程数等指标,
* 当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。
*
* 限流的直接表现是在执行 Entry nodeA = SphU.entry(resourceName) 的时候抛出 FlowException 异常。
* FlowException 是 BlockException 的子类,您可以捕捉 BlockException 来自定义被限流之后的处理逻辑。
*
* 流量控制规则 (FlowRule).
* 同一个资源可以同时有多个限流规则,检查规则时会依次检查。
* @param resourceName 资源名,资源名是限流规则的作用对象
* */
private static void initFlowRule(String resourceName) {
List rules = new ArrayList<>();
/*
* 配置策略1: 并发线程数控制【通常在调用端进行配置】
* 并发数控制用于保护业务线程池不被慢调用耗尽
* */
FlowRule thRule = new FlowRule(resourceName);
thRule.setCount(1); //限流阈值
thRule.setGrade(RuleConstant.FLOW_GRADE_THREAD); //限流阈值类型,QPS 模式(1)或并发线程数模式(0)。默认:QPS 模式
thRule.setLimitApp("default"); //流控针对的调用来源。默认:default,代表不区分调用来源
thRule.setClusterMode(false) ; //是否集群限流。默认为false
/*
* 流量控制的效果
* 1)直接拒绝(RuleConstant.CONTROL_BEHAVIOR_DEFAULT)方式是默认的流量控制方式(该方式适用于对系统处理能力确切已知的情况下);
* 2)Warm Up(RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式,即预热/冷启动方式。
* 3)匀速排队(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)让请求以均匀的速度通过,对应的是漏桶算法(该方式主要用于处理间隔性突发的流量,暂不支持 QPS > 1000 的场景)。
* */
thRule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT) ;
rules.add(thRule);
/*
* 配置策略2:QPS流量控制
* 当 QPS 超过某个阈值的时候,则采取措施进行流量控制
* */
FlowRule qpsRule = new FlowRule(resourceName);
qpsRule.setCount(1); //限流阈值
qpsRule.setGrade(RuleConstant.FLOW_GRADE_QPS); //限流阈值类型,QPS 模式(1)或并发线程数模式(0)。默认:QPS 模式
qpsRule.setLimitApp("default"); //流控针对的调用来源。默认:default,代表不区分调用来源
qpsRule.setClusterMode(false) ; //是否集群限流。默认为false
/*
* 流量控制的效果
* 1)直接拒绝(RuleConstant.CONTROL_BEHAVIOR_DEFAULT)方式是默认的流量控制方式(该方式适用于对系统处理能力确切已知的情况下);
* 2)Warm Up(RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式,即预热/冷启动方式。
* 3)匀速排队(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)让请求以均匀的速度通过,对应的是漏桶算法(该方式主要用于处理间隔性突发的流量,暂不支持 QPS > 1000 的场景)。
* */
qpsRule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER) ;
/*
* 这里设置的等待处理时间较大, 让系统能平稳的处理所有的请求.
* 表示每一个请求的最长等待时间20s
* */
qpsRule.setMaxQueueingTimeMs(20 * 1000);
rules.add(qpsRule);
//定义流量控制规则
FlowRuleManager.loadRules(rules);
}
/**
* 熔断降级规则 (DegradeRule)
*
* 1:慢调用比例 (SLOW_REQUEST_RATIO):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),
* 请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,
* 并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。 经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),
* 若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。
*
* 注意:只会统计在单位统计时长(statIntervalMs)内已经响应的请求【这样的请求才能判断是否满足慢调用条件】,
* 如果实际请求的响应时长或设置的慢时长(count)都超出了statIntervalMs,那么将不可能启动熔断的作用
* ----------------------------------------------------
*
*2:异常比例 (ERROR_RATIO):当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。
*
* 3:异常数 (ERROR_COUNT):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。
* 注意异常降级仅针对业务异常,对 Sentinel 限流降级本身的异常(BlockException)不生效。为了统计异常比例或异常数,需要通过 Tracer.trace(ex) 记录业务异常。示例:
* */
private static void initDegradeRule(String resourceName) {
List rules = new ArrayList<>();
/*
* 配置策略1:慢调用比例
* 当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断;
*
* 当资源的保护处于CLOSED状态时,当请求进来时开始计时,统计statIntervalMs时间范围内所有请求中有多大比例的请求
* 满足“慢请求”的条件(statIntervalMs时间范围内已经响应的才能判断是否为慢请求),如果满足则开启(OPEN)熔断,熔断时间结束后,接受一条请求通过,
* 如果不是慢请求,则切换到HALF_OPEN状态,然后切换到CLOSE状态;
* 所以:statIntervalMs > count
* */
DegradeRule srule = new DegradeRule(resourceName);
/*
* 熔断策略,支持慢调用比例/异常比例/异常数策略。
* 默认:慢调用比例
**/
srule.setGrade(RuleConstant.DEGRADE_GRADE_RT);
/*
* 慢调用比例模式下为慢调用临界 RT(超出该值计为慢调用,单位ms);
* 异常比例/异常数模式下为对应的阈值;
* 注意:该模式下,该值要小于“统计时长”,否则不会生效。
**/
srule.setCount(10);
/*
*熔断时长,单位为 s
**/
srule.setTimeWindow(10);
/*
* 熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断。
* 默认值:5
* */
srule.setMinRequestAmount(5) ;
/*
* 统计时长(单位为 ms),如 60*1000 代表分钟级。
* 默认:1000 ms
* 注意与上面count值得联系,同时该时间段内的请求都会进入并参与统计。
* */
srule.setStatIntervalMs(1000) ;
/*
*慢调用比例阈值,仅慢调用比例模式有效
* */
srule.setSlowRatioThreshold(0.6) ;
rules.add(srule);
/*
* 配置策略2:异常比例
* 当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。
* 注意:需要通过Tracer.trace(ex)记录非BlockException类型的业务异常数
* */
DegradeRule erule = new DegradeRule(resourceName);
erule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO);
erule.setCount(0.1) ; //异常比率阈值,阈值范围是 [0.0, 1.0],代表 0% - 100%。
erule.setTimeWindow(10) ; //熔断时长,单位为 s
erule.setMinRequestAmount(5) ; //熔断触发的最小请求数
erule.setStatIntervalMs(1000) ; //单位统计时长
rules.add(erule);
/*
* 配置策略3:异常数
* 当单位统计时长内的异常数目超过阈值之后会自动进行熔断
* 注意:需要通过Tracer.trace(ex)记录非BlockException类型的业务异常数
* */
DegradeRule ecrule = new DegradeRule(resourceName);
ecrule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);
ecrule.setCount(2) ; //异常数阈值
ecrule.setTimeWindow(10) ; //熔断时长,单位为 s
ecrule.setMinRequestAmount(5) ; //熔断触发的最小请求数
ecrule.setStatIntervalMs(1000) ; //单位统计时长
rules.add(ecrule);
//加载配置的熔断策略
DegradeRuleManager.loadRules(rules);
}
private void addEventObserver(){
//熔断器事件监听
EventObserverRegistry.getInstance().addStateChangeObserver("logging",
(prevState, newState, rule, snapshotValue) -> {
if (newState == CircuitBreaker.State.OPEN) {
// 变换至 OPEN state 时会携带触发时的值
System.err.println(String.format("%s -> OPEN at %d, snapshotValue=%.2f", prevState.name(),
TimeUtil.currentTimeMillis(), snapshotValue));
} else {
System.err.println(String.format("%s -> %s at %d", prevState.name(), newState.name(),
TimeUtil.currentTimeMillis()));
}
});
}
}
通过以上两步,test方法被调用的时候就能受到限流和熔断的保护了。
至于怎么样熔断规则配置才是有效的,可看以下的代码
public static boolean isValidRule(DegradeRule rule) {
boolean baseValid = rule != null && !StringUtil.isBlank(rule.getResource())
&& rule.getCount() >= 0 && rule.getTimeWindow() > 0;
if (!baseValid) {
return false;
}
if (rule.getMinRequestAmount() <= 0 || rule.getStatIntervalMs() <= 0) {
return false;
}
switch (rule.getGrade()) {
case RuleConstant.DEGRADE_GRADE_RT:
return rule.getSlowRatioThreshold() >= 0 && rule.getSlowRatioThreshold() <= 1;
case RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO:
return rule.getCount() <= 1;
case RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT:
return true;
default:
return false;
}
}
使用方式二:使用Spring的AOP进行控制
步骤1:添加所需切面的配置
在Spring的配置文件中添加以下配置
也可以通过JavaConfig的方式来配置
@Configuration(proxyBeanMethods = false)
//SpringBoot下该@EnableAspectJAutoProxy可以不需要,会自动完成装配
//@EnableAspectJAutoProxy(proxyTargetClass = true)
public class SentinelAspectConfiguration {
@Bean
public SentinelResourceAspect sentinelResourceAspect() {
return new SentinelResourceAspect();
}
}
步骤2:在方法上添加注解
/**
*
* @SentinelResource注解参数介绍
* 1)value 配置资源名称,如果不配置则使用方法全路径名
* 2)entryType 指定规则作用于入口流量还是出口流量。默认为EntryType.OUT
* 3)blockHandler 对应处理 BlockException 的函数名称。
* 该函数的返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的类型为BlockException的参数;
* 默认需要和原方法在同一个类中,也可以配置blockHandlerClass来指定处理的类,但类里的方法必须是static。
* 4)fallback 失败回调的函数名称(优先级低于blockHandler),可以处理除了在参数exceptionsToIgnore中指定排除的所有异常类型,
* 该函数默认与原函数在同一个类型中,也可以配置fallbackClass 来指定处理的类,但类里的方法必须是static,其函数的签名要求如下:
* - 返回类型与原函数类型一致
* - 参数列表与原函数保持一致,同时可以额外添加一个Throwable类型参数来接收对应的异常
* 5)defaultFallback 默认的 fallback 函数名称,可以处理除了在参数exceptionsToIgnore中指定排除的所有异常类型,在未配置fallback的情况下生效。
* 该函数默认与原函数在同一个类型中,也可以配置fallbackClass 来指定处理的类,但类里的方法必须是static,其函数的签名要求如下:
* - 返回类型与原函数类型一致
* - 参数列表为空,同时可以额外添加一个Throwable类型参数来接收对应的异常
* 6)exceptionsToIgnore 用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。
* */
@SentinelResource(value = "getUserById", fallback = "fallbackForGetUser")
public String getUserById(String id) {
throw new RuntimeException("getUserById command failed");
}
/**
* fallback 方法,原方法被降级的时候调用;若需要限流/系统保护的 fallback 可以配置 blockHandler.
* */
public String fallbackForGetUser(String id) {
return "unknown";
}
步骤3:定义资源保护规则(同上)
方法同上,只是要修改资源名为“getUserById”
经过以上几个步骤也就完成了对资源“getUserById”的保护。
最后
以上就是难过百合为你收集整理的java 限流熔断_Sentinel进行限流及熔断降级的全部内容,希望文章能够帮你解决java 限流熔断_Sentinel进行限流及熔断降级所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复