在上一篇文章中,我们初步体验了下sentinel的流量控制,流量控制通常都是在调用端进行控制,那么如果某一个服务每次都报错呢,那么这里我们了可以用熔断降级的策略。如果在固定时间内服务报错了规定的次数,我们就不在执行正常业务逻辑了,直接执行备用的方法,这样对系统性能和用户体验都比较好,我们来试试吧!
1、环境准备
五、springCloudAlibaba-sentinel的初步使用
2、熔断规则
List<DegradeRule> degradeRules = new ArrayList<>();
DegradeRule degradeRule = new DegradeRule();
degradeRule.setResource(BREAK_RESOURCE_NAME);
//设置规则策略,异常数
degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);
//触发熔断异常数:2
degradeRule.setCount(2);
//触发熔断最小请求数:4
degradeRule.setMinRequestAmount(4);
//熔断时长,单位为秒,一旦触发了熔断,再次请求对应的接口就会直接调用降级方法,这个跟之前的流量控制还是有区别的
//10秒过后会变成半开的状态,恢复接口请求调用,如果第一次请求异就异常,将会再次熔断
degradeRule.setTimeWindow(10);
degradeRule.setStatIntervalMs(60*1000);
degradeRules.add(degradeRule);
DegradeRuleManager.loadRules(degradeRules);
3、请求方法
@RequestMapping("/break")
@SentinelResource(value = BREAK_RESOURCE_NAME, blockHandler = "exceptionHandler2")
public String breakA(String id) {
throw new RuntimeException("报错了");
}
// Block 异常处理函数,参数最后多一个 BlockException,其余与原函数一致.
public String exceptionHandler2(String id, BlockException ex) {
// Do some log here.
// ex.printStackTrace();
return "被熔断了"+id;
}
4、启动测试
我们可以发现,请求第五次就返回了被熔断提示,这是因为我们设置了最小请求是4,等10s后再请求用进入了业务逻辑,此时业务逻辑还是报错,那么再次请求就继续熔断了!
5、总结
其他规则用法大体跟流量控制和熔断限流差不多,根据官网即可
6、这两节的全部代码
Controller类
package com.suibibk.springCloud.order.controller;
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
@RestController
@RequestMapping("/order")
public class OrderController {
public static final String HELLO_RESOURCE_NAME = "hello";
public static final String USER_RESOURCE_NAME = "user";
public static final String BREAK_RESOURCE_NAME = "break";
@RequestMapping("/hello")
public String hello(){
// 1.5.0 版本开始可以直接利用 try-with-resources 特性
try (Entry entry = SphU.entry(HELLO_RESOURCE_NAME)) {
// 被保护的逻辑
return "hello world";
} catch (BlockException ex) {
// 处理被流控的逻辑
return "被限流了";
}
}
@PostConstruct
private void initFlowRules(){
List<FlowRule> rules = new ArrayList<>();
FlowRule rule = new FlowRule();
rule.setResource(HELLO_RESOURCE_NAME);
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
// Set limit QPS to 20. 这里表示超过1秒的频率就会限流
rule.setCount(1);
rules.add(rule);
FlowRule rule2 = new FlowRule();
rule2.setResource(USER_RESOURCE_NAME);
rule2.setGrade(RuleConstant.FLOW_GRADE_QPS);
// Set limit QPS to 20. 这里表示超过1秒的频率就会限流
rule2.setCount(1);
rules.add(rule2);
FlowRuleManager.loadRules(rules);
List<DegradeRule> degradeRules = new ArrayList<>();
DegradeRule degradeRule = new DegradeRule();
degradeRule.setResource(BREAK_RESOURCE_NAME);
//设置规则策略,异常数
degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);
//触发熔断异常数:2
degradeRule.setCount(2);
//触发熔断最小请求数:4
degradeRule.setMinRequestAmount(4);
//熔断时长,单位为秒,一旦触发了熔断,再次请求对应的接口就会直接调用降级方法,这个跟之前的流量控制还是有区别的
//10秒过后会变成半开的状态,恢复接口请求调用,如果第一次请求异就异常,将会再次熔断
degradeRule.setTimeWindow(10);
degradeRule.setStatIntervalMs(60*1000);
degradeRules.add(degradeRule);
DegradeRuleManager.loadRules(degradeRules);
}
/**
* exceptionHandler :被流控降级的方法,默认该方法必须声明在同一个类中,一定是public,返回值跟原方法一致
* @param id
* @return
*/
@RequestMapping("/user")
@SentinelResource(value = USER_RESOURCE_NAME, blockHandler = "exceptionHandler")
public String user(String id) {
return "返回用户成功"+id;
}
// Block 异常处理函数,参数最后多一个 BlockException,其余与原函数一致.
public String exceptionHandler(String id, BlockException ex) {
// Do some log here.
ex.printStackTrace();
return "被限流了"+id;
}
@RequestMapping("/break")
@SentinelResource(value = BREAK_RESOURCE_NAME, blockHandler = "exceptionHandler2")
public String breakA(String id) {
throw new RuntimeException("报错了");
}
// Block 异常处理函数,参数最后多一个 BlockException,其余与原函数一致.
public String exceptionHandler2(String id, BlockException ex) {
// Do some log here.
// ex.printStackTrace();
return "被熔断了"+id;
}
}
启动类
package com.suibibk.springCloud.order;
import com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
/**
* Hello world!
*/
@SpringBootApplication
public class OrderApplication {
public static void main( String[] args ) {
SpringApplication.run(OrderApplication.class,args);
}
@Bean
public SentinelResourceAspect sentinelResourceAspect(){
return new SentinelResourceAspect();
}
}