(万字好⽂)Dubbo服务熔断与降级的深⼊讲解代码实战
原⽂链接:
⼀、Dubbo服务降级实战
1 mock 机制
谈到服务降级,Dubbo 本⾝就提供了服务降级的机制;⽽ Dubbo 的服务降级机制主要是利⽤服务消费者的 mock 属性。
服务消费者的 mock 属性有以下三种使⽤⽅式,下⾯将带着例⼦简单介绍⼀下。
1.1 服务消费者注册url的mock属性
例⼦:
mock=return+null,即当服务提供者出现异常(宕机或者业务异常),则返回null给服务消费者。
2021-01-26 09:39:54.631 [main] [INFO ] [o.ZookeeperRegistry] [] [] -  [DUBBO] Notify urls for subscribe url consumer://127.0.0.1/com.winfun.service.DubboServiceOne?application=dubbo-service&c
ategory=providers,configurators,routers& 1.2 @DubboReference注解或者标签的mock属性
例⼦:
mock="return null",即当服务提供者出现异常(宕机或者业务异常),则返回null给服务消费者。
public class HelloController{
@DubboReference(check = false,lazy = true,retries = 1,mock = "return null")
private DubboServiceOne dubboServiceOne;
//.....
}
1.3 服务消费者mock属性设置为true+Mock实现类
例⼦:
Mock实现类为 Dubbo接⼝的实现类,并且 Mock实现类与 Dubbo接⼝放同⼀个路径下(可不同项⽬,但是保证包路径是⼀致的)。
/**
*
* DubboServiceTwo
* @author winfun
* @date 2020/10/29 5:00 下午
**/
public interface DubboServiceTwo {
/***
*  say hi
* @author winfun
* @param name name
* @return {@link ApiResult<String> }
**/
ApiResult<String> sayHi(String name);
}
/**
* DubboServiceTwo 降级实现类
* @author winfun
* @date 2021/1/26 9:21 上午
**/
public class DubboServiceTwoMock implements DubboServiceTwo{
/***
*  say hi
* @author winfun
* @param name name
* @return {@link ApiResult <String> }
**/
@Override
public ApiResult<String> sayHi(String name) {
return ApiResult.fail("Mock实现类-服务降级了");
}
}
2 实战例⼦:
下⾯将使⽤第⼆种⽅式来展⽰ Duboo ⾃⾝提供的服务降级机制。
2.1 consumer 代码:
/**
* Say Hello
* @author winfun
* @date 2020/10/29 5:12 下午
**/
@RestController
public class HelloController {
@DubboReference(check = false,lazy = true,retries = 1,mock="return {\"code\":1,\"message\":\"熔断限流了\"}")
private DubboServiceOne dubboServiceOne;
@GetMapping("/hello/{name}")
public ApiResult sayHello(@PathVariable("name") String name){
return this.dubboServiceOne.sayHello(name);
}
}
2.2 provider 代码:
/**
* DubboServiceOneImpl
* @author winfun
* @date 2020/10/29 5:04 下午
**/
@DubboService(interfaceClass = DubboServiceOne.class)
public class DubboServiceOneImpl implements DubboServiceOne {
/***
*  say hello
* @author winfun
* @param name name
* @return {@link ApiResult<String> }
**/
@SneakyThrows
@Override
public ApiResult<String> sayHello(String name) {
/
/ dubbo 接⼝默认超时时间为1s,我们这⾥直接休眠5s
Thread.sleep(5000);
return ApiResult.success("hello "+name);
}
2.3 结果分析:
情况⼀:服务提供者没起来
这个时候服务消费者不会进⾏重试,只会直接进⾏服务降级,返回我们设定的 Mock 值。
2021-01-27 18:02:12.288 [http-nio-8081-exec-1] [WARN ] [o.s.w.MockClusterInvoker] [/hello/name] [16117417328056102141] -  [DUBBO] fail-mock: sayHello fail-mock enabled , url : zookeeper://127.0.0.1:2181/org.istry.R org.apache.dubbo.rpc.RpcException: No provider available from registry 127.0.0.1:2181 for service com.winfun.service.DubboServiceOne on consumer 172.26.144.16 use dubbo version 2.7.7, please check status of providers(disabled, not regist  //.....省略
2021-01-27 18:02:12.289 [http-nio-8081-exec-1] [INFO ] [o.s.w.MockClusterInvoker] [/hello/name] [16117417328056102141] -  [DUBBO] Exception when try to invoke mock. Get mock invokers error for service:com.winfun.service.DubboSe org.apache.dubbo.rpc.RpcException: No provider available from registry 127.0.0.1:2181 for service com.winfun.service.DubboServiceOne on consumer 172.26.144.16 use dubbo version 2.7.7, please check status of providers(disabled, not regist    //....省略
⼤家可能会存在⼀个质疑点:我上⾯说的是不会进⾏重试,但是控制台我们看到了两次异常;其实第⼆次异常,是获取 MockInvoker 导致的,所以⼤家可以先忽略,下⾯我会详
细分析 MockClusterInvoker 的源码,就知道为啥会有两次异常了。
情况⼆:服务提供者超时
注意:Dubbo 提供的服务降级机制,不⽀持对服务提供者业务异常的情况。
这个时候消费者会进⾏ 1+retries 次调⽤,然后再进⾏服务降级。
org.apache.dubbo.rpc.RpcException: Failed to invoke the method sayHello in the service com.winfun.service.DubboServiceOne. Tried 2 times of the providers [127.0.0.1:20881] (1/1) from the r
egistry 127.0.0.1:2181 on the consumer 172.26.144. at org.apache.dubbo.rpc.cluster.support.FailoverClusterInvoker.doInvoke(FailoverClusterInvoker.java:113)
//....省略
3 源码分析
关于服务降级的逻辑,主要在 Dubbo 提供的 MockClusterInvoker 类中。
下⾯我们直接看看 MockClusterInvoker 的源码:
public class MockClusterInvoker<T> implements Invoker<T> {
// ...省略
@Override
public Result invoke(Invocation invocation) throws RpcException {
Result result = null;
// 从 consumer 的注册url中获取⽅法的 mock 属性值
String value = getUrl().MethodName(), MOCK_KEY, String()).trim();
// mock 为空或者false,不进⾏服务降级处理
if (value.length() == 0 || "false".equalsIgnoreCase(value)) {
//no mock
result = this.invoker.invoke(invocation);
// 是否强⾏执⾏服务降级处理
} else if (value.startsWith("force")) {
if (logger.isWarnEnabled()) {
logger.warn("force-mock: " + MethodName() + " force-mock enabled , url : " + getUrl());
}
//force:direct mock
result = doMockInvoke(invocation, null);
} else {
//fail-mock
try {
result = this.invoker.invoke(invocation);
//fix:#4585
Exception() != null && Exception() instanceof RpcException){
RpcException rpcException= (Exception();
// 如果是业务异常,直接抛出
if(rpcException.isBiz()){
throw  rpcException;
}else {
// 服务降级处理
result = doMockInvoke(invocation, rpcException);
}
}
} catch (RpcException e) {
// 如果是业务异常,直接抛出
if (e.isBiz()) {
throw e;
}
if (logger.isWarnEnabled()) {
logger.warn("fail-mock: " + MethodName() + " fail-mock enabled , url : " + getUrl(), e);
}
// 服务降级处理
result = doMockInvoke(invocation, e);
}
}
return result;
}
@SuppressWarnings({"unchecked", "rawtypes"})
private Result doMockInvoke(Invocation invocation, RpcException e) {
Result result = null;
Invoker<T> minvoker;
// 获取服务降级 Invoker 列表
List<Invoker<T>> mockInvokers = selectMockInvoker(invocation);
if (CollectionUtils.isEmpty(mockInvokers)) {
// 服务降级 Invoker 列表为空,默认使⽤ Dubbo 提供的 MockInvoker 类
minvoker = (Invoker<T>) new MockInvoker(getUrl(), Interface());
} else {
minvoker = (0);
}
try {
// 服务降级处理
result = minvoker.invoke(invocation);
} catch (RpcException me) {
if (me.isBiz()) {
result = Cause(), invocation);
} else {
throw new Code(), getMockExceptionMessage(e, me), me.getCause());
}
} catch (Throwable me) {
throw new RpcException(getMockExceptionMessage(e, me), me.getCause());
}
return result;
}
//...
}
从上⾯的源码分析可知:
在 MockClusterInvoker#invoke ⽅法⾥⾯,如果是业务异常是不会做 mock 做处理的。⽽其他关于 RPC 的异常,是会做 mock 处理的,例如我们这⾥拿来测试的服务提供者超时异常和服务提供者不存在;
在 doMockInvoke ⽅法中,⾸先会调⽤ selectMockInvoker ⽅法会尝试获取 MockInvoker,⽽默认情况下,都是没有的,所以最后会使⽤ Dubbo 提供的 MockInvoker。
这⾥也回答了情况⼀例⼦中,会抛出两次异常的原因,就是因为获取 MockInvoker 的时候,会调⽤ selectMockInvoker,⽽如果服务没启动,那么必须还会再抛⼀次 No provider 的异常啦~
最后,⼤家如果有兴趣,可以⾃⾏继续研究 MockInvoker 的源码,特别是⾥⾯的 invoke 和 parseMockValue ⽅法,分别是服务降级的逻辑和 Mock 属性内容的解析。
如果不是看了 MockInvoker#parseMockValue ⽅法,⼀开始我都不知道如何返回 Json 格式的结果,只会直接返回 null,哈哈哈。所以源码还是得多看!
到此,关于 Dubbo 提供的服务降级的 Mock 机制已经简单地过了⼀遍,但是我们可以发现有⼀个问题:
4 Dubbo 服务降级机制的缺陷
4.1 缺陷分析
其实经过上⾯的例⼦分析和源码分析,我们会发现⼀个问题:由于 dubbo 不带熔断机制,所以尽管每次因为 RPC 异常⽽导致调⽤失败,也不会进⾏熔断处理;即不管调⽤失败多少次,消费者还是会继续进⾏调⽤。
其实这样会导致服务的资源浪费:
只要服务提供者出现异常达到⼀定的次数,其实可以理解为服务提供者短时间内已经不能正常提供服务了,后续再调⽤也是浪费资源。
如果是上述的超时问题,消费者还会进⾏ 1+retires 次的 RPC 调⽤,这样就更加浪费资源了。
所以,为 dubbo 配⼀个熔断机制是⾮常有必要的了。
⼆熔断机制
我个⼈对熔断的理解:
如果当调⽤失败达到指定的次数,则将熔断器打开⼀段时间,即将请求链路断开;在指定时间内,都不再让消费者向提供者发送请求;当熔断时间到了,就将熔断器设置为半打开的状态,此时消费者可以往提供者发送请求,并统计成功次数,如果达到指定的成功次数,熔断器则变为关闭状态,即将请求链路打开,否则熔断器⼜变回打开状态。
所以说,只要给dubbo加上熔断机制,不管是业务错误还是请求超时,只要时间内达到了⼀定的次数就做上述的熔断处理,这样就可以防⽌没有必要的调⽤。
1 引⼊ Sentinel
经过上⾯的对⽐,我个⼈是建议使⽤ Sentinel 的,因为它提供了更加灵活的使⽤⽅式,并且⽀持更多的规则,还提供了⼀个易⽤强⼤的控制台。
Sentinel 提供了三⼤接⼊⽅式:利⽤ sentinel-core 组件进⾏硬代码、利⽤ sentinel-annotation-aspectj 组件提供的注解功能、各种主流框架的接⼊⽅式。
下⾯我将分别使⽤三种⽅式为 Dubbo接⼝接⼊限流和熔断的机制。
在接⼊之前,我们需要注意的⼀个点是:要为 Dubbo接⼝接⼊熔断&限流等机制,必须要为 Dubbo接⼝指定资源,并且为资源初始化规则;否则只是引⼊了组件,也⽆法使⽤Sentinel 提供的限流&熔断功能。
1.1 ⽅式⼀:sentinel-core组件
引⼊依赖:
引⼊ sentinel-core 依赖,直接植⼊硬代码进⾏熔断限流。
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
<version>1.8.0</version>
</dependency>
Controller 代码:
/**
* Say Hello
* @author winfun
* @date 2020/10/29 5:12 下午
**/
@Slf4j
@RequestMapping("/hello")
@RestController
public class HelloController {
public static final String RESOURCE_NAME = "dubboServiceOne";
@DubboReference(check = false,lazy = true,retries = 0)
private DubboServiceOne dubboServiceOne;
/**
* 初始化流控规则和熔断规则
* ps:因为我们没有接⼊ Sentinel Dashboard,所以得⾃⼰在代码⾥⾯设置好
*/
static{
// 初始化流控规则
final List<FlowRule> flowRules = new ArrayList<>();
final List<DegradeRule> degradeRules = new ArrayList<>();
// 限流规则
final FlowRule flowRule = new FlowRule();
flowRule.setResource(RESOURCE_NAME);
flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
// 1 QPS
flowRule.setCount(1);
flowRules.add(flowRule);
// 熔断规则
final DegradeRule degradeRule = new DegradeRule();
degradeRule.setResource(RESOURCE_NAME);
degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);
// 2个异常数
degradeRule.setCount(2);
/
/ 时间窗⼝长度,单位为秒
degradeRule.setTimeWindow(5);
// 最⼩请求数
degradeRule.setMinRequestAmount(5);
// 熔断时长:当5秒内,10个请求⾥⾯出现2个异常,则进⾏熔断,熔断时长为10s
degradeRule.setStatIntervalMs(10000);
degradeRules.add(degradeRule);
FlowRuleManager.loadRules(flowRules);
DegradeRuleManager.loadRules(degradeRules);
}
@GetMapping("/{name}")
public ApiResult sayHello(@PathVariable("name") final String name){
final String hello = this.sayHelloByDubbo2Code(name);
return ApiResult.success(hello);
}
/***
* 接⼊Sentinel⽅式:植⼊硬代码进⾏熔断限流
* @author winfun
* @param name name
* @return {@link ApiResult<String> }
**/
private ApiResult<String> sayHelloByDubbo2Code(final String name) {
ApiResult<String> result;
Entry entry = null;
try {
entry = (RESOURCE_NAME);
result = this.dubboServiceOne.sayHello(name);
}  catch (BlockException e) {
if (e instanceof DegradeException){
<("资源:{} 被熔断了,message is {}",RESOURCE_Message());
result = ApiResult.fail("hello fallback");
}else {
<("资源:{} 被流控了",RESOURCE_NAME);
result = ApiResult.fail("hello block");
}
} catch (Exception e){
<("业务处理发⽣异常,exception is {}",e.getMessage());
// 若需要配置降级规则,需要通过这种⽅式记录业务异常
result = ApiResult.fail("exception");
//throw new RuntimeException("业务处理发⽣异常");
} finally {
// 务必保证 exit,务必保证每个 entry 与 exit 配对
if (entry != null) {
}
}
return result;
}
}
单元测试:
利⽤ MockMvc 来进⾏接⼝测试,循环调⽤。
@AutoConfigureMockMvc
@SpringBootTest(classes = DubboServiceApplication.class)
java dubbo
@RunWith(SpringRunner.class)
public class ServiceOneApplicationTests {
@Autowired
private MockMvc mockMvc;
@SneakyThrows
@Test
public void sayHello(){
for (int i = 0; i < 100; i++) {
// 休眠500毫秒,即1秒两次调⽤,可以触发流控规则
Thread.sleep(500);
MvcResult result = mockMvc.("/hello/winfun"))
.andReturn();
System.out.Response().getContentAsString());
}
}
}
在看单元测试的结果前,我们先分析⼀下我们的流控&熔断配置:
限流,我们是限制每秒只能有1个请求
熔断:在5秒内,如果5个请求中有两个请求是发⽣异常的,则打开熔断器,熔断时长为10s。
熔断中,当超过熔断时长了,接下来⼀个请求如果还是发⽣异常,则继续打开熔断器,否则就是关闭熔断器,恢复正常的请求链路。
单元测试中,我们是不会开启服务提供者的,先看看控制台打印的⽇志信息:
2021-01-27 11:42:18.568 [main] [ERROR] [HelloController] [] [] - 资源:dubboServiceOne 发⽣异常,message is No provider available from registry 127.0.0.1:2181 for service com.winfun.service.Dubb
oServiceOne on consumer 127.0.0.1 us {"code":1,"message":"exception","data":null,"traceId":null}
2021-01-27 11:42:19.147 [main] [ERROR] [HelloController] [] [] - 资源:dubboServiceOne 被流控了
{"code":1,"message":"hello block","data":null,"traceId":null}
2021-01-27 11:42:19.653 [main] [ERROR] [HelloController] [] [] - 资源:dubboServiceOne 发⽣异常,message is No provider available from registry 127.0.0.1:2181 for service com.winfun.service.DubboServiceOne on consumer 127.0.0.1 us {"code":1,"message":"exception","data":null,"traceId":null}
2021-01-27 11:42:20.160 [main] [ERROR] [HelloController] [] [] - 资源:dubboServiceOne 被流控了
{"code":1,"message":"hello block","data":null,"traceId":null}
2021-01-27 11:42:20.666 [main] [ERROR] [HelloController] [] [] - 资源:dubboServiceOne 发⽣异常,message is No provider available from registry 127.0.0.1:2181 for service com.winfun.service.DubboServiceOne on consumer 127.0.0.1 us {"code":1,"message":"exception","dat
a":null,"traceId":null}
2021-01-27 11:42:21.172 [main] [ERROR] [HelloController] [] [] - 资源:dubboServiceOne 被流控了
{"code":1,"message":"hello block","data":null,"traceId":null}
2021-01-27 11:42:21.681 [main] [ERROR] [HelloController] [] [] - 资源:dubboServiceOne 发⽣异常,message is No provider available from registry 127.0.0.1:2181 for service com.winfun.service.DubboServiceOne on consumer 127.0.0.1 us {"code":1,"message":"exception","data":null,"traceId":null}
2021-01-27 11:42:22.190 [main] [ERROR] [HelloController] [] [] - 资源:dubboServiceOne 被流控了
{"code":1,"message":"hello block","data":null,"traceId":null}
2021-01-27 11:42:22.695 [main] [ERROR] [HelloController] [] [] - 资源:dubboServiceOne 发⽣异常,message is No provider available from registry 127.0.0.1:2181 for service com.winfun.service.DubboServiceOne on consumer 127.0.0.1 us {"code":1,"message":"exception","dat
a":null,"traceId":null}
2021-01-27 11:42:23.202 [main] [ERROR] [HelloController] [] [] - 资源:dubboServiceOne 被流控了
{"code":1,"message":"hello block","data":null,"traceId":null}
2021-01-27 11:42:23.709 [main] [ERROR] [HelloController] [] [] - 资源:dubboServiceOne 发⽣异常,message is No provider available from registry 127.0.0.1:2181 for service com.winfun.service.DubboServiceOne on consumer 127.0.0.1 us {"code":1,"message":"exception","data":null,"traceId":null}
2021-01-27 11:42:24.215 [main] [ERROR] [HelloController] [] [] - 资源:dubboServiceOne 被流控了
{"code":1,"message":"hello block","data":null,"traceId":null}
2021-01-27 11:42:24.724 [main] [ERROR] [HelloController] [] [] - 资源:dubboServiceOne 发⽣异常,message is No provider available from registry 127.0.0.1:2181 for service com.winfun.service.DubboServiceOne on consumer 127.0.0.1 us {"code":1,"message":"exception","dat
a":null,"traceId":null}
2021-01-27 11:42:25.232 [main] [ERROR] [HelloController] [] [] - 资源:dubboServiceOne 被流控了
{"code":1,"message":"hello block","data":null,"traceId":null}
2021-01-27 11:42:25.738 [main] [ERROR] [HelloController] [] [] - 资源:dubboServiceOne 被熔断了,message is null
{"code":1,"message":"hello fallback","data":null,"traceId":null}
2021-01-27 11:42:26.247 [main] [ERROR] [HelloController] [] [] - 资源:dubboServiceOne 被熔断了,message is null
{"code":1,"message":"hello fallback","data":null,"traceId":null}
2021-01-27 11:42:26.757 [main] [ERROR] [HelloController] [] [] - 资源:dubboServiceOne 被熔断了,message is null
{"code":1,"message":"hello fallback","data":null,"traceId":null}
2021-01-27 11:42:27.265 [main] [ERROR] [HelloController] [] [] - 资源:dubboServiceOne 被熔断了,message is null
{"code":1,"message":"hello fallback","data":null,"traceId":null}
2021-01-27 11:42:27.769 [main] [ERROR] [HelloController] [] [] - 资源:dubboServiceOne 被熔断了,message is null
{"code":1,"message":"hello fallback","data":null,"traceId":null}
2021-01-27 11:42:28.274 [main] [ERROR] [HelloController] [] [] - 资源:dubboServiceOne 被熔断了,message is null
{"code":1,"message":"hello fallback","data":null,"traceId":null}
2021-01-27 11:42:28.779 [main] [ERROR] [HelloController] [] [] - 资源:dubboServiceOne 被熔断了,message is null
{"code":1,"message":"hello fallback","data":null,"traceId":null}
2021-01-27 11:42:29.284 [main] [ERROR] [HelloController] [] [] - 资源:dubboServiceOne 被熔断了,message is null
{"code":1,"message":"hello fallback","data":null,"traceId":null}
2021-01-27 11:42:29.790 [main] [ERROR] [HelloController] [] [] - 资源:dubboServiceOne 发⽣异常,message is No provider available from registry 127.0.0.1:2181 for service com.winfun.service.DubboServiceOne on consumer 127.0.0.1 us {"code":1,"message":"exception","data":null,"traceId":null}
2021-01-27 11:42:30.299 [main] [ERROR] [HelloController] [] [] - 资源:dubboServiceOne 被流控了
{"code":1,"message":"hello block","data":null,"traceId":null}
2021-01-27 11:42:30.803 [main] [ERROR] [HelloController] [] [] - 资源:dubboServiceOne 被熔断了,message is null
{"code":1,"message":"hello fallback","data":null,"traceId":null}
2021-01-27 11:42:31.309 [main] [ERROR] [HelloController] [] [] - 资源:dubboServiceOne 被熔断了,message is null
{"code":1,"message":"hello fallback","data":null,"traceId":null}
2021-01-27 11:42:31.814 [main] [ERROR] [HelloController] [] [] - 资源:dubboServiceOne 被熔断了,message is null
{"code":1,"message":"hello fallback","data":null,"traceId":null}
// .....
总结:
我们可以看到,控制台的⽇志打印是符合我们的预期的:
限流:1秒内会调⽤两次接⼝,所以会每两次调⽤都会触发限流规则。
熔断:服务提供者未启动,即每次 RPC 调⽤都会出现异常,所以时间窗⼝内出现⼀定数量的异常调⽤,触发了熔断规则。
并且,流控规则的优先级优先于熔断规则。
1.2 ⽅式⼆:使⽤注解 @SentinelResource
引⼊依赖:
引⼊ sentinel-annotation-aspectj 依赖。
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>1.8.0</version>
</dependency>
注⼊切⾯:
⼿动注⼊ SentinelResourceAspect,因为 Sentinel 提供的这个切⾯,是没有 @Component 等注解的,所以还是得⾃⼰注⼊到 Spring 容器中。
/**
* 需要引⼊⼀下,因为 Sentile 提供的这个切⾯是没有加 @Component 注解的
* @return
*/
@Bean
public SentinelResourceAspect sentinelResourceAspect() {
return new SentinelResourceAspect();
}
我们使⽤这个 @SentinelResource 注解,可直接在 Controller 的⽅法加注解,也可以⾃⼰再弄⼀个 Service 来加注解,这两个都可以.
因为我们的 Controller 层就是只调⽤了 Dubbo 接⼝,所以就直接在 Controller 的⽅法上⾯加注解了,⽽如果业务是⾮常多的,那就可以考虑单独弄个 Service 来给 Dubbo 接⼝
再包⼀层。
Spring AOP 同时⽀持 JDK 和 CGLIB 动态代理,SpringBoot 2.x 默认使⽤ CGLIB 动态代理。
Controller 代码:
/**
* Say Hello
* @author winfun
* @date 2020/10/29 5:12 下午
**/
@Slf4j
@RequestMapping("/hello")
@RestController
public class HelloController {
public static final String RESOURCE_NAME = "dubboServiceOne";
@DubboReference(check = false,lazy = true,retries = 0)
private DubboServiceOne dubboServiceOne;
/**
* 初始化流控规则和熔断规则
* ps:因为我们没有接⼊ Sentinel Dashboard,所以得⾃⼰在代码⾥⾯设置好
*/
static{
// 初始化流控规则
final List<FlowRule> flowRules = new ArrayList<>();
final List<DegradeRule> degradeRules = new ArrayList<>();
// 限流规则
final FlowRule flowRule = new FlowRule();
flowRule.setResource(RESOURCE_NAME);
flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
// 1 QPS
flowRule.setCount(1);
flowRules.add(flowRule);
// 熔断规则
final DegradeRule degradeRule = new DegradeRule();
degradeRule.setResource(RESOURCE_NAME);
degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);
// 2个异常数
degradeRule.setCount(1);
// 时间窗⼝长度,单位为秒
degradeRule.setTimeWindow(5);
// 最⼩请求数
degradeRule.setMinRequestAmount(5);
// 熔断时长:当5秒内,10个请求⾥⾯出现2个异常,则进⾏熔断,熔断时长为10s
degradeRule.setStatIntervalMs(10000);
degradeRules.add(degradeRule);
FlowRuleManager.loadRules(flowRules);
DegradeRuleManager.loadRules(degradeRules);
}
@GetMapping("/{name}")
@SentinelResource(value=RESOURCE_NAME,fallback = "sayHelloFallback",blockHandler = "sayHelloBlock")
public ApiResult sayHello(@PathVariable("name") final String name){
String hello = this.dubboServiceOne.sayHello(name);
return ApiResult.success(hello);
}
/**
* Fallback 函数,函数签名与原函数⼀致或加⼀个 Throwable 类型的参数.
* @param name
* @param throwable
* @return {@link ApiResult<String> }
*/
public ApiResult<String> sayHelloFallback(final String name, final Throwable throwable){
<("资源:{} 发⽣异常,message is {}",RESOURCE_Message());
return ApiResult.fail("hello exception");
}

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。