sentinel小记
1、被处理的接口
java
/**
* 分页获取题目列表(封装类)
*
* @param questionQueryRequest
* @param request
* @return
*/
@PostMapping("/list/page/vo")
public BaseResponse<Page<QuestionVO>> listQuestionVOByPage(@RequestBody QuestionQueryRequest questionQueryRequest,
HttpServletRequest request) {
long current = questionQueryRequest.getCurrent();
long size = questionQueryRequest.getPageSize();
// 限制爬虫,限制每页最多 20 条数据
ThrowUtils.throwIf(size > 20, ErrorCode.PARAMS_ERROR);
//对ip进行限流
String ip = request.getRemoteAddr();
Entry entry = null;
try {
entry = SphU.entry("listQuestionVOByPage", EntryType.IN, 1, ip);
//被保护的用户
// 查询数据库
Page<Question> questionPage = questionService.page(new Page<>(current, size), questionService.getQueryWrapper(questionQueryRequest));
// 获取封装类
return ResultUtils.success(questionService.getQuestionVOPage(questionPage, request));
} catch (Throwable ex) {
// 处理业务异常
if (!BlockException.isBlockException(ex)){
Tracer.trace(ex);
return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "系统错误");
}
if (ex instanceof DegradeException) {
// 降级操作
return handleFallback(questionQueryRequest, request, ex);
}
// 限流操作
return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "访问过于频繁,情稍后再试");
} finally {
if (entry != null) {
entry.exit(1, ip);
}
}
}
/**
* listQuestionBankVOByPage 降级操作:直接返回本地数据
* 处理的是业务本身的异常
*/
public BaseResponse<Page<QuestionVO>> handleFallback(@RequestBody QuestionQueryRequest questionQueryRequest,
HttpServletRequest request, Throwable ex) {
// 可以返回本地数据或空数据
return ResultUtils.success(null);
}
2、熔断和限流规则例子
java
/**
* @author zzj
* 限流规则管理器
*/
@Component
public class SentinelRulesManager {
@PostConstruct
public void initRules() {
initFlowRules();
initDegradeRules();
}
// 限流规则
public void initFlowRules() {
// 单 IP 查看题目列表限流规则
ParamFlowRule rule = new ParamFlowRule("listQuestionVOByPage")
.setParamIdx(0) // 对第 0 个参数限流,即 IP 地址
.setCount(60) // 每分钟最多 60 次
.setDurationInSec(60); // 规则的统计周期为 60 秒
ParamFlowRuleManager.loadRules(Collections.singletonList(rule));
}
// 降级规则
public void initDegradeRules() {
// 单 IP 查看题目列表熔断规则
DegradeRule slowCallRule = new DegradeRule("listQuestionVOByPage")
.setGrade(CircuitBreakerStrategy.SLOW_REQUEST_RATIO.getType())
.setCount(0.2) // 慢调用比例大于 20%
.setTimeWindow(60) // 熔断持续时间 60 秒
.setStatIntervalMs(30 * 1000) // 统计时长 30 秒
.setMinRequestAmount(10) // 最小请求数
.setSlowRatioThreshold(3); // 响应时间超过 3 秒
DegradeRule errorRateRule = new DegradeRule("listQuestionVOByPage")
.setGrade(CircuitBreakerStrategy.ERROR_RATIO.getType())
.setCount(0.1) // 异常率大于 10%
.setTimeWindow(60) // 熔断持续时间 60 秒
.setStatIntervalMs(30 * 1000) // 统计时长 30 秒
.setMinRequestAmount(10); // 最小请求数
// 加载规则
DegradeRuleManager.loadRules(Arrays.asList(slowCallRule, errorRateRule));
}
}
3、正常请求--->限流
-
当请求到61次时,进行限流
-
-
4、触发熔断
-
请求一个不存在的值,触发异常熔断
-
随后进入熔断降级操作,返回空对象
正常请求也返回空对象
-
但是我在
熔断期间请求数频繁时
又会触发限流,并且返回限流规则,无法返回降级规则-
这里可知,限流的优先级是要高于熔断的,并且两个规则是独立的。