Sentinel
Sentinel copied to clipboard
SpringMVC异步情况下System的Thread限流计数有问题
背景
使用SpringMVC进行Sentinel限流,配置了System的Thread最大数限流规则。
当使用SpringMVC @Callable
异步模式后,SystemRule的当前线程数会不停的放大,一直递增不扣减,请求次数超过最大线程数就会出现BlockingException,后面所有请求都会是这个错,无法恢复。
业务代码:
@ResponseBody
@GetMapping("/async")
public Callable<String> async() throws Exception {
Callable<String> callable = () -> {
TimeUnit.MILLISECONDS.sleep(50); //
return "hello world";
};
return callable;
}
问题分析
通过打断点分析发现是因为SpringMVC异步情况下preHandle会进来两次,Sentinel的AbstractSentinelInterceptor拦截器会两次计数,导致Entry没有退出。
关于异步两次进入preHandler可以参考这个解决方案: https://stackoverflow.com/questions/26995395/spring-mvc-interceptorhandler-called-twice-with-deferredresult
#2810 @sczyh30 @brotherlu-xcq 使用栈来替换之前的引用计数
preHandler
入栈一个 preEvent
postHandler
中入栈 postEvent
在 afterCompletion
对事件进行闭合处理 ,一个postEvent
和他之前连续最远的一个 preEvent
进行匹配闭合,