我是靠谱客的博主 难过百合,最近开发中收集的这篇文章主要介绍java 限流熔断_Sentinel进行限流及熔断降级,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

在 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进行限流及熔断降级所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(42)

评论列表共有 0 条评论

立即
投稿
返回
顶部