前言
sentinel 是面向分布式服務架構的流量控制組件,主要以流量為切入點,從限流、流量整形、熔斷降級、系統負載保護、熱點防護等多個維度來幫助開發者保障微服務的穩定性。自從hytrix 2018年進入維護狀態,再到springcloud 2020.0版本hytrix被移除,就可以料想未來一段時間springcloud全家桶的熔斷降級組件基本上的首選就是alibaba sentinel。
今天就來聊聊因不恰當使用alibaba sentinel,而導致熔斷降級失效的一些例子。因為sentinel還在不斷迭代更新中,不同版本會有一些差異,而且在版本的迭代中,有些問題可能也已經修復。
本文演示的版本使用的sentinel-dashboard是1.8.0。使用springcloud alibaba的版本為2.2.3.RELEASE
失效場景例子
1、降級不生效問題
a、原因分析
項目中使用了自定義全局異常處理,而異常數或者異常比例的統計在
com.alibaba.csp.sentinel.adapter.spring.webmvc.AbstractSentinelInterceptor.afterCompletion
這個方法執行,自定義全局異常的處理會先於
com.alibaba.csp.sentinel.adapter.spring.webmvc.AbstractSentinelInterceptor.afterCompletion
這個方法執行執行,因為我們在全局異常里面已經對異常進行處理,比如轉換為一個對象,這樣導致AbstractSentinelInterceptor.afterCompletion無法獲取到異常,進而無法統計異常數或者異常比例。
b、解決方案
在官方的issue中已經有網友提出了解決思路
https://github.com/alibaba/Sentinel/issues/1281
和
https://github.com/alibaba/Sentinel/issues/404
因為我是在查issue的之前,就通過源碼跟蹤,找到答案,這邊說下我的實現思路。我的思路是定義一個切面,在切面的AfterThrowing進行異常統計。因為切面會在全局異常之前執行。統計的源碼我是直接把sentinel統計的源拷貝過來,核心代碼如下
@Aspect
@Component
@Slf4j
public class StatisticsExceptionCountAspect {
@Autowired
@Lazy
private BaseWebMvcConfig baseWebMvcConfig;
@Pointcut("execution(* com.github.lybgeek.sentinel.controller..*.*(..))")
public void pointcut(){
}
@AfterThrowing(pointcut = "pointcut()",throwing = "ex")
public void afterAfterThrowing(Throwable ex){
log.info("statisticsExceptionCount...");
traceException(ex);
}
/**
* 統計異常
* @param ex
*/
private void traceException(Throwable ex) {
Entry entry = getEntryInRequest();
if (entry != null) {
Tracer.traceEntry(ex, entry);
}
}
protected Entry getEntryInRequest() {
RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
ServletRequestAttributes attributes = (ServletRequestAttributes)requestAttributes;
HttpServletRequest request = attributes.getRequest();
Object entryObject = request.getAttribute(baseWebMvcConfig.getRequestAttributeName());
return entryObject == null ? null : (Entry)entryObject;
}
}
2、授權規則不生效問題
a、原因分析
項目中沒有實現
com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser
接口,導致無法解析請求來源
b、解決方案
在項目中自定義請求來源解析器。示例代碼如下
**
* @description: 解析訪問來源,用於授權規則--黑白名單。
* 當要進行授權規則時,則必須配置RequestOriginParser,否則授權規則無法生效
*
**/
@Component
public class CustomRequestOriginParser implements RequestOriginParser {
@Override
public String parseOrigin(HttpServletRequest request) {
String origin = request.getParameter("origin");
if(!StringUtils.isEmpty(origin)){
//根據接口是否攜帶origin參數,如果攜帶參數為origin=pc,
// 且sentinel-dashbord授權規則,來源設置為pc時,則表示要對請求來源為pc,進行黑白名單配置
return origin;
}
//如果沒請求參數接口沒有攜帶,則表示按ip進行黑白名單設置
return request.getRemoteAddr();
}
}
3、熱點規則不生效問題
a、原因分析
web埋點如果以url作為資源名,規則不生效
b、解決方案
以@SentinelResource注解定義的name作為資源名
參考官方issue
https://github.com/alibaba/Sentinel/issues/1734
配置熱點規則配置@SentinelResource后,可能還會出現
java.lang.reflect.UndeclaredThrowableException: null
解決方法:需要在方法中添加throws BlockException或添加blockHandler來處理異常
參考官方issue
https://github.com/alibaba/Sentinel/issues/776
示例代碼
@GetMapping(value = "/paramFlowRule/{msg}")
@ApiImplicitParams({
@ApiImplicitParam(name="msg",defaultValue = "hello",value="信息", paramType = "path"),
})
@ApiOperation(value = "測試熱點規則")
@SentinelResource(value = "testParamFlowRule")
public AjaxResult<String> testParamFlowRule(@PathVariable("msg") String msg) throws BlockException {
System.out.println(String.format("msg : %s",msg));
return AjaxResult.success("測試熱點規則");
}
總結
本文主要介紹了常見使用alibaba sentinel可能遇到的問題,不得說下阿里在國內開源做的真的挺好的,大部分問題在官方issue都能找到解答
文章下方的demo鏈接,提供其他熔斷降級例子以及基於文件持久熔斷降級配置的功能例子。感興趣的朋友可以蠻看看。
demo鏈接
https://github.com/lyb-geek/springboot-learning/tree/master/springboot-sentinel