<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Alibaba Sentinel流控詳解

          共 9741字,需瀏覽 20分鐘

           ·

          2021-06-13 18:17

          點(diǎn)擊上方藍(lán)色字體,選擇“標(biāo)星公眾號(hào)”

          優(yōu)質(zhì)文章,第一時(shí)間送達(dá)

          概述

           流量控制(flow control),其原理是監(jiān)控應(yīng)用流量的 QPS 或并發(fā)線程數(shù)等指標(biāo),當(dāng)達(dá)到指定的閾值時(shí)對(duì)流量進(jìn)行控制,以避免被瞬時(shí)的流量高峰沖垮,從而保障應(yīng)用的高可用性。

           

          限流類(lèi)型分為:

          • QPS 每秒請(qǐng)求數(shù)限制

          • 線程數(shù) 資源使用線程數(shù)限制

          流控模式

          • 直接 資源直接限流,這個(gè)就是簡(jiǎn)單的限流。

          • 關(guān)聯(lián) 關(guān)聯(lián)模式需要填寫(xiě)關(guān)聯(lián)資源的路徑,意為如果關(guān)聯(lián)資源的流量超額之后,限流自己(自己為資源名填寫(xiě)的路徑)。

          • 鏈路 如果是鏈路模式需要填寫(xiě)入口資源,限制入口資源對(duì)自己的調(diào)用,這里不太好理解,下面進(jìn)行測(cè)試。

          流控效果

          • 快速失敗 直接拋異常了

          • Warm Up 需要填寫(xiě)預(yù)熱時(shí)間,表示,在預(yù)熱時(shí)間內(nèi),慢慢的達(dá)到QPS的限制。

          • 排隊(duì)等待 需要填寫(xiě)超時(shí)時(shí)間,排隊(duì)很好理解啦。

          1.QPS測(cè)試

          設(shè)置/hello的QPS為1。

          @GetMapping(value = "/hello")
          public String hello() {
              return "Hello Sentinel1";
          }

          這個(gè)比較好理解,直接快速訪問(wèn)hello即可。

          正常的時(shí)候返回

          Hello Sentinel1

          如果訪問(wèn)太快,會(huì)返回如下,表示流量控制。

          Blocked by Sentinel (flow limiting)

          2.線程數(shù)測(cè)試

          線程數(shù)限制,表示執(zhí)行當(dāng)前方法的線程數(shù)控制,因?yàn)樵L問(wèn)太快,加入sleep,方便測(cè)試。

          @GetMapping(value = "/hello")
          public String hello() {
              try {
                  Thread.sleep(1000);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
              return "Hello Sentinel1";
          }

          線程數(shù)設(shè)置1

          使用jmeter進(jìn)行測(cè)試。jmeter設(shè)置一秒2個(gè)請(qǐng)求。在View Results Tree中會(huì)有1個(gè)成功1個(gè)限流。

          至于QPS限制,還是線程限制,需要不同的場(chǎng)景,進(jìn)行選擇。

          3.關(guān)聯(lián)測(cè)試

          設(shè)置/hello的關(guān)聯(lián)資源為/hello2,表示如果hello2超過(guò)每秒1次的話,限制hello1。這個(gè)久很怪異,明明不管我的的事,卻要限制我,但是存在即合理,應(yīng)該也有這樣的場(chǎng)景。

              @GetMapping(value = "/hello")
              public String hello() {
                  return "Hello Sentinel1";
              }
              @GetMapping(value = "/hello2")
              public String hello2() {
                  return "Hello Sentinel2";
              }

          先通過(guò)jmeter對(duì)hello進(jìn)行頻繁訪問(wèn),正常返回,沒(méi)有測(cè)試出限流。再對(duì)hello2進(jìn)行頻繁訪問(wèn),正常返回,沒(méi)有限流。

          驗(yàn)證關(guān)聯(lián)控制。jmeter設(shè)置hello2為10秒請(qǐng)求30次,表示前10秒內(nèi)hello返回限流。hello在這15秒請(qǐng)求15次,多5秒就是想測(cè)試沒(méi)有了hello2的頻繁訪問(wèn),是否還限流。

          設(shè)置信息如下。


          hello2的返回信息一切正常。

          hello前10秒限流,后5秒正常返回。

          4.鏈路測(cè)試

              @Autowired
              private TestService testService;
              @GetMapping(value = "/hello")
              public String hello() {
                  testService.listOrder();
                  return "Hello Sentinel1";
              }
              @GetMapping(value = "/hello2")
              public String hello2() {
                  testService.listOrder();
                  return "Hello Sentinel2";
              }

          @Service
          public class TestService {
              //資源信息
              @SentinelResource("listOrder")
              public void listOrder(){
                  System.out.println("listOrder");
              }
          }

          這樣就形成了一個(gè)鏈路。一個(gè)controller對(duì)service調(diào)用的鏈路。在頁(yè)面上有如下信息。

          配置listOrder流控,鏈路入口為/hello

          如此,配置即可限制/hello對(duì)listOrder的調(diào)用次數(shù)。當(dāng)然在微服務(wù)之間也可以這么去設(shè)置。現(xiàn)在又對(duì)這個(gè)針對(duì)來(lái)源的概念模糊了,這兩個(gè)不一樣么?針對(duì)來(lái)源默認(rèn)為default,,表示不區(qū)分來(lái)源,處理服務(wù)之間的限制,如果細(xì)化到方法的層面上,針對(duì)來(lái)源的設(shè)置無(wú)法做到,這時(shí)就需要進(jìn)行鏈路設(shè)置。

          5.快速失敗

          流控效果中快速失敗是最簡(jiǎn)單的限流處理策略,直接拋了個(gè)異常。

          自定義失敗

          在被限流的時(shí)候拋出 FlowException 異常。FlowException 是 BlockException 的子類(lèi),您可以捕捉 BlockException 來(lái)自定義被限流之后的處理邏輯。

          官方是這么說(shuō)的,但是在直接對(duì)controller的接口進(jìn)行限制的時(shí)候,通過(guò)spring全局異常捕獲死活捕獲不到。后來(lái)發(fā)現(xiàn)這里發(fā)現(xiàn),這里進(jìn)行controller的流量控制是通過(guò)Filter來(lái)控制的,所有spring的全局異常根本無(wú)法捕獲。

          @ControllerAdvice
          @RestController
          public class CommonException {
              @ExceptionHandler(BlockException.class)
              public String customException(Exception e) {
                  return "系統(tǒng)出小差,請(qǐng)稍后再試。";
              }
              @ExceptionHandler(UndeclaredThrowableException.class)
              public String undeclaredThrowableException(Exception e) {
                  return "系統(tǒng)出小差,請(qǐng)稍后再試。";
              }
              @ExceptionHandler(Exception.class)
              public String exception(Exception e) {
                  return "系統(tǒng)出小差,請(qǐng)稍后再試。";
              }
          }

          如此,可以通過(guò)WebCallbackManager.setUrlBlockHandler設(shè)置限流之后的處理類(lèi)。

          注意:Filter的具體實(shí)現(xiàn)在CommonFilter中,有的版本通過(guò)攔截器實(shí)現(xiàn),可以試著搜索AbstractSentinelInterceptor,可能這種小改動(dòng)不會(huì)影響什么,所以貌似官方?jīng)]有說(shuō)明。

          @Configuration
          public class Config {
          static {
              WebCallbackManager.setUrlBlockHandler(new UrlBlockHandler() {
                  @Override
                  public void blocked(HttpServletRequest request, HttpServletResponse response, BlockException ex) throws IOException {
                      // 簡(jiǎn)單演示,這里可以自行處理
                      PrintWriter out = response.getWriter();
                      out.print("try again later");
                      out.flush();
                      out.close();
                  }
              });
          }
          }

          當(dāng)然,全局異常處理并不能解決所有的問(wèn)題,更多的時(shí)候是希望每個(gè)方法都有自己的處理邏輯。

             @SentinelResource(value = "helloResource" ,blockHandler = "getOrderDowngradeRtTypeFallback",fallback = "helloFallback")
              @GetMapping(value = "/hello")
              public String hello(@RequestParam(value = "id") Long id)  {
                  if(id==1l){
                      throw  new RuntimeException("1231");
                  }
                  return "SUCCESS";
              }
              public String helloFallback(Long id,Throwable e) {
                  System.out.println(1111);
                  return id+"helloFallback";
              }
              public String getOrderDowngradeRtTypeFallback(Long id,BlockException ex) {
                  return "服務(wù)降級(jí)啦,當(dāng)前服務(wù)器請(qǐng)求次數(shù)過(guò)多,請(qǐng)稍后重試!";
              }

          通過(guò)SentinelResource注解來(lái)自定義異常的處理。

          • blockHandler限流之后的補(bǔ)償處理方法。這里是限流的請(qǐng)求才會(huì)執(zhí)行這個(gè)方法。另外,還有blockHandlerClass效果一樣。

          • fallback 如果方法中有異常則執(zhí)行fallback指定的方法。另外,還有fallbackClass指定處理類(lèi),效果是一樣的。

          另外需要注意的是,如果添加SentinelResource注解之后,在控制臺(tái)會(huì)有如下信息。兩個(gè)都可以對(duì)這個(gè)方法進(jìn)行限制,但是/hello是通過(guò)Filter實(shí)現(xiàn)的(后面改成了攔截器)全局異常可能是攔截不到的哦,具體可以看源碼CommonFilter或者AbstractSentinelInterceptorhelloResource是通過(guò)AOP來(lái)實(shí)現(xiàn)的,所以全局異常是可以對(duì)此進(jìn)行處理的,源碼SentinelResourceAspect

          在使用之前版本的時(shí)候fallback 死活不好用,不知道是不是版本BUG。換成了這個(gè)版本就好用了, 也是在這個(gè)版本使用的時(shí)候,發(fā)現(xiàn)conroller限流從Filter變成了攔截器。

          <dependencyManagement>
                  <dependencies>
                      <dependency>
                          <groupId>org.springframework.cloud</groupId>
                          <artifactId>spring-cloud-dependencies</artifactId>
                          <version>Hoxton.RELEASE</version>
                          <type>pom</type>
                          <scope>import</scope>
                      </dependency>
                      <dependency>
                          <groupId>com.alibaba.cloud</groupId>
                          <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                          <version>2.2.1.RELEASE</version>
                          <type>pom</type>
                          <scope>import</scope>
                      </dependency>
                  </dependencies>
              </dependencyManagement>

          6.Warm Up

          這個(gè)是一個(gè)預(yù)熱的概念,比如服務(wù)剛剛啟動(dòng),所有的緩存還在加載中,不能有太多的請(qǐng)求進(jìn)來(lái),所以需要進(jìn)行一個(gè)服務(wù)的預(yù)熱,剛啟動(dòng)QPS限制小于設(shè)定數(shù)值,待服務(wù)啟動(dòng)一段時(shí)間后,慢慢的達(dá)到所設(shè)置的QPS。

           規(guī)則設(shè)置之后開(kāi)始預(yù)熱。

          如此設(shè)置,即可發(fā)現(xiàn),開(kāi)始的5秒中,QPS特別小,然后慢慢增加,到5秒的時(shí)候達(dá)到每秒10QPS。

          7.排隊(duì)等待

          設(shè)置超時(shí)時(shí)間后,如果QPS限制之后,會(huì)等待,超過(guò)設(shè)定時(shí)間后,拋出BlockException異常。



          本文鏈接:

          https://blog.csdn.net/qq_30285985/article/details/107692608








          瀏覽 47
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  久久亚洲精品影院 | 国产欧美欧美金五星的户外操逼。 | 亚洲电影区 | 色老板视频凹凸精品视频 | jizz少妇 |