结合上文,流量控制测试对应的Controller 如下所示
// 流量控制
// http://localhost:8880/test/flow
@SentinelResource(value = "flowResource", blockHandler = "flowBlockHandler", fallback = "flowFallback")
@RequestMapping("/flow")
@ResponseBody
public String flow(@RequestBody String request) {
System.out.println(request);
return "This is Flow Page";
}
// 返回值类型必须与原函数返回值类型一致;
// 方法参数列表需要和原函数一致,或者可以额外多一个 BlockException 类型的参数用于接收对应的异常。
public String flowBlockHandler(@RequestBody String request, BlockException ex) {
return "flowBlockHandler";
}
// 返回值类型必须与原函数返回值类型一致;
// 方法参数列表需要和原函数一致,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。
public String flowFallback(@RequestBody String request, Throwable throwable) {
return "flowFallback";
}
yml 中流量控制规则配置如下
sentinel:
flow:
rules: "[{'resource':'flowResource', 'grade':'1', 'strategy':'0', 'count':'1', 'controlBehavior':'0'}]"
对应的含义是:
- grade=1,表示按照QPS 进行流量控制
- strategy=0,表示流控模式为直接
- count=1,表示QPS超过1后触发流量控制
- controlBehavior=0,表示流控效果为快速失败
当发起请求速度超过1QPS 之后,会触发BlockException 异常,对应触发blockHandler = “flowBlockHandler” 方法,在客户端收到对应的返回值flowBlockHandler
使用Postman 很容易模拟这种场景
fallback 功能测试
Sentinel 支持通过@SentinelResource 注解定义资源并配置blockHandler 和fallback 函数来进行限流之后的处理。注意blockHandler 函数会在原方法被限流/降级/系统保护的时候调用,而fallback 函数会针对所有类型的异常
如果把flow() 方法修改为下面这样,直接抛出异常
// 流量控制
// http://localhost:8880/test/flow
@SentinelResource(value = "flowResource", blockHandler = "flowBlockHandler", fallback = "flowFallback")
@RequestMapping("/flow")
@ResponseBody
public String flow(@RequestBody String request) {
throw new ExceptionMain();
}
因为blockHandler 函数会在原方法被限流/降级/系统保护的时候调用,而fallback 函数会针对所有类型的异常,所以会触发fallback = “flowFallback” 的回调
这一点很有用,对应在我们的业务场景中,可以把需要处理的数据库异常等进行特殊封装,使用fallback 进行捕获,然后进行相关处理
流量控制规则只支持按照线程数和QPS 方式控制,比如想实现基于应答时间控制的逻辑,则行不通,那么可以选择熔断机制,参见下一篇文章