国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|JavaScript|易語言|

服務器之家 - 編程語言 - Java教程 - 一篇帶給你Sentinel 流控原理

一篇帶給你Sentinel 流控原理

2021-05-24 23:51運維開發故事老鄭 Java教程

配置流控規則我們最簡單的方式就是通過 @ResoureSetinel 的方式來管理,該注解可以直接定義流控規則、降級規則。

一篇帶給你Sentinel 流控原理

我們在項目中添加 Spring Cloud Sentinel 依賴添加后 spring-cloud-starter-alibaba-sentinel 在 Spring-Boot 啟動的過程中回去初始化 spring.factories 中的配置信息,如:SentinelWebAutoConfiguration 、SentinelAutoConfiguration 等配置文件來初始化

再講代碼之前我先聲明一下我的版本號sentinel 1.8.0 。后續的所有內容均基于該版本進行

@ResoureSetinel 工作原理

 

配置流控規則我們最簡單的方式就是通過 @ResoureSetinel 的方式來管理,該注解可以直接定義流控規則、降級規則。下面是一個簡單的使用例子:

  1. @SentinelResource(value = "ResOrderGet"
  2.                   fallback = "fallback"
  3.                   fallbackClass = SentinelResourceExceptionHandler.class, 
  4.                   blockHandler = "blockHandler"
  5.                   blockHandlerClass = SentinelResourceExceptionHandler.class 
  6.                  ) 
  7. @GetMapping("/order/get/{id}"
  8. public CommonResult<StockModel> getStockDetails(@PathVariable Integer id) { 
  9.   StockModel stockModel = new StockModel(); 
  10.   stockModel.setCode("STOCK==>1000"); 
  11.   stockModel.setId(id); 
  12.   return CommonResult.success(stockModel); 

如果大家熟悉 Spring 相關的組件大家都可以想到,這里多半是通過Spring Aop. 的方式來攔截 getStockDetails 方法。我們先看看SentinelAutoConfiguration 配置文件,我們可以找到 SentinelResourceAspect Bean 的定義方法。

  1. @Bean 
  2. @ConditionalOnMissingBean 
  3. public SentinelResourceAspect sentinelResourceAspect() { 
  4.    return new SentinelResourceAspect(); 

讓后我們再來看看 SentinelResourceAspect 具體是怎么處理的,源碼如下:

  1. // 定義 Pointcut 
  2. @Pointcut("@annotation(com.alibaba.csp.sentinel.annotation.SentinelResource)"
  3. public void sentinelResourceAnnotationPointcut() { 
  4. // Around 來對被標記 @SentinelResource 注解的方法進行處理 
  5. @Around("sentinelResourceAnnotationPointcut()"
  6. public Object invokeResourceWithSentinel(ProceedingJoinPoint pjp) throws Throwable { 
  7.   Method originMethod = resolveMethod(pjp); 
  8.   // 獲取注解信息 
  9.   SentinelResource annotation = originMethod.getAnnotation(SentinelResource.class); 
  10.   // 獲取資源名稱 
  11.   String resourceName = getResourceName(annotation.value(), originMethod); 
  12.   EntryType entryType = annotation.entryType(); 
  13.   int resourceType = annotation.resourceType(); 
  14.   Entry entry = null
  15.   try { 
  16.     // 執行 entry 
  17.     entry = SphU.entry(resourceName, resourceType, entryType, pjp.getArgs()); 
  18.     // 執行業務方法 
  19.     Object result = pjp.proceed(); 
  20.     // 返回 
  21.     return result; 
  22.   } catch (BlockException ex) { 
  23.     // 處理 BlockException 
  24.     return handleBlockException(pjp, annotation, ex); 
  25.   } catch (Throwable ex) { 
  26.     Class<? extends Throwable>[] exceptionsToIgnore = annotation.exceptionsToIgnore(); 
  27.     // The ignore list will be checked first
  28.     if (exceptionsToIgnore.length > 0 && exceptionBelongsTo(ex, exceptionsToIgnore)) { 
  29.       throw ex; 
  30.     } 
  31.     if (exceptionBelongsTo(ex, annotation.exceptionsToTrace())) { 
  32.       traceException(ex); 
  33.       // 處理降級 
  34.       return handleFallback(pjp, annotation, ex); 
  35.     } 
  36.     // No fallback function can handle the exception, so throw it out
  37.     throw ex; 
  38.   } 

我們總結一下, @SentinelResource 的執行過程, 首先是通過 Aop 進行攔截,然后通過 SphU.entry 執行對應的流控規則,最后調用業務方法。如果觸發流控規則首先處理流控異常 BlockException 然后在判斷是否有服務降級的處理,如果有就調用 fallback 方法。通過 handleBlockException 、handleFallback 進行處理。

責任鏈模式處理流控

 

通過上面的梳理,我們知道對于流控的過程,核心處理方法就是 SphU.entry 。在這個方法中其實主要就是初始化流控 Solt 和執行 Solt. 在這個過程中會對:簇點定義、流量控制、熔斷降級、系統白名單等頁面功能進行處理。

1. 初始化責任鏈

 

下面是初始化 Solt 的核心代碼在 SphU.entryWithPriority

  1. // 刪減部分代碼 
  2. private Entry entryWithPriority(ResourceWrapper resourceWrapper, int count, boolean prioritized, Object... args) 
  3.   throws BlockException { 
  4.   // 初始化責任鏈 
  5.   ProcessorSlot<Object> chain = lookProcessChain(resourceWrapper); 
  6.   Entry e = new CtEntry(resourceWrapper, chain, context); 
  7.   try { 
  8.     // 執行 entry 
  9.     chain.entry(context, resourceWrapper, nullcount, prioritized, args); 
  10.   } catch (BlockException e1) { 
  11.     e.exit(count, args); 
  12.     // 異常拋出,讓 SentinelResourceAspect.invokeResourceWithSentinel 統一處理 
  13.     throw e1; 
  14.   } catch (Throwable e1) { 
  15.     // This should not happen, unless there are errors existing in Sentinel internal. 
  16.     RecordLog.info("Sentinel unexpected exception", e1); 
  17.   } 
  18.   return e; 

通過 lookProcessChain 方法我逐步的查找,我們可以看到最終的責任鏈初始化類,默認是 DefaultSlotChainBuilder

 

  1. public class DefaultSlotChainBuilder implements SlotChainBuilder { 
  2.     @Override 
  3.     public ProcessorSlotChain build() { 
  4.         ProcessorSlotChain chain = new DefaultProcessorSlotChain(); 
  5.         // Note: the instances of ProcessorSlot should be different, since they are not stateless. 
  6.         // 通過 SPI 去加載所有的  ProcessorSlot 實現,通過 Order 排序 
  7.         List<ProcessorSlot> sortedSlotList = SpiLoader.loadPrototypeInstanceListSorted(ProcessorSlot.class); 
  8.         for (ProcessorSlot slot : sortedSlotList) { 
  9.             if (!(slot instanceof AbstractLinkedProcessorSlot)) { 
  10.                 RecordLog.warn("The ProcessorSlot(" + slot.getClass().getCanonicalName() + ") is not an instance of AbstractLinkedProcessorSlot, can't be added into ProcessorSlotChain"); 
  11.                 continue
  12.             } 
  13.                       // 添加到 chain 尾部 
  14.             chain.addLast((AbstractLinkedProcessorSlot<?>) slot); 
  15.         } 
  16.         return chain; 
  17.     } 

2. 責任鏈的處理過程

 

我們可以通過斷點的方式來查看在 sortedSlotList 集合中所有的 solt 順序如下圖所示:

一篇帶給你Sentinel 流控原理

我們可以通過如下的順序進行逐個的簡單的分析一下

  • NodeSelectorSolt
  • CusterBuilderSolt
  • LogSlot
  • StatisicSlot
  • AuthoritySolt
  • SystemSolts
  • ParamFlowSolt
  • FlowSolt
  • DegradeSlot

對于 Sentinel 的 Slot 流控協作流程可以參考官方給出的文檔, 如下圖所示:

一篇帶給你Sentinel 流控原理

FlowSolt 流控

 

通過 NodeSelectorSolt、CusterBuilderSolt、StatisicSlot 等一系列的請求數據處理,在 FlowSolt會進入流控規則,所有的 Solt 都會執行 entry 方法, 如下所示

  1. // FlowSolt 的 entry 方法 
  2. @Override 
  3. public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count
  4.                   boolean prioritized, Object... args) throws Throwable { 
  5.   // 檢查流量 
  6.   checkFlow(resourceWrapper, context, node, count, prioritized); 
  7.   fireEntry(context, resourceWrapper, node, count, prioritized, args); 

在后續的流程中,會執進行判斷具體的流控策略,默認是快速失敗,會執行 DefaultController 方法。

  1. // DefaultController 
  2. @Override 
  3. public boolean canPass(Node node, int acquireCount, boolean prioritized) { 
  4.   // 當前資源的調用次數 
  5.   int curCount = avgUsedTokens(node); 
  6.   // 當前資源的調用次數 + 1 > 當前閾值 
  7.   if (curCount + acquireCount > count) { 
  8.     // 刪減比分代碼 
  9.     // 不通過 
  10.     return false
  11.   } 
  12.   // 通過 
  13.   return true
  14. private int avgUsedTokens(Node node) { 
  15.   if (node == null) { 
  16.     return DEFAULT_AVG_USED_TOKENS; 
  17.   } 
  18.   return grade == RuleConstant.FLOW_GRADE_THREAD ? node.curThreadNum() : (int)(node.passQps()); 

如果上面返回不通過會回到,那么會拋出 FlowException

  1. public void checkFlow(Function<String, Collection<FlowRule>> ruleProvider, ResourceWrapper resource, 
  2.                       Context context, DefaultNode node, int count, boolean prioritized) throws BlockException { 
  3.   if (ruleProvider == null || resource == null) { 
  4.     return
  5.   } 
  6.   Collection<FlowRule> rules = ruleProvider.apply(resource.getName()); 
  7.   if (rules != null) { 
  8.     for (FlowRule rule : rules) { 
  9.       if (!canPassCheck(rule, context, node, count, prioritized)) { 
  10.         // 流控規則不通過,會拋出 FlowException 
  11.         throw new FlowException(rule.getLimitApp(), rule); 
  12.       } 
  13.     } 
  14.   } 

然后會在 StatisticSlot 中增加統計信息, 最后會拋出給 SentinelResourceAspect 進行處理,完成流控功能。我們再來看看這個異常信息,如果是BlockException 異常,會進入 handleBlockException 方法處理, 如果是其他的業務異常首先會判斷是否有配置 fallback 處理如果有,就調用 handleFallback 沒有就繼續往外拋,至此完成流控功能

  1. try { 
  2.   entry = SphU.entry(resourceName, resourceType, entryType, pjp.getArgs()); 
  3.   Object result = pjp.proceed(); 
  4.   return result; 
  5. } catch (BlockException ex) { 
  6.   return handleBlockException(pjp, annotation, ex); 
  7. } catch (Throwable ex) { 
  8.   Class<? extends Throwable>[] exceptionsToIgnore = annotation.exceptionsToIgnore(); 
  9.   // The ignore list will be checked first
  10.   if (exceptionsToIgnore.length > 0 && exceptionBelongsTo(ex, exceptionsToIgnore)) { 
  11.     throw ex; 
  12.   } 
  13.   if (exceptionBelongsTo(ex, annotation.exceptionsToTrace())) { 
  14.     traceException(ex); 
  15.     return handleFallback(pjp, annotation, ex); 
  16.   } 
  17.   // No fallback function can handle the exception, so throw it out
  18.   throw ex; 

DegradeSlot 降級

 

斷路器的作用是當某些資源一直出現故障時,將觸發斷路器。斷路器不會繼續訪問已經發生故障的資源,而是攔截請求并返回故障信號。

Sentinel 在 DegradeSlot 這個 Slot 中實現了熔斷降級的功能,它有三個狀態 OPEN 、HALF_OPEN、CLOSED 以ResponseTimeCircuitBreaker RT 響應時間維度來分析, 斷路器工作的過程。下面是一個標準斷路器的工作流程:

一篇帶給你Sentinel 流控原理

在 Sentinel 實現的源碼過程如下圖所示:

一篇帶給你Sentinel 流控原理

Sentinel 通過 Web 攔截器

 

Sentinel 在默認情況下, 不使用 @ResourceSentinel 注解實現流控的時候, Sentinel 通過攔截器進行流控實現的。初始化類在 SentinelWebAutoConfiguration 它實現了 WebMvcConfigurer 接口,在 sentinelWebInterceptor 方法初始化 SentinelWebInterceptor 等 Bean。

  1. @Bean 
  2. @ConditionalOnProperty(name = "spring.cloud.sentinel.filter.enabled"
  3.                        matchIfMissing = true
  4. public SentinelWebInterceptor sentinelWebInterceptor( 
  5.   SentinelWebMvcConfig sentinelWebMvcConfig) { 
  6.   return new SentinelWebInterceptor(sentinelWebMvcConfig); 

我們在 SentinelWebInterceptor 的核心方法 preHandle 中處理,這里面我們又可以看到 SphU.entry 熟悉的過程調用流控的責任鏈。由于邏輯都類似,此處不再多說。代碼如下:

  1. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) 
  2.   throws Exception { 
  3.   try { 
  4.     String resourceName = getResourceName(request); 
  5.     if (StringUtil.isEmpty(resourceName)) { 
  6.       return true
  7.     } 
  8.     if (increaseReferece(request, this.baseWebMvcConfig.getRequestRefName(), 1) != 1) { 
  9.       return true
  10.     } 
  11.     // Parse the request origin using registered origin parser. 
  12.     String origin = parseOrigin(request); 
  13.     String contextName = getContextName(request); 
  14.     ContextUtil.enter(contextName, origin); 
  15.     Entry entry = SphU.entry(resourceName, ResourceTypeConstants.COMMON_WEB, EntryType.IN); 
  16.     request.setAttribute(baseWebMvcConfig.getRequestAttributeName(), entry); 
  17.     return true
  18.   } catch (BlockException e) { 
  19.     try { 
  20.       handleBlockException(request, response, e); 
  21.     } finally { 
  22.       ContextUtil.exit(); 
  23.     } 
  24.     return false
  25.   } 

參考文檔

https://github.com/alibaba/Sentinel/wiki

https://martinfowler.com/bliki/CircuitBreaker.html

原文鏈接:https://mp.weixin.qq.com/s/88ZnMVwvMKVk_uWTOvK-qg

延伸 · 閱讀

精彩推薦
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25 Weibo Article 26 Weibo Article 27 Weibo Article 28 Weibo Article 29 Weibo Article 30 Weibo Article 31 Weibo Article 32 Weibo Article 33 Weibo Article 34 Weibo Article 35 Weibo Article 36 Weibo Article 37 Weibo Article 38 Weibo Article 39 Weibo Article 40
主站蜘蛛池模板: 亚洲影视一区 | 中文字幕国产 | 成人中文字幕在线观看 | 激情综合网激情 | 日韩欧美国产一区二区三区 | 欧美视频免费在线 | 久久亚洲欧美日韩精品专区 | 日韩国产在线看 | 欧美乱大交xxxxx春色视频 | 在线观看国产 | 国产性猛交xxxx免费看久久 | 亚洲国产一区在线 | 夜夜嗨aⅴ免费视频 | 国内自拍网站 | 国产高清久久久 | 欧美成人精品高清视频在线观看 | 国产精品亚洲视频 | 国产宾馆自拍 | 亚洲一区免费观看 | 欧美一区在线视频 | 一区二区三区影视 | 久久久精品网 | 欧美成人精品在线视频 | 麻豆二区 | 国产在线观看二区 | 一区二区三区视频 | 亚洲一本 | 中文av字幕 | 国产精品久久久久久亚洲调教 | 中文字幕在线观看av | 国产a视频 | 欧美国产精品一区 | 日韩中文字幕在线观看视频 | 中文字幕在线电影观看 | 少妇一级片免费看 | 成人免费毛片高清视频 | 久久午夜网站 | 桃色视频在线播放 | 懂色一区二区三区av片 | 成人av电影网址 | 91在线视频播放 |