<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>

          SpringCloud中Hystrix容錯(cuò)保護(hù)原理及配置,看它就夠了!

          共 63243字,需瀏覽 127分鐘

           ·

          2021-03-26 12:33

          點(diǎn)擊上方藍(lán)色“小哈學(xué)Java”,選擇“設(shè)為星標(biāo)

          回復(fù)“資源”獲取獨(dú)家整理的學(xué)習(xí)資料!

          作者:kosamino

          cnblogs.com/jing99/p/11625306.html

          1 什么是災(zāi)難性雪崩效應(yīng)?

          如下圖的過(guò)程所示,災(zāi)難性雪崩形成原因就大致如此:

          造成災(zāi)難性雪崩效應(yīng)的原因,可以簡(jiǎn)單歸結(jié)為下述三種:

          • 服務(wù)提供者不可用。如:硬件故障、程序BUG、緩存擊穿、并發(fā)請(qǐng)求量過(guò)大等。
          • 重試加大流量。如:用戶(hù)重試、代碼重試邏輯等。
          • 服務(wù)調(diào)用者不可用。如:同步請(qǐng)求阻塞造成的資源耗盡等。

          雪崩效應(yīng)最終的結(jié)果就是:服務(wù)鏈條中的某一個(gè)服務(wù)不可用,導(dǎo)致一系列的服務(wù)不可用,最終造成服務(wù)邏輯崩潰。這種問(wèn)題造成的后果,往往是無(wú)法預(yù)料的。

          2 如何解決災(zāi)難性雪崩效應(yīng)?

          解決災(zāi)難性雪崩效應(yīng)的方式通常有:降級(jí)、隔離、熔斷、請(qǐng)求緩存、請(qǐng)求合并。

          在Spring cloud中處理服務(wù)雪崩效應(yīng),都需要依賴(lài)hystrix組件。在pom文件中都需要引入下述依賴(lài):

          <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-hystrix</artifactId>
          </dependency>

          通常來(lái)說(shuō),開(kāi)發(fā)的時(shí)候,使用ribbon處理服務(wù)災(zāi)難雪崩效應(yīng)(因此章節(jié)2示例均采用Ribbon,章節(jié)3是Feign實(shí)現(xiàn)方式詳解),開(kāi)發(fā)的成本低。維護(hù)成本高。使用feign技術(shù)處理服務(wù)災(zāi)難雪崩效應(yīng),開(kāi)發(fā)的成本較高,維護(hù)成本低。

          2.1 降級(jí)

          降級(jí)是指,當(dāng)請(qǐng)求超時(shí)、資源不足等情況發(fā)生時(shí)進(jìn)行服務(wù)降級(jí)處理,不調(diào)用真實(shí)服務(wù)邏輯,而是使用快速失?。╢allback)方式直接返回一個(gè)托底數(shù)據(jù),保證服務(wù)鏈條的完整,避免服務(wù)雪崩。

          解決服務(wù)雪崩效應(yīng),都是避免application client請(qǐng)求application service時(shí),出現(xiàn)服務(wù)調(diào)用錯(cuò)誤或網(wǎng)絡(luò)問(wèn)題。處理手法都是在application client中實(shí)現(xiàn)。我們需要在application client相關(guān)工程中導(dǎo)入hystrix依賴(lài)信息。

          并在對(duì)應(yīng)的啟動(dòng)類(lèi)上增加新的注解@EnableCircuitBreaker,這個(gè)注解是用于開(kāi)啟hystrix熔斷器的,簡(jiǎn)言之,就是讓代碼中的hystrix相關(guān)注解生效。

          引入依賴(lài):

          <!-- hystrix依賴(lài), 處理服務(wù)災(zāi)難雪崩效應(yīng)的。 -->
          <dependency>
              <groupId>org.springframework.cloud</groupId>
              <artifactId>spring-cloud-starter-hystrix</artifactId>
          </dependency>

          啟動(dòng)器代碼:

          /**
           * @EnableCircuitBreaker - 開(kāi)啟斷路器。就是開(kāi)啟hystrix服務(wù)容錯(cuò)能力。
           * 當(dāng)應(yīng)用啟用Hystrix服務(wù)容錯(cuò)的時(shí)候,必須增加的一個(gè)注解。
           */

          @EnableCircuitBreaker
          @EnableEurekaClient
          @SpringBootApplication
          public class HystrixApplicationClientApplication {
              public static void main(String[] args) {
                SpringApplication.run(HystrixApplicationClientApplication.classargs);
              }
          }

          在調(diào)用application service相關(guān)代碼中,增加新的方法注解@HystrixCommand,代表當(dāng)前方法啟用Hystrix處理服務(wù)雪崩效應(yīng)。

          @HystrixCommand注解中的屬性:fallbackMethod - 代表當(dāng)調(diào)用的application service出現(xiàn)問(wèn)題時(shí),調(diào)用哪個(gè)fallback快速失敗處理方法返回托底數(shù)據(jù)。

          實(shí)現(xiàn)類(lèi):

          @Service
          public class HystrixService {

              @Autowired
              private LoadBalancerClient loadBalancerClient;

              /**
               * 服務(wù)降級(jí)處理。
               * 當(dāng)前方法遠(yuǎn)程調(diào)用application service服務(wù)的時(shí)候,如果service服務(wù)出現(xiàn)了任何錯(cuò)誤(超時(shí),異常等)
               * 不會(huì)將異常拋到客戶(hù)端,而是使用本地的一個(gè)fallback(錯(cuò)誤返回)方法來(lái)返回一個(gè)托底數(shù)據(jù)。
               * 避免客戶(hù)端看到錯(cuò)誤頁(yè)面。
               * 使用注解來(lái)描述當(dāng)前方法的服務(wù)降級(jí)邏輯。
               * @HystrixCommand - 開(kāi)啟Hystrix命令的注解。代表當(dāng)前方法如果出現(xiàn)服務(wù)調(diào)用問(wèn)題,使用Hystrix邏輯來(lái)處理。
               *  重要屬性 - fallbackMethod
               *      錯(cuò)誤返回方法名。如果當(dāng)前方法調(diào)用服務(wù),遠(yuǎn)程服務(wù)出現(xiàn)問(wèn)題的時(shí)候,調(diào)用本地的哪個(gè)方法得到托底數(shù)據(jù)。
               *      Hystrix會(huì)調(diào)用fallbackMethod指定的方法,獲取結(jié)果,并返回給客戶(hù)端。
               * @return
               */

              @HystrixCommand(fallbackMethod="downgradeFallback")
              public List<Map<String, Object>> testDowngrade() {
                  System.out.println("testDowngrade method : " + Thread.currentThread().getName());
                  ServiceInstance si = 
                          this.loadBalancerClient.choose("eureka-application-service");
                  StringBuilder sb = new StringBuilder();
                  sb.append("http://").append(si.getHost())
                      .append(":").append(si.getPort()).append("/test");
                  System.out.println("request application service URL : " + sb.toString());
                  RestTemplate rt = new RestTemplate();
                  ParameterizedTypeReference<List<Map<String, Object>>> type = 
                          new ParameterizedTypeReference<List<Map<String, Object>>>() {
                  };
                  ResponseEntity<List<Map<String, Object>>> response = 
                          rt.exchange(sb.toString(), HttpMethod.GET, null, type);
                  List<Map<String, Object>> result = response.getBody();
                  return result;
              }

              /**
               * fallback方法。本地定義的。用來(lái)處理遠(yuǎn)程服務(wù)調(diào)用錯(cuò)誤時(shí),返回的基礎(chǔ)數(shù)據(jù)。
               */

              private List<Map<String, Object>> downgradeFallback(){
                  List<Map<String, Object>> result = new ArrayList<>();
                  
                  Map<String, Object> data = new HashMap<>();
                  data.put("id", -1);
                  data.put("name""downgrade fallback datas");
                  data.put("age"0);
                  result.add(data);
                  return result;
              }    
          }

          2.2 緩存

          緩存是指請(qǐng)求緩存。通常意義上說(shuō),就是將同樣的GET請(qǐng)求結(jié)果緩存起來(lái),使用緩存機(jī)制(如redis、mongodb)提升請(qǐng)求響應(yīng)效率。

          使用請(qǐng)求緩存時(shí),需要注意非冪等性操作對(duì)緩存數(shù)據(jù)的影響。

          請(qǐng)求緩存是依托某一緩存服務(wù)來(lái)實(shí)現(xiàn)的。在案例中使用redis作為緩存服務(wù)器,那么可以使用spring-data-redis來(lái)實(shí)現(xiàn)redis的訪(fǎng)問(wèn)操作。需要在application client相關(guān)工程中導(dǎo)入下述依賴(lài):

          <!-- hystrix依賴(lài), 處理服務(wù)災(zāi)難雪崩效應(yīng)的。 -->
          <dependency>
              <groupId>org.springframework.cloud</groupId>
              <artifactId>spring-cloud-starter-hystrix</artifactId>
          </dependency>
                  
          <!-- spring-data-redis spring cloud中集成的spring-data相關(guān)啟動(dòng)器。 -->
          <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-data-redis</artifactId>
          </dependency>

          在Spring Cloud應(yīng)用中,啟用spring對(duì)cache的支持,需要在啟動(dòng)類(lèi)中增加注解@EnableCaching,此注解代表當(dāng)前應(yīng)用開(kāi)啟spring對(duì)cache的支持。簡(jiǎn)言之就是使spring-data-redis相關(guān)的注解生效,如:@CacheConfig、@Cacheable、@CacheEvict等。

          啟動(dòng)器:

          /**
           * @EnableCircuitBreaker - 開(kāi)啟斷路器。就是開(kāi)啟hystrix服務(wù)容錯(cuò)能力。
           * 當(dāng)應(yīng)用啟用Hystrix服務(wù)容錯(cuò)的時(shí)候,必須增加的一個(gè)注解。
           */

          @EnableCircuitBreaker
          /**
           * @EnableCaching - 開(kāi)啟spring cloud對(duì)cache的支持。
           * 可以自動(dòng)的使用請(qǐng)求緩存,訪(fǎng)問(wèn)redis等cache服務(wù)。
           */

          @EnableCaching
          @EnableEurekaClient
          @SpringBootApplication
          public class HystrixApplicationClientApplication {
              public static void main(String[] args) {
                  SpringApplication.run(HystrixApplicationClientApplication.classargs);
              }
          }

          spring cloud會(huì)檢查每個(gè)冪等性請(qǐng)求,如果請(qǐng)求完全相同(路徑、參數(shù)等完全一致),則首先訪(fǎng)問(wèn)緩存redis,查看緩存數(shù)據(jù),如果緩存中有數(shù)據(jù),則不調(diào)用遠(yuǎn)程服務(wù)application service。如果緩存中沒(méi)有數(shù)據(jù),則調(diào)用遠(yuǎn)程服務(wù),并將結(jié)果緩存到redis中,供后續(xù)請(qǐng)求使用。

          如果請(qǐng)求是一個(gè)非冪等性操作,則會(huì)根據(jù)方法的注解來(lái)動(dòng)態(tài)管理redis中的緩存數(shù)據(jù),避免數(shù)據(jù)不一致。

          注意:使用請(qǐng)求緩存會(huì)導(dǎo)致很多的隱患,如:緩存管理不當(dāng)導(dǎo)致的數(shù)據(jù)不同步、問(wèn)題排查困難等。在商業(yè)項(xiàng)目中,解決服務(wù)雪崩效應(yīng)不推薦使用請(qǐng)求緩存。

          實(shí)現(xiàn)類(lèi):

          /**
           * 在類(lèi)上,增加@CacheConfig注解,用來(lái)描述當(dāng)前類(lèi)型可能使用cache緩存。
           * 如果使用緩存,則緩存數(shù)據(jù)的key的前綴是cacheNames。
           * cacheNames是用來(lái)定義一個(gè)緩存集的前綴命名的,相當(dāng)于分組。
           */

          @CacheConfig(cacheNames={"test.hystrix.cache"})
          @Service
          public class HystrixService {

              @Autowired
              private LoadBalancerClient loadBalancerClient;

              /**
               * 請(qǐng)求緩存處理方法。
               * 使用注解@Cacheable描述方法。配合啟動(dòng)器中的相關(guān)注解,實(shí)現(xiàn)一個(gè)請(qǐng)求緩存邏輯。
               * 將當(dāng)期方法的返回值緩存到cache中。
               * 屬性 value | cacheNames - 代表緩存到cache的數(shù)據(jù)的key的一部分。
               * 可以使用springEL來(lái)獲取方法參數(shù)數(shù)據(jù),定制特性化的緩存key。
               * 只要方法增加了@Cacheable注解,每次調(diào)用當(dāng)前方法的時(shí)候,spring cloud都會(huì)先訪(fǎng)問(wèn)cache獲取數(shù)據(jù),
               * 如果cache中沒(méi)有數(shù)據(jù),則訪(fǎng)問(wèn)遠(yuǎn)程服務(wù)獲取數(shù)據(jù)。遠(yuǎn)程服務(wù)返回?cái)?shù)據(jù),先保存在cache中,再返回給客戶(hù)端。
               * 如果cache中有數(shù)據(jù),則直接返回cache中的數(shù)據(jù),不會(huì)訪(fǎng)問(wèn)遠(yuǎn)程服務(wù)。
               * 
               * 請(qǐng)求緩存會(huì)有緩存數(shù)據(jù)不一致的可能。
               * 緩存數(shù)據(jù)過(guò)期、失效、臟數(shù)據(jù)等情況。
               * 一旦使用了請(qǐng)求緩存來(lái)處理冪等性請(qǐng)求操作。則在非冪等性請(qǐng)求操作中必須管理緩存。避免緩存數(shù)據(jù)的錯(cuò)誤。
               * @return
               */

              @Cacheable("testCache4Get")
              public List<Map<String, Object>> testCache4Get() {
                  System.out.println("testCache4Get method thread name : " + Thread.currentThread().getName());
                  ServiceInstance si = 
                          this.loadBalancerClient.choose("eureka-application-service");
                  StringBuilder sb = new StringBuilder();
                  sb.append("http://").append(si.getHost())
                      .append(":").append(si.getPort()).append("/test");
                  System.out.println("request application service URL : " + sb.toString());
                  RestTemplate rt = new RestTemplate();
                  ParameterizedTypeReference<List<Map<String, Object>>> type = 
                          new ParameterizedTypeReference<List<Map<String, Object>>>() {
                  };
                  ResponseEntity<List<Map<String, Object>>> response = 
                          rt.exchange(sb.toString(), HttpMethod.GET, null, type);
                  List<Map<String, Object>> result = response.getBody();
                  return result;
              }
              
              /**
               * 非冪等性操作。用于模擬刪除邏輯。
               * 一旦非冪等性操作執(zhí)行,則必須管理緩存。就是釋放緩存中的數(shù)據(jù)。刪除緩存數(shù)據(jù)。
               * 使用注解@CacheEvict管理緩存。
               * 通過(guò)數(shù)據(jù)cacheNames | value來(lái)刪除對(duì)應(yīng)key的緩存。
               * 刪除緩存的邏輯,是在當(dāng)前方法執(zhí)行結(jié)束后。
               * @return
               */

              @CacheEvict("testCache4Get")
              public List<Map<String, Object>> testCache4Del() {
                  ServiceInstance si = 
                          this.loadBalancerClient.choose("eureka-application-service");
                  StringBuilder sb = new StringBuilder();
                  sb.append("http://").append(si.getHost())
                      .append(":").append(si.getPort()).append("/test");
                  System.out.println("request application service URL : " + sb.toString());
                  RestTemplate rt = new RestTemplate();
                  ParameterizedTypeReference<List<Map<String, Object>>> type = 
                          new ParameterizedTypeReference<List<Map<String, Object>>>() {
                  };
                  ResponseEntity<List<Map<String, Object>>> response = 
                          rt.exchange(sb.toString(), HttpMethod.GET, null, type);
                  List<Map<String, Object>> result = response.getBody();
                  return result;
              }
          }

          2.3 請(qǐng)求合并

          請(qǐng)求合并是指,在一定時(shí)間內(nèi),收集一定量的同類(lèi)型請(qǐng)求,合并請(qǐng)求需求后,一次性訪(fǎng)問(wèn)服務(wù)提供者,得到批量結(jié)果。這種方式可以減少服務(wù)消費(fèi)者和服務(wù)提供者之間的通訊次數(shù),提升應(yīng)用執(zhí)行效率。

          未使用請(qǐng)求合并:

          使用請(qǐng)求合并:

          什么情況下使用請(qǐng)求合并:

          在微服務(wù)架構(gòu)中,我們將一個(gè)項(xiàng)目拆分成很多個(gè)獨(dú)立的模塊,這些獨(dú)立的模塊通過(guò)遠(yuǎn)程調(diào)用來(lái)互相配合工作,但是,在高并發(fā)情況下,通信次數(shù)的增加會(huì)導(dǎo)致總的通信時(shí)間增加,同時(shí),線(xiàn)程池的資源也是有限的,高并發(fā)環(huán)境會(huì)導(dǎo)致有大量的線(xiàn)程處于等待狀態(tài),進(jìn)而導(dǎo)致響應(yīng)延遲,為了解決這些問(wèn)題,我們需要來(lái)了解Hystrix的請(qǐng)求合并。

          通常來(lái)說(shuō),服務(wù)鏈條超出4個(gè),不推薦使用請(qǐng)求合并。因?yàn)檎?qǐng)求合并有等待時(shí)間。

          請(qǐng)求合并的缺點(diǎn):

          設(shè)置請(qǐng)求合并之后,本來(lái)一個(gè)請(qǐng)求可能5ms就搞定了,但是現(xiàn)在必須再等10ms看看還有沒(méi)有其他的請(qǐng)求一起的,這樣一個(gè)請(qǐng)求的耗時(shí)就從5ms增加到15ms了,不過(guò),如果我們要發(fā)起的命令本身就是一個(gè)高延遲的命令,那么這個(gè)時(shí)候就可以使用請(qǐng)求合并了,因?yàn)檫@個(gè)時(shí)候時(shí)間窗的時(shí)間消耗就顯得微不足道了,另外高并發(fā)也是請(qǐng)求合并的一個(gè)非常重要的場(chǎng)景。

          引入依賴(lài):

          <!-- hystrix依賴(lài), 處理服務(wù)災(zāi)難雪崩效應(yīng)的。 -->
          <dependency>
              <groupId>org.springframework.cloud</groupId>
              <artifactId>spring-cloud-starter-hystrix</artifactId>
          </dependency>

          啟動(dòng)器:

          /**
           * @EnableCircuitBreaker - 開(kāi)啟斷路器。就是開(kāi)啟hystrix服務(wù)容錯(cuò)能力。
           * 當(dāng)應(yīng)用啟用Hystrix服務(wù)容錯(cuò)的時(shí)候,必須增加的一個(gè)注解。
           */

          @EnableCircuitBreaker
          @EnableEurekaClient
          @SpringBootApplication
          public class HystrixApplicationClientApplication {
              public static void main(String[] args) {
                  SpringApplication.run(HystrixApplicationClientApplication.classargs);
              }
          }

          使用注解@HystrixCollapser來(lái)描述需要合并請(qǐng)求的方法,并提供合并方法使用注解@HystrixCommand來(lái)描述。當(dāng)合并條件(@HystrixCollapser)滿(mǎn)足時(shí),會(huì)觸發(fā)合并方法(@HystrixCommand)來(lái)調(diào)用遠(yuǎn)程服務(wù)并得到結(jié)果。

          @HystrixCollapser注解介紹:此注解描述的方法,返回值類(lèi)型必須是java.util.concurrent.Future類(lèi)型的。代表方法為異步方法。

          @HystrixCollapser注解的屬性:

          • batchMethod - 請(qǐng)求合并方法名。
          • scope - 請(qǐng)求合并方式??蛇x值有REQUEST和GLOBAL。REQUEST代表在一個(gè)request請(qǐng)求生命周期內(nèi)的多次遠(yuǎn)程服務(wù)調(diào)用請(qǐng)求需要合并處理,此為默認(rèn)值。GLOBAL代表所有request線(xiàn)程內(nèi)的多次遠(yuǎn)程服務(wù)調(diào)用請(qǐng)求需要合并處理。
          • timerDelayInMilliseconds - 多少時(shí)間間隔內(nèi)的請(qǐng)求進(jìn)行合并處理,默認(rèn)值為10ms。建議設(shè)置時(shí)間間隔短一些,如果單位時(shí)間并發(fā)量不大,并沒(méi)有請(qǐng)求合并的必要。
          • maxRequestsInBatch - 設(shè)置合并請(qǐng)求的最大極值,也就是timerDelayInMilliseconds時(shí)間內(nèi),最多合并多少個(gè)請(qǐng)求。默認(rèn)值是Integer.MAX_VALUE。

          實(shí)現(xiàn)類(lèi):

          @Service
          public class HystrixService {

              @Autowired
              private LoadBalancerClient loadBalancerClient;

              /**
               * 需要合并請(qǐng)求的方法。
               * 這種方法的返回結(jié)果一定是Future類(lèi)型的。
               * 這種方法的處理邏輯都是異步的。
               * 是application client在一定時(shí)間內(nèi)收集客戶(hù)端請(qǐng)求,或收集一定量的客戶(hù)端請(qǐng)求,一次性發(fā)給application service。
               * application service返回的結(jié)果,application client會(huì)進(jìn)行二次處理,封裝為future對(duì)象并返回
               * future對(duì)象需要通過(guò)get方法獲取最終的結(jié)果。get方法是由控制器調(diào)用的。所以控制器調(diào)用service的過(guò)程是一個(gè)異步處理的過(guò)程。
               * 合并請(qǐng)求的方法需要使用@HystrixCollapser注解描述。
               * batchMethod - 合并請(qǐng)求后,使用的方法是什么。如果當(dāng)前方法有參數(shù),合并請(qǐng)求后的方法參數(shù)是當(dāng)前方法參數(shù)的集合,如 int id >> int[] ids。
               * scope - 合并請(qǐng)求的請(qǐng)求作用域??蛇x值有g(shù)lobal和request。
               *     global代表所有的請(qǐng)求線(xiàn)程都可以等待可合并。 常用,所有瀏覽器或者請(qǐng)求源(Postman、curl等)調(diào)用的請(qǐng)求
               *     request代表一個(gè)請(qǐng)求線(xiàn)程中的多次遠(yuǎn)程服務(wù)調(diào)用可合并
               * collapserProperties - 細(xì)致配置。就是配置合并請(qǐng)求的特性。如等待多久,如可合并請(qǐng)求的數(shù)量。
               *     屬性的類(lèi)型是@HystrixProperty類(lèi)型數(shù)組,可配置的屬性值可以直接通過(guò)字符串或常量類(lèi)定義。
               *     timerDelayInMilliseconds - 等待時(shí)長(zhǎng)
               *     maxRequestsInBatch - 可合并的請(qǐng)求最大數(shù)量。
               * 
               * 方法處理邏輯不需要實(shí)現(xiàn),直接返回null即可。
               * 合并請(qǐng)求一定是可合并的。也就是同類(lèi)型請(qǐng)求。同URL的請(qǐng)求。
               * @param id
               * @return
               */

              @HystrixCollapser(batchMethod = "mergeRequest"
                      scope = com.netflix.hystrix.HystrixCollapser.Scope.GLOBAL,  
                      collapserProperties = {  
                      // 請(qǐng)求時(shí)間間隔在20ms之內(nèi)的請(qǐng)求會(huì)被合并為一個(gè)請(qǐng)求,默認(rèn)為10ms
                      @HystrixProperty(name = "timerDelayInMilliseconds", value = "20"),
                      // 設(shè)置觸發(fā)批處理執(zhí)行之前,在批處理中允許的最大請(qǐng)求數(shù)。
                      @HystrixProperty(name = "maxRequestsInBatch", value = "200"),  
              })  
              public Future<Map<String, Object>> testMergeRequest(Long id){
                  return null;
              }
              
              /**
               * 批量處理方法。就是合并請(qǐng)求后真實(shí)調(diào)用遠(yuǎn)程服務(wù)的方法。
               * 必須使用@HystrixCommand注解描述,代表當(dāng)前方法是一個(gè)Hystrix管理的服務(wù)容錯(cuò)方法。
               * 是用于處理請(qǐng)求合并的方法。
               * @param ids
               * @return
               */

              @HystrixCommand
              public List<Map<String, Object>> mergeRequest(List<Long> ids){
                  ServiceInstance si = 
                          this.loadBalancerClient.choose("eureka-application-service");
                  StringBuilder sb = new StringBuilder();
                  sb.append("http://").append(si.getHost())
                      .append(":").append(si.getPort()).append("/testMerge?");
                  for(int i = 0; i < ids.size(); i++){
                      Long id = ids.get(i);
                      if(i != 0){
                          sb.append("&");
                      }
                      sb.append("ids=").append(id);
                  }
                  System.out.println("request application service URL : " + sb.toString());
                  RestTemplate rt = new RestTemplate();
                  ParameterizedTypeReference<List<Map<String, Object>>> type = 
                          new ParameterizedTypeReference<List<Map<String, Object>>>() {
                  };
                  ResponseEntity<List<Map<String, Object>>> response = 
                          rt.exchange(sb.toString(), HttpMethod.GET, null, type);
                  List<Map<String, Object>> result = response.getBody();
                  return result;
              }
          }

          2.4 熔斷

          當(dāng)一定時(shí)間內(nèi),異常請(qǐng)求比例(請(qǐng)求超時(shí)、網(wǎng)絡(luò)故障、服務(wù)異常等)達(dá)到閥值時(shí),啟動(dòng)熔斷器,熔斷器一旦啟動(dòng),則會(huì)停止調(diào)用具體服務(wù)邏輯,通過(guò)fallback快速返回托底數(shù)據(jù),保證服務(wù)鏈的完整。

          熔斷有自動(dòng)恢復(fù)機(jī)制,如:當(dāng)熔斷器啟動(dòng)后,每隔5秒,嘗試將新的請(qǐng)求發(fā)送給服務(wù)提供者,如果服務(wù)可正常執(zhí)行并返回結(jié)果,則關(guān)閉熔斷器,服務(wù)恢復(fù)。如果仍舊調(diào)用失敗,則繼續(xù)返回托底數(shù)據(jù),熔斷器持續(xù)開(kāi)啟狀態(tài)。

          引入依賴(lài):

          <!-- hystrix依賴(lài), 處理服務(wù)災(zāi)難雪崩效應(yīng)的。 -->
          <dependency>
              <groupId>org.springframework.cloud</groupId>
              <artifactId>spring-cloud-starter-hystrix</artifactId>
          </dependency>

          啟動(dòng)器:

          /**
           * @EnableCircuitBreaker - 開(kāi)啟斷路器。就是開(kāi)啟hystrix服務(wù)容錯(cuò)能力。
           * 當(dāng)應(yīng)用啟用Hystrix服務(wù)容錯(cuò)的時(shí)候,必須增加的一個(gè)注解。
           */

          @EnableCircuitBreaker
          @EnableEurekaClient
          @SpringBootApplication
          public class HystrixApplicationClientApplication {
              public static void main(String[] args) {
                  SpringApplication.run(HystrixApplicationClientApplication.classargs);
              }
          }

          熔斷的實(shí)現(xiàn)是在調(diào)用遠(yuǎn)程服務(wù)的方法上增加@HystrixCommand注解。當(dāng)注解配置滿(mǎn)足則開(kāi)啟或關(guān)閉熔斷器。

          @Service
          public class HystrixService {

              @Autowired
              private LoadBalancerClient loadBalancerClient;
              
              /**
               * 熔斷機(jī)制
               * 相當(dāng)于一個(gè)強(qiáng)化的服務(wù)降級(jí)。 服務(wù)降級(jí)是只要遠(yuǎn)程服務(wù)出錯(cuò),立刻返回fallback結(jié)果。
               * 熔斷是收集一定時(shí)間內(nèi)的錯(cuò)誤比例,如果達(dá)到一定的錯(cuò)誤率。則啟動(dòng)熔斷,返回fallback結(jié)果。
               * 間隔一定時(shí)間會(huì)將請(qǐng)求再次發(fā)送給application service進(jìn)行重試。如果重試成功,熔斷關(guān)閉。
               * 如果重試失敗,熔斷持續(xù)開(kāi)啟,并返回fallback數(shù)據(jù)。
               * @HystrixCommand 描述方法。
               *  fallbackMethod - fallback方法名
               *  commandProperties - 具體的熔斷標(biāo)準(zhǔn)。類(lèi)型是HystrixProperty數(shù)組。
               *   可以通過(guò)字符串或常亮類(lèi)配置。
               *   CIRCUIT_BREAKER_REQUEST_VOLUME_THRESHOLD - 錯(cuò)誤數(shù)量。在10毫秒內(nèi),出現(xiàn)多少次遠(yuǎn)程服務(wù)調(diào)用錯(cuò)誤,則開(kāi)啟熔斷。
               *       默認(rèn)20個(gè)。10毫秒內(nèi)有20個(gè)錯(cuò)誤請(qǐng)求則開(kāi)啟熔斷。
               *   CIRCUIT_BREAKER_ERROR_THRESHOLD_PERCENTAGE - 錯(cuò)誤比例。在10毫秒內(nèi),遠(yuǎn)程服務(wù)調(diào)用錯(cuò)誤比例達(dá)標(biāo)則開(kāi)啟熔斷。
               *   CIRCUIT_BREAKER_SLEEP_WINDOW_IN_MILLISECONDS - 熔斷開(kāi)啟后,間隔多少毫秒重試遠(yuǎn)程服務(wù)調(diào)用。默認(rèn)5000毫秒。
               * @return
               */

              @HystrixCommand(fallbackMethod = "breakerFallback",
                      commandProperties = {
                        // 默認(rèn)20個(gè);10ms內(nèi)請(qǐng)求數(shù)大于20個(gè)時(shí)就啟動(dòng)熔斷器,當(dāng)請(qǐng)求符合熔斷條件時(shí)將觸發(fā)getFallback()。
                        @HystrixProperty(name=HystrixPropertiesManager.CIRCUIT_BREAKER_REQUEST_VOLUME_THRESHOLD, 
                                    value="10"),
                        // 請(qǐng)求錯(cuò)誤率大于50%時(shí)就熔斷,然后for循環(huán)發(fā)起請(qǐng)求,當(dāng)請(qǐng)求符合熔斷條件時(shí)將觸發(fā)getFallback()。
                        @HystrixProperty(name=HystrixPropertiesManager.CIRCUIT_BREAKER_ERROR_THRESHOLD_PERCENTAGE, 
                                    value="50"),
                        // 默認(rèn)5秒;熔斷多少秒后去嘗試請(qǐng)求
                        @HystrixProperty(name=HystrixPropertiesManager.CIRCUIT_BREAKER_SLEEP_WINDOW_IN_MILLISECONDS, 
                                    value="5000")}
              )
              public List<Map<String, Object>> testBreaker() {
                  System.out.println("testBreaker method thread name : " + Thread.currentThread().getName());
                  ServiceInstance si = 
                          this.loadBalancerClient.choose("eureka-application-service");
                  StringBuilder sb = new StringBuilder();
                  sb.append("http://").append(si.getHost())
                      .append(":").append(si.getPort()).append("/test");
                  System.out.println("request application service URL : " + sb.toString());
                  RestTemplate rt = new RestTemplate();
                  ParameterizedTypeReference<List<Map<String, Object>>> type = 
                          new ParameterizedTypeReference<List<Map<String, Object>>>() {
                  };
                  ResponseEntity<List<Map<String, Object>>> response = 
                          rt.exchange(sb.toString(), HttpMethod.GET, null, type);
                  List<Map<String, Object>> result = response.getBody();
                  return result;
              }
              
              private List<Map<String, Object>> breakerFallback(){
                  System.out.println("breakerFallback method thread name : " + Thread.currentThread().getName());
                  List<Map<String, Object>> result = new ArrayList<>();
                  
                  Map<String, Object> data = new HashMap<>();
                  data.put("id", -1);
                  data.put("name""breaker fallback datas");
                  data.put("age"0);
                  
                  result.add(data);
                  
                  return result;
              }
          }

          注解屬性描述:

          CIRCUIT_BREAKER_ENABLED
          "circuitBreaker.enabled";
          # 是否開(kāi)啟熔斷策略。默認(rèn)值為true。

          CIRCUIT_BREAKER_REQUEST_VOLUME_THRESHOLD
          "circuitBreaker.requestVolumeThreshold";
          # 10ms內(nèi),請(qǐng)求并發(fā)數(shù)超出則觸發(fā)熔斷策略。默認(rèn)值為20。

          CIRCUIT_BREAKER_SLEEP_WINDOW_IN_MILLISECONDS
          "circuitBreaker.sleepWindowInMilliseconds";
          # 當(dāng)熔斷策略開(kāi)啟后,延遲多久嘗試再次請(qǐng)求遠(yuǎn)程服務(wù)。默認(rèn)為5秒。

          CIRCUIT_BREAKER_ERROR_THRESHOLD_PERCENTAGE
          "circuitBreaker.errorThresholdPercentage";
          # 10ms內(nèi),出現(xiàn)錯(cuò)誤的請(qǐng)求百分比達(dá)到限制,則觸發(fā)熔斷策略。默認(rèn)為50%。

          CIRCUIT_BREAKER_FORCE_OPEN
          "circuitBreaker.forceOpen";
          # 是否強(qiáng)制開(kāi)啟熔斷策略。即所有請(qǐng)求都返回fallback托底數(shù)據(jù)。默認(rèn)為false。

          CIRCUIT_BREAKER_FORCE_CLOSED
          "circuitBreaker.forceClosed";
          # 是否強(qiáng)制關(guān)閉熔斷策略。即所有請(qǐng)求一定調(diào)用遠(yuǎn)程服務(wù)。默認(rèn)為false。

          2.5 隔離

          所謂隔離,就是當(dāng)服務(wù)發(fā)生問(wèn)題時(shí),使用技術(shù)手段隔離請(qǐng)求,保證服務(wù)調(diào)用鏈的完整。隔離分為線(xiàn)程池隔離和信號(hào)量隔離兩種實(shí)現(xiàn)方式。

          2.5.1 線(xiàn)程池隔離

          所謂線(xiàn)程池隔離,就是將并發(fā)請(qǐng)求量大的部分服務(wù)使用獨(dú)立的線(xiàn)程池處理,避免因個(gè)別服務(wù)并發(fā)過(guò)高導(dǎo)致整體應(yīng)用宕機(jī)。

          線(xiàn)程池隔離優(yōu)點(diǎn):

          • 使用線(xiàn)程池隔離可以完全隔離依賴(lài)的服務(wù),請(qǐng)求線(xiàn)程可以快速放回。
          • 當(dāng)線(xiàn)程池出現(xiàn)問(wèn)題時(shí),線(xiàn)程池是完全隔離狀態(tài)的,是獨(dú)立的,不會(huì)影響到其他服務(wù)的正常執(zhí)行。
          • 當(dāng)崩潰的服務(wù)恢復(fù)時(shí),線(xiàn)程池可以快速清理并恢復(fù),不需要相對(duì)漫長(zhǎng)的恢復(fù)等待。
          • 獨(dú)立的線(xiàn)程池也提供了并發(fā)處理能力。

          線(xiàn)程池隔離缺點(diǎn):

          線(xiàn)程池隔離機(jī)制,會(huì)導(dǎo)致服務(wù)硬件計(jì)算開(kāi)銷(xiāo)加大(CPU計(jì)算、調(diào)度等),每個(gè)命令的執(zhí)行都涉及到排隊(duì)、調(diào)度、上下文切換等,這些命令都是在一個(gè)單獨(dú)的線(xiàn)程上運(yùn)行的。

          線(xiàn)程池隔離的實(shí)現(xiàn)方式同樣是使用@HystrixCommand注解。相關(guān)注解配置屬性如下:

          • groupKey - 分組命名,在application client中會(huì)為每個(gè)application service服務(wù)設(shè)置一個(gè)分組,同一個(gè)分組下的服務(wù)調(diào)用使用同一個(gè)線(xiàn)程池。默認(rèn)值為this.getClass().getSimpleName();
          • commandKey - Hystrix中的命令命名,默認(rèn)為當(dāng)前方法的方法名??墒÷?。用于標(biāo)記當(dāng)前要觸發(fā)的遠(yuǎn)程服務(wù)是什么。
          • threadPoolKey - 線(xiàn)程池命名。要求一個(gè)應(yīng)用中全局唯一。多個(gè)方法使用同一個(gè)線(xiàn)程池命名,代表使用同一個(gè)線(xiàn)程池。默認(rèn)值是groupKey數(shù)據(jù)。
          • threadPoolProperties - 用于為線(xiàn)程池設(shè)置的參數(shù)。其類(lèi)型為HystrixProperty數(shù)組。常用線(xiàn)程池設(shè)置參數(shù)有:
          • coreSize - 線(xiàn)程池最大并發(fā)數(shù),建議設(shè)置標(biāo)準(zhǔn)為:requests per second at peak when healthy * 99th percentile latency in second + some breathing room。即每秒最大支持請(qǐng)求數(shù)*(99%平均響應(yīng)時(shí)間 + 一定量的緩沖時(shí)間(99%平均響應(yīng)時(shí)間的10%-20%))。如:每秒可以處理請(qǐng)求數(shù)為1000,99%的響應(yīng)時(shí)間為60ms,自定義提供緩沖時(shí)間為60*0.2=12ms,那么結(jié)果是 1000*(0.060+0.012) = 72
          • maxQueueSize - BlockingQueue的最大長(zhǎng)度,默認(rèn)值為-1,即不限制。如果設(shè)置為正數(shù),等待隊(duì)列將從同步隊(duì)列SynchronousQueue轉(zhuǎn)換為阻塞隊(duì)列LinkedBlockingQueue。
          • queueSizeRejectionThreshold - 設(shè)置拒絕請(qǐng)求的臨界值。默認(rèn)值為5。此屬性是配合阻塞隊(duì)列使用的,也就是不適用maxQueueSize=-1(為-1的時(shí)候此值無(wú)效)的情況。是用于設(shè)置阻塞隊(duì)列限制的,如果超出限制,則拒絕請(qǐng)求。此參數(shù)的意義就是在服務(wù)啟動(dòng)后,可以通過(guò)Hystrix的API調(diào)用config API動(dòng)態(tài)修改,而不用用重啟服務(wù),不常用。
          • keepAliveTimeMinutes - 線(xiàn)程存活時(shí)間,單位是分鐘。默認(rèn)值為1。
          • execution.isolation.thread.timeoutInMilliseconds - 超時(shí)時(shí)間,默認(rèn)為1000ms。當(dāng)請(qǐng)求超時(shí)自動(dòng)中斷,返回fallback,避免服務(wù)長(zhǎng)期阻塞。
          • execution.isolation.thread.interruptOnTimeout - 是否開(kāi)啟超時(shí)中斷。默認(rèn)為T(mén)RUE。和上一個(gè)屬性配合使用。

          引入依賴(lài):

          <!-- hystrix依賴(lài), 處理服務(wù)災(zāi)難雪崩效應(yīng)的。 -->
          <dependency>
              <groupId>org.springframework.cloud</groupId>
              <artifactId>spring-cloud-starter-hystrix</artifactId>
          </dependency>

          啟動(dòng)器:

          /**
           * @EnableCircuitBreaker - 開(kāi)啟斷路器。就是開(kāi)啟hystrix服務(wù)容錯(cuò)能力。
           * 當(dāng)應(yīng)用啟用Hystrix服務(wù)容錯(cuò)的時(shí)候,必須增加的一個(gè)注解。
           */

          @EnableCircuitBreaker
          @EnableEurekaClient
          @SpringBootApplication
          public class HystrixApplicationClientApplication {
              public static void main(String[] args) {
                  SpringApplication.run(HystrixApplicationClientApplication.classargs);
              }
          }

          實(shí)現(xiàn)類(lèi):

          @Service
          public class HystrixService {

              @Autowired
              private LoadBalancerClient loadBalancerClient;

              /**
               * 如果使用了@HystrixCommand注解,則Hystrix自動(dòng)創(chuàng)建獨(dú)立的線(xiàn)程池。
               * groupKey和threadPoolKey默認(rèn)值是當(dāng)前服務(wù)方法所在類(lèi)型的simpleName
               * 
               * 所有的fallback方法,都執(zhí)行在一個(gè)HystrixTimer線(xiàn)程池上。
               * 這個(gè)線(xiàn)程池是Hystrix提供的一個(gè),專(zhuān)門(mén)處理fallback邏輯的線(xiàn)程池。
               * 
               * 線(xiàn)程池隔離實(shí)現(xiàn)
               * 線(xiàn)程池隔離,就是為某一些服務(wù),獨(dú)立劃分線(xiàn)程池。讓這些服務(wù)邏輯在獨(dú)立的線(xiàn)程池中運(yùn)行。
               * 不使用tomcat提供的默認(rèn)線(xiàn)程池。
               * 線(xiàn)程池隔離也有熔斷能力。如果線(xiàn)程池不能處理更多的請(qǐng)求的時(shí)候,會(huì)觸發(fā)熔斷,返回fallback數(shù)據(jù)。
               * groupKey - 分組名稱(chēng),就是為服務(wù)劃分分組。如果不配置,默認(rèn)使用threadPoolKey作為組名。
               * commandKey - 命令名稱(chēng),默認(rèn)值就是當(dāng)前業(yè)務(wù)方法的方法名。
               * threadPoolKey - 線(xiàn)程池命名,真實(shí)線(xiàn)程池命名的一部分。Hystrix在創(chuàng)建線(xiàn)程池并命名的時(shí)候,會(huì)提供完整命名。默認(rèn)使用gourpKey命名
               *  如果多個(gè)方法使用的threadPoolKey是同名的,則使用同一個(gè)線(xiàn)程池。
               * threadPoolProperties - 為Hystrix創(chuàng)建的線(xiàn)程池做配置??梢允褂米址騂ystrixPropertiesManager中的常量指定。
               *  常用線(xiàn)程池配置:
               *      coreSize - 核心線(xiàn)程數(shù)。最大并發(fā)數(shù)。1000*(99%平均響應(yīng)時(shí)間 + 適當(dāng)?shù)难舆t時(shí)間)
               *      maxQueueSize - 阻塞隊(duì)列長(zhǎng)度。如果是-1這是同步隊(duì)列。如果是正數(shù)這是LinkedBlockingQueue。如果線(xiàn)程池最大并發(fā)數(shù)不足,
               *          提供多少的阻塞等待。
               *      keepAliveTimeMinutes - 心跳時(shí)間,超時(shí)時(shí)長(zhǎng)。單位是分鐘。
               *      queueSizeRejectionThreshold - 拒絕臨界值,當(dāng)最大并發(fā)不足的時(shí)候,超過(guò)多少個(gè)阻塞請(qǐng)求,后續(xù)請(qǐng)求拒絕。
               */

              @HystrixCommand(groupKey="test-thread-quarantine"
                  commandKey = "testThreadQuarantine",
                  threadPoolKey="test-thread-quarantine"
                  threadPoolProperties = {
                      @HystrixProperty(name="coreSize", value="30"),
                      @HystrixProperty(name="maxQueueSize", value="100"),
                      @HystrixProperty(name="keepAliveTimeMinutes", value="2"),
                      @HystrixProperty(name="queueSizeRejectionThreshold", value="15")
                  },
                  fallbackMethod = "threadQuarantineFallback")
              public List<Map<String, Object>> testThreadQuarantine() {
                  System.out.println("testQuarantine method thread name : " + Thread.currentThread().getName());
                  ServiceInstance si = 
                          this.loadBalancerClient.choose("eureka-application-service");
                  StringBuilder sb = new StringBuilder();
                  sb.append("http://").append(si.getHost())
                      .append(":").append(si.getPort()).append("/test");
                  System.out.println("request application service URL : " + sb.toString());
                  RestTemplate rt = new RestTemplate();
                  ParameterizedTypeReference<List<Map<String, Object>>> type = 
                          new ParameterizedTypeReference<List<Map<String, Object>>>() {
                  };
                  ResponseEntity<List<Map<String, Object>>> response = 
                          rt.exchange(sb.toString(), HttpMethod.GET, null, type);
                  List<Map<String, Object>> result = response.getBody();
                  return result;
              }
              
              private List<Map<String, Object>> threadQuarantineFallback(){
                  System.out.println("threadQuarantineFallback method thread name : " + Thread.currentThread().getName());
                  List<Map<String, Object>> result = new ArrayList<>();
                  
                  Map<String, Object> data = new HashMap<>();
                  data.put("id", -1);
                  data.put("name""thread quarantine fallback datas");
                  data.put("age"0);
                  
                  result.add(data);
                  
                  return result;
              }
          }

          關(guān)于線(xiàn)程池:

          • 對(duì)于所有請(qǐng)求,都交由tomcat容器的線(xiàn)程池處理,是一個(gè)以http-nio開(kāi)頭的的線(xiàn)程池;
          • 開(kāi)啟了線(xiàn)程池隔離后,tomcat容器默認(rèn)的線(xiàn)程池會(huì)將請(qǐng)求轉(zhuǎn)交給threadPoolKey定義名稱(chēng)的線(xiàn)程池,處理結(jié)束后,由定義的線(xiàn)程池進(jìn)行返回,無(wú)需還回tomcat容器默認(rèn)的線(xiàn)程池。線(xiàn)程池默認(rèn)為當(dāng)前方法名;
          • 所有的fallback都單獨(dú)由Hystrix創(chuàng)建的一個(gè)線(xiàn)程池處理。

          2.5.2 信號(hào)量隔離

          所謂信號(hào)量隔離,就是設(shè)置一個(gè)并發(fā)處理的最大極值。當(dāng)并發(fā)請(qǐng)求數(shù)超過(guò)極值時(shí),通過(guò)fallback返回托底數(shù)據(jù),保證服務(wù)完整性。

          信號(hào)量隔離同樣通過(guò)@HystrixCommand注解配置,常用注解屬性有:

          • commandProperty - 配置信號(hào)量隔離具體數(shù)據(jù)。屬性類(lèi)型為HystrixProperty數(shù)組,常用配置內(nèi)容如下:
          • execution.isolation.strategy - 設(shè)置隔離方式,默認(rèn)為線(xiàn)程池隔離??蛇x值只有THREAD和SEMAPHORE。
          • execution.isolation.semaphore.maxConcurrentRequests - 最大信號(hào)量并發(fā)數(shù),默認(rèn)為10。

          依賴(lài)注入和啟動(dòng)器同線(xiàn)程池隔離,實(shí)現(xiàn)類(lèi)如下:

          @Service
          public class HystrixService {

              @Autowired
              private LoadBalancerClient loadBalancerClient;

              /**
               * 信號(hào)量隔離實(shí)現(xiàn)
               * 不會(huì)使用Hystrix管理的線(xiàn)程池處理請(qǐng)求。使用容器(Tomcat)的線(xiàn)程處理請(qǐng)求邏輯。
               * 不涉及線(xiàn)程切換,資源調(diào)度,上下文的轉(zhuǎn)換等,相對(duì)效率高。
               * 信號(hào)量隔離也會(huì)啟動(dòng)熔斷機(jī)制。如果請(qǐng)求并發(fā)數(shù)超標(biāo),則觸發(fā)熔斷,返回fallback數(shù)據(jù)。
               * commandProperties - 命令配置,HystrixPropertiesManager中的常量或字符串來(lái)配置。
               *     execution.isolation.strategy - 隔離的種類(lèi),可選值只有THREAD(線(xiàn)程池隔離)和SEMAPHORE(信號(hào)量隔離)。
               *      默認(rèn)是THREAD線(xiàn)程池隔離。
               *      設(shè)置信號(hào)量隔離后,線(xiàn)程池相關(guān)配置失效。
               *  execution.isolation.semaphore.maxConcurrentRequests - 信號(hào)量最大并發(fā)數(shù)。默認(rèn)值是10。常見(jiàn)配置500~1000。
               *      如果并發(fā)請(qǐng)求超過(guò)配置,其他請(qǐng)求進(jìn)入fallback邏輯。
               */

              @HystrixCommand(fallbackMethod="semaphoreQuarantineFallback",
                      commandProperties={
                        @HystrixProperty(
                                name=HystrixPropertiesManager.EXECUTION_ISOLATION_STRATEGY, 
                                value="SEMAPHORE"), // 信號(hào)量隔離
                        @HystrixProperty(
                                name=HystrixPropertiesManager.EXECUTION_ISOLATION_SEMAPHORE_MAX_CONCURRENT_REQUESTS, 
                                value="100"// 信號(hào)量最大并發(fā)數(shù)
              })
              public List<Map<String, Object>> testSemaphoreQuarantine() {
                  System.out.println("testSemaphoreQuarantine method thread name : " + Thread.currentThread().getName());
                  ServiceInstance si = 
                          this.loadBalancerClient.choose("eureka-application-service");
                  StringBuilder sb = new StringBuilder();
                  sb.append("http://").append(si.getHost())
                      .append(":").append(si.getPort()).append("/test");
                  System.out.println("request application service URL : " + sb.toString());
                  RestTemplate rt = new RestTemplate();
                  ParameterizedTypeReference<List<Map<String, Object>>> type = 
                          new ParameterizedTypeReference<List<Map<String, Object>>>() {
                  };
                  ResponseEntity<List<Map<String, Object>>> response = 
                          rt.exchange(sb.toString(), HttpMethod.GET, null, type);
                  List<Map<String, Object>> result = response.getBody();
                  return result;
              }
              
              private List<Map<String, Object>> semaphoreQuarantineFallback(){
                  System.out.println("threadQuarantineFallback method thread name : " + Thread.currentThread().getName());
                  List<Map<String, Object>> result = new ArrayList<>();
                  
                  Map<String, Object> data = new HashMap<>();
                  data.put("id", -1);
                  data.put("name""thread quarantine fallback datas");
                  data.put("age"0);
                  
                  result.add(data);
                  
                  return result;
              }
          }

          2.5.3線(xiàn)程池隔離和信號(hào)量隔離的對(duì)比

          2.5.4線(xiàn)程池隔離和信號(hào)量隔離的選擇

          • 線(xiàn)程池隔離:請(qǐng)求并發(fā)大,耗時(shí)較長(zhǎng)(一般都是計(jì)算大,服務(wù)鏈長(zhǎng)或訪(fǎng)問(wèn)數(shù)據(jù)庫(kù))時(shí)使用線(xiàn)程池隔離。可以盡可能保證外部容器(如Tomcat)線(xiàn)程池可用,不會(huì)因?yàn)榉?wù)調(diào)用的原因?qū)е抡?qǐng)求阻塞等待。
          • 信號(hào)量隔離:請(qǐng)求并發(fā)大,耗時(shí)短(計(jì)算小,服務(wù)鏈段或訪(fǎng)問(wèn)緩存)時(shí)使用信號(hào)量隔離。因?yàn)檫@類(lèi)服務(wù)的響應(yīng)快,不會(huì)占用外部容器(如Tomcat)線(xiàn)程池太長(zhǎng)時(shí)間,減少線(xiàn)程的切換,可以避免不必要的開(kāi)銷(xiāo),提高服務(wù)處理效率。

          3 Feign的雪崩處理

          在聲明式遠(yuǎn)程服務(wù)調(diào)用Feign中,實(shí)現(xiàn)服務(wù)災(zāi)難性雪崩效應(yīng)處理也是通過(guò)Hystrix實(shí)現(xiàn)的。而feign啟動(dòng)器spring-cloud-starter-feign中是包含Hystrix相關(guān)依賴(lài)的。

          如果只使用服務(wù)降級(jí)、熔斷功能不需要做獨(dú)立依賴(lài)。如果需要使用Hystrix其他服務(wù)容錯(cuò)能力,需要依賴(lài)spring-cloud-starter-hystrix資源。

          <!-- hystrix依賴(lài)。 -->
          <dependency>
              <groupId>org.springframework.cloud</groupId>
              <artifactId>spring-cloud-starter-hystrix</artifactId>
          </dependency>

          從Dalston版本后,feign默認(rèn)關(guān)閉Hystrix支持。所以必須在全局配置文件中開(kāi)啟feign技術(shù)中的Hystrix支持。配置如下:

          feign.hystrix.enabled=true

          如果不使用Hystrix服務(wù)容錯(cuò)功能,在application client端,服務(wù)接口只需要繼承服務(wù)標(biāo)準(zhǔn)api接口即可實(shí)現(xiàn)遠(yuǎn)程服務(wù)調(diào)用。如果使用了Hystrix,則有不同的編寫(xiě)方式。具體如下。

          3.1 代碼實(shí)現(xiàn) - 接口實(shí)現(xiàn)類(lèi)方式

          定義和服務(wù)標(biāo)準(zhǔn)api相同的application client服務(wù)接口。并通過(guò)@FeignClient注解來(lái)描述fallback方法所在類(lèi)是什么。這個(gè)fallback方法所在類(lèi)就是接口的實(shí)現(xiàn)類(lèi),實(shí)現(xiàn)的方法就是接口中定義方法的fallback方法。

          /**
           * 如果在Feign中使用Hystrix,則不能直接繼承服務(wù)標(biāo)準(zhǔn)接口。
           * 因?yàn)槔^承接口,一般都不會(huì)給予實(shí)現(xiàn)。會(huì)缺少fallback方法。熔斷機(jī)制鏈條不完整。
           * 在當(dāng)前接口中,重復(fù)定義服務(wù)標(biāo)準(zhǔn)接口中定義的方法。
           * 遠(yuǎn)程服務(wù)調(diào)用的時(shí)候,是通過(guò)@FeignClient實(shí)現(xiàn)的。
           * 如果遠(yuǎn)程服務(wù)調(diào)用失敗,則觸發(fā)fallback注解屬性定義的接口實(shí)現(xiàn)類(lèi)中的對(duì)應(yīng)方法,作為fallback方法。
           * 
           * 在默認(rèn)的Hystrix配置環(huán)境中,使用的是服務(wù)降級(jí)保護(hù)機(jī)制。
           * 
           * 服務(wù)降級(jí),默認(rèn)的情況下,包含了請(qǐng)求超時(shí)。
           * feign聲明式遠(yuǎn)程服務(wù)調(diào)用,在啟動(dòng)的時(shí)候,初始化過(guò)程比較慢(通過(guò)注釋@FeignClient描述接口,接口生成動(dòng)態(tài)代理對(duì)象,實(shí)現(xiàn)服務(wù)調(diào)用)。比ribbon要慢很多。
           * 很容易在第一次訪(fǎng)問(wèn)的時(shí)候,產(chǎn)生超時(shí)。導(dǎo)致返回fallback數(shù)據(jù)。
           */

          @FeignClient(name="test-feign-application-service",
                  fallback=FirstClientFeignServiceImpl.class
                  )
          public interface FirstClientFeignService
          {

              @RequestMapping(value="/testFeign", method=RequestMethod.GET)
              public List<String> testFeign();
              
              @RequestMapping(value="/get", method=RequestMethod.GET)
              public FeignTestPOJO getById(@RequestParam(value="id") Long id);
              
              @RequestMapping(value="/get", method=RequestMethod.POST)
              public FeignTestPOJO getByIdWithPOST(@RequestBody Long id);
              
              @RequestMapping(value="/add", method=RequestMethod.GET)
              public FeignTestPOJO add(@RequestParam("id") Long id, @RequestParam("name") String name);
              
              @RequestMapping(value="/addWithGET", method=RequestMethod.GET)
              public FeignTestPOJO add(@RequestBody FeignTestPOJO pojo);
              
              @RequestMapping(value="/addWithPOST", method=RequestMethod.POST)
              public FeignTestPOJO addWithPOST(@RequestBody FeignTestPOJO pojo);
              
          }

          為接口提供實(shí)現(xiàn)類(lèi),類(lèi)中的方法實(shí)現(xiàn)就是fallback邏輯。實(shí)現(xiàn)類(lèi)需要spring容器管理,使用@Component注解來(lái)描述類(lèi)型。

          /**
           * 實(shí)現(xiàn)類(lèi)中的每個(gè)方法,都是對(duì)應(yīng)的接口方法的fallback。
           * 一定要提供spring相關(guān)注解(@Component/@Service/@Repository等)。
           * 注解是為了讓當(dāng)前類(lèi)型的對(duì)象被spring容器管理。
           * fallback是本地方法。
           * 是接口的實(shí)現(xiàn)方法。
           */

          @Component
          public class FirstClientFeignServiceImpl implements FirstClientFeignService {

              @Override
              public List<String> testFeign() {
                  List<String> result = new ArrayList<>();
                  result.add("this is testFeign method fallback datas");
                  return result;
              }

              @Override
              public FeignTestPOJO getById(Long id) {
                  return new FeignTestPOJO(-1L"this is getById method fallback datas");
              }

              @Override
              public FeignTestPOJO getByIdWithPOST(Long id) {
                  return new FeignTestPOJO(-1L"this is getByIdWithPOST method fallback datas");
              }

              @Override
              public FeignTestPOJO add(Long id, String name) {
                  return new FeignTestPOJO(-1L"this is add(id, name) method fallback datas");
              }

              @Override
              public FeignTestPOJO add(FeignTestPOJO pojo) {
                  return new FeignTestPOJO(-1L"this is add(pojo) method fallback datas");
              }

              @Override
              public FeignTestPOJO addWithPOST(FeignTestPOJO pojo) {
                  return new FeignTestPOJO(-1L"this is addWithPOST method fallback datas");
              }
          }

          3.2 相關(guān)配置

          在Feign技術(shù)中,一般不使用請(qǐng)求合并,請(qǐng)求緩存等容錯(cuò)機(jī)制。常用的機(jī)制是隔離,降級(jí)和熔斷。

          3.2.1 Properties全局配置

          # hystrix.command.default和hystrix.threadpool.default中的default為默認(rèn)CommandKey,CommandKey默認(rèn)值為服務(wù)方法名。# 在properties配置中配置格式混亂,如果需要為每個(gè)方法設(shè)置不同的容錯(cuò)規(guī)則,建議使用yml文件配置。
          # Command Properties

          # Execution相關(guān)的屬性的配置:
          # 隔離策略,默認(rèn)是Thread, 可選Thread|Semaphore
          hystrix.command.default.execution.isolation.strategy=THREAD
          #命令執(zhí)行超時(shí)時(shí)間,默認(rèn)1000ms,只在線(xiàn)程池隔離中有效。
          hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=1000
          # 執(zhí)行是否啟用超時(shí),默認(rèn)啟用true,只在線(xiàn)程池隔離中有效。
          hystrix.command.default.execution.timeout.enabled=true
          # 發(fā)生超時(shí)是是否中斷,默認(rèn)true,只在線(xiàn)程池隔離中有效。
          hystrix.command.default.execution.isolation.thread.interruptOnTimeout=true
          # 最大并發(fā)請(qǐng)求數(shù),默認(rèn)10,該參數(shù)當(dāng)使用ExecutionIsolationStrategy.SEMAPHORE策略時(shí)才有效。如果達(dá)到最大并發(fā)請(qǐng)求數(shù),請(qǐng)求會(huì)被拒絕。# 理論上選擇semaphore的原則和選擇thread一致,但選用semaphore時(shí)每次執(zhí)行的單元要比較小且執(zhí)行速度快(ms級(jí)別),否則的話(huà)應(yīng)該用thread。# semaphore應(yīng)該占整個(gè)容器(tomcat)的線(xiàn)程池的一小部分。
          hystrix.command.default.execution.isolation.semaphore.maxConcurrentRequests=10
          # 如果并發(fā)數(shù)達(dá)到該設(shè)置值,請(qǐng)求會(huì)被拒絕和拋出異常并且fallback不會(huì)被調(diào)用。默認(rèn)10。# 只在信號(hào)量隔離策略中有效,建議設(shè)置大一些,這樣并發(fā)數(shù)達(dá)到execution最大請(qǐng)求數(shù)時(shí),會(huì)直接調(diào)用fallback,而并發(fā)數(shù)達(dá)到fallback最大請(qǐng)求數(shù)時(shí)會(huì)被拒絕和拋出異常。
          hystrix.command.default.fallback.isolation.semaphore.maxConcurrentRequests=10
          # ThreadPool 相關(guān)參數(shù)
          # 并發(fā)執(zhí)行的最大線(xiàn)程數(shù),默認(rèn)10
          hystrix.threadpool.default.coreSize=10
          # BlockingQueue的最大隊(duì)列數(shù),當(dāng)設(shè)為-1,會(huì)使用SynchronousQueue,值為正時(shí)使用LinkedBlcokingQueue。# 該設(shè)置只會(huì)在初始化時(shí)有效,之后不能修改threadpool的queue size,除非reinitialising thread executor。默認(rèn)-1。
          hystrix.threadpool.default.maxQueueSize=-1
          # 即使maxQueueSize沒(méi)有達(dá)到,達(dá)到queueSizeRejectionThreshold該值后,請(qǐng)求也會(huì)被拒絕。
          hystrix.threadpool.default.queueSizeRejectionThreshold=20
          # 線(xiàn)程存活時(shí)間,單位是分鐘。默認(rèn)值為1。
          hystrix.threadpool.default.keepAliveTimeMinutes=1
          # Fallback相關(guān)的屬性 # 當(dāng)執(zhí)行失敗或者請(qǐng)求被拒絕,是否會(huì)嘗試調(diào)用fallback方法 。默認(rèn)true hystrix.command.default.fallback.enabled=true # Circuit Breaker相關(guān)的屬性 # 是否開(kāi)啟熔斷器。默認(rèn)true hystrix.command.default.circuitBreaker.enabled=true # 一個(gè)rolling window內(nèi)最小的請(qǐng)求數(shù)。如果設(shè)為20,那么當(dāng)一個(gè)rolling window的時(shí)間內(nèi)(比如說(shuō)1個(gè)rolling window是10毫秒)收到19個(gè)請(qǐng)求# 即使19個(gè)請(qǐng)求都失敗,也不會(huì)觸發(fā)circuit break。默認(rèn)20
          hystrix.command.default.circuitBreaker.requestVolumeThreshold=20
          # 觸發(fā)短路的時(shí)間值,當(dāng)該值設(shè)為5000時(shí),則當(dāng)觸發(fā)circuit break后的5000毫秒內(nèi)都會(huì)拒絕遠(yuǎn)程服務(wù)調(diào)用,也就是5000毫秒后才會(huì)重試遠(yuǎn)程服務(wù)調(diào)用。默認(rèn)5000
          hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds=5000
          # 錯(cuò)誤比率閥值,如果錯(cuò)誤率>=該值,circuit會(huì)被打開(kāi),并短路所有請(qǐng)求觸發(fā)fallback。默認(rèn)50
          hystrix.command.default.circuitBreaker.errorThresholdPercentage=50
          # 強(qiáng)制打開(kāi)熔斷器
          hystrix.command.default.circuitBreaker.forceOpen=false
          # 強(qiáng)制關(guān)閉熔斷器
          hystrix.command.default.circuitBreaker.forceClosed=false

          3.2.2 YML全局配置

          YML配置文件,對(duì)SpringEL的支持更加優(yōu)秀??梢酝ㄟ^(guò)SpringEL定制化的為每個(gè)服務(wù)調(diào)用配置Hystrix的容錯(cuò)處理方案。對(duì)Hystrix的配置粒度相比較Properties的配置方案更加細(xì)致。

          在YML中可配置的Hystrix信息,和Properties中配置的內(nèi)容是一致。

          如果需要對(duì)每個(gè)服務(wù)做定制化配置,建議使用yml配置文件。在語(yǔ)法和格式上更容易管理和維護(hù)。

          spring:
            application:
              name: test-feign-application-client
          server:
            port: 9008

          feign:
            hystrix:
              enabled: true

          hystrix:
            command:
              # default代表全部服務(wù)配置,如果為某個(gè)具體服務(wù)定制配置,使用:'服務(wù)接口名#方法名(參數(shù)類(lèi)型列表)'的方式來(lái)定義。
              # 如:'FirstClientFeignService#test(int)'。如果接口名稱(chēng)在應(yīng)用中唯一,可以只寫(xiě)simpleName。
              # 如果接口名稱(chēng)在應(yīng)用中不唯一,需要寫(xiě)fullName(包名.類(lèi)名)
              "FirstClientFeignService#testFeign()":
                fallback:
                  enabled: true

          3.3 代碼實(shí)現(xiàn) - Factory實(shí)現(xiàn)方式

          在服務(wù)接口的@FeignClient注解中,不再使用fallback屬性,而是定義fallbackFactory屬性。這個(gè)屬性的類(lèi)型是Class類(lèi)型的,用于配置fallback代碼所處的Factory。

          再定義一個(gè)Java類(lèi),實(shí)現(xiàn)接口FallbackFactory,實(shí)現(xiàn)其中的create方法。使用匿名內(nèi)部類(lèi)的方式,為服務(wù)接口定義一個(gè)實(shí)現(xiàn)類(lèi),定義fallback方法實(shí)現(xiàn)。


          本地接口定義:

          @FeignClient(name="test-feign-application-service",
                  fallbackFactory=FirstClientFeignServiceFallbackFactory.class
                  )
          public interface FirstClientFeignService
          {

              @RequestMapping(value="/testFeign", method=RequestMethod.GET)
              public List<String> testFeign();
              
              @RequestMapping(value="/get", method=RequestMethod.GET)
              public FeignTestPOJO getById(@RequestParam(value="id") Long id);
              
              @RequestMapping(value="/get", method=RequestMethod.POST)
              public FeignTestPOJO getByIdWithPOST(@RequestBody Long id);
              
              @RequestMapping(value="/add", method=RequestMethod.GET)
              public FeignTestPOJO add(@RequestParam("id") Long id, @RequestParam("name") String name);
              
              @RequestMapping(value="/addWithGET", method=RequestMethod.GET)
              public FeignTestPOJO add(@RequestBody FeignTestPOJO pojo);
              
              @RequestMapping(value="/addWithPOST", method=RequestMethod.POST)
              public FeignTestPOJO addWithPOST(@RequestBody FeignTestPOJO pojo);
              
          }

          FallbackFactory實(shí)現(xiàn)類(lèi):

          /**
           * 使用Factory方式實(shí)現(xiàn)Feign的Hystrix容錯(cuò)處理。
           * 編寫(xiě)的自定義Factory必須實(shí)現(xiàn)接口FallbackFactory。
           * FallbackFactory中的方法是
           *  服務(wù)接口的類(lèi)型 create(Throwable 遠(yuǎn)程服務(wù)調(diào)用的錯(cuò)誤)
           * 
           * 工廠(chǎng)實(shí)現(xiàn)方案和服務(wù)接口實(shí)現(xiàn)類(lèi)實(shí)現(xiàn)方案的區(qū)別:
           *  工廠(chǎng)可以提供自定義的異常信息處理邏輯。因?yàn)閏reate方法負(fù)責(zé)傳遞遠(yuǎn)程服務(wù)調(diào)用的異常對(duì)象。
           *  實(shí)現(xiàn)類(lèi)可以快速的開(kāi)發(fā),但是會(huì)丟失遠(yuǎn)程服務(wù)調(diào)用的異常信息。
           */

          @Component
          public class FirstClientFeignServiceFallbackFactory implements FallbackFactory<FirstClientFeignService{

              Logger logger = LoggerFactory.getLogger(FirstClientFeignServiceFallbackFactory.class);
              
              /**
               * create方法 - 就是工廠(chǎng)的生產(chǎn)產(chǎn)品的方法。
               *  當(dāng)前工廠(chǎng)生產(chǎn)的產(chǎn)品就是服務(wù)接口的Fallback處理對(duì)象。 就是服務(wù)接口的實(shí)現(xiàn)類(lèi)的對(duì)象。
               */

              @Override
              public FirstClientFeignService create(final Throwable cause) {
                  
                  return new FirstClientFeignService() {
                      @Override
                      public List<String> testFeign() {
                          logger.warn("testFeign() - ", cause);
                          List<String> result = new ArrayList<>();
                          result.add("this is testFeign method fallback datas");
                          return result;
                      }

                      @Override
                      public FeignTestPOJO getById(Long id) {
                          return new FeignTestPOJO(-1L"this is getById method fallback datas");
                      }

                      @Override
                      public FeignTestPOJO getByIdWithPOST(Long id) {
                          return new FeignTestPOJO(-1L"this is getByIdWithPOST method fallback datas");
                      }

                      @Override
                      public FeignTestPOJO add(Long id, String name) {
                          return new FeignTestPOJO(-1L"this is add(id, name) method fallback datas");
                      }

                      @Override
                      public FeignTestPOJO add(FeignTestPOJO pojo) {
                          return new FeignTestPOJO(-1L"this is add(pojo) method fallback datas");
                      }

                      @Override
                      public FeignTestPOJO addWithPOST(FeignTestPOJO pojo) {
                          return new FeignTestPOJO(-1L"this is addWithPOST method fallback datas");
                      }
                  };
              }
          }

          這種實(shí)現(xiàn)邏輯的優(yōu)勢(shì)是,可以獲取遠(yuǎn)程調(diào)用服務(wù)的異常信息。為后期異常處理提供參考。

          工廠(chǎng)實(shí)現(xiàn)方案和實(shí)現(xiàn)類(lèi)的實(shí)現(xiàn)方案,沒(méi)有效率和邏輯上的優(yōu)缺點(diǎn)對(duì)比。只是在遠(yuǎn)程服務(wù)調(diào)用異常的處理上有區(qū)別。

          4 Hystrix Dashboard - 數(shù)據(jù)監(jiān)控

          Hystrix dashboard是一款針對(duì)Hystrix進(jìn)行實(shí)時(shí)監(jiān)控的工具,通過(guò)Hystrix Dashboard我們可以在直觀(guān)地看到各Hystrix Command的請(qǐng)求響應(yīng)時(shí)間, 請(qǐng)求成功率等數(shù)據(jù)。

          4.1 實(shí)現(xiàn)單服務(wù)單節(jié)點(diǎn)數(shù)據(jù)監(jiān)控

          在使用了Hystrix技術(shù)的application client工程中增加下述依賴(lài):

          <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-actuator</artifactId>
          </dependency>

          <dependency>
              <groupId>org.springframework.cloud</groupId>
              <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
          </dependency>

          在啟動(dòng)器上增加注解@EnableHystrixDashboard、@EnableHystrix。

          @EnableCircuitBreaker
          @EnableCaching
          @EnableEurekaClient
          @SpringBootApplication
          @EnableHystrixDashboard
          @EnableHystrix
          public class HystrixDashboardApplication {

              public static void main(String[] args) {
                  SpringApplication.run(HystrixDashboardApplication.classargs);
              }
              
          }

          啟動(dòng)工程后,如果觸發(fā)了Hystrix,則可以通過(guò)http://ip:port/hystrix.stream得到監(jiān)控?cái)?shù)據(jù)。這種監(jiān)控?cái)?shù)據(jù)的獲取都是JSON數(shù)據(jù)。

          且數(shù)據(jù)量級(jí)較大。不易于查看??梢允褂肏ystrix Dashboard提供的視圖界面來(lái)觀(guān)察監(jiān)控結(jié)果。視圖界面訪(fǎng)問(wèn)路徑為http://ip:port/hystrix。視圖界面中各數(shù)據(jù)的含義如下:

          建議:監(jiān)控中心建議使用獨(dú)立工程來(lái)實(shí)現(xiàn)。這樣更便于維護(hù)。

          4.2 使用Turbine實(shí)現(xiàn)多服務(wù)或集群的數(shù)據(jù)監(jiān)控

          Turbine是聚合服務(wù)器發(fā)送事件流數(shù)據(jù)的一個(gè)工具,hystrix的監(jiān)控中,只能監(jiān)控單個(gè)服務(wù)或單個(gè)節(jié)點(diǎn),實(shí)際生產(chǎn)中都為多服務(wù)集群,因此可以通過(guò)turbine來(lái)監(jiān)控多集群服務(wù)。

          Turbine在Hystrix Dashboard中的作用如下:

          4.2.1多服務(wù)監(jiān)控

          當(dāng)使用Turbine來(lái)監(jiān)控多服務(wù)狀態(tài)時(shí),需提供一個(gè)獨(dú)立工程來(lái)搭建Turbine服務(wù)邏輯。并在工程中增加下述依賴(lài):

          <!-- Dashboard需要的依賴(lài)信息。 -->
          <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-actuator</artifactId>
          </dependency>

          <dependency>
              <groupId>org.springframework.cloud</groupId>
              <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
          </dependency>
          <!-- Turbine需要的依賴(lài)信息。 -->
          <dependency>
              <groupId>org.springframework.cloud</groupId>
              <artifactId>spring-cloud-starter-turbine</artifactId>
          </dependency>
          <dependency>
              <groupId>org.springframework.cloud</groupId>
              <artifactId>spring-cloud-netflix-turbine</artifactId>
          </dependency>

          并在全局配置文件中增加下述配置:

          #配置Eureka中的serviceId列表,標(biāo)記監(jiān)控哪些服務(wù),多個(gè)服務(wù)名用逗號(hào)分隔,可以配置監(jiān)控的服務(wù),必須開(kāi)啟了Hystrix Dashboard。
          turbine.appConfig=hystrix-application-client,test-feign-application-client
          #指定聚合哪些集群,多個(gè)使用","分割,default代表默認(rèn)集群。集群就是服務(wù)名稱(chēng)。需要配置clusterNameExpression使用。
          turbine.aggregator.clusterConfig=default
          # 1. clusterNameExpression指定集群名稱(chēng),默認(rèn)表達(dá)式appName;此時(shí):turbine.aggregator.clusterConfig需要配置想要監(jiān)控的應(yīng)用名稱(chēng);
          # 2. 當(dāng)clusterNameExpression: default時(shí),turbine.aggregator.clusterConfig可以不寫(xiě),因?yàn)槟J(rèn)就是default;代表所有集群都需要監(jiān)控
          turbine.clusterNameExpression="default"

          在應(yīng)用啟動(dòng)類(lèi)中,增加注解@EnableTurbine,代表開(kāi)啟Turbine服務(wù),提供多服務(wù)集群監(jiān)控?cái)?shù)據(jù)收集。

          /**
           * @EnableTurbine - 開(kāi)啟Turbine功能。
           *  可以實(shí)現(xiàn)收集多個(gè)App client的Dashboard監(jiān)控?cái)?shù)據(jù)。
           */

          @SpringBootApplication
          @EnableTurbine
          public class HystrixTurbineApplication {

              public static void main(String[] args) {
                  SpringApplication.run(HystrixTurbineApplication.classargs);
              }
              
          }

          最后再Hystrix Dashboard視圖監(jiān)控服務(wù)中,使用http://ip:port/turbine.stream作為監(jiān)控?cái)?shù)據(jù)來(lái)源,提供可視化監(jiān)控界面。

          注意:使用Turbine做多服務(wù)監(jiān)控的時(shí)候,要求全局配置文件中配置的服務(wù)列表命名在Eureka注冊(cè)中心中可見(jiàn)。就是先啟動(dòng)Application client再啟動(dòng)Turbine。

          4.2.2服務(wù)集群監(jiān)控

          在spring cloud中,服務(wù)名相同的多服務(wù)結(jié)點(diǎn)會(huì)自動(dòng)形成集群,并提供服務(wù)。在Turbine中,監(jiān)控服務(wù)集群不需要提供任何的特殊配置,因?yàn)閠urbine.appConfig已經(jīng)配置了要監(jiān)控的服務(wù)名稱(chēng)。集群監(jiān)控?cái)?shù)據(jù)會(huì)自動(dòng)收集。

          在Hystrix Dashboard的可視化監(jiān)控界面中,hosts信息會(huì)顯示出服務(wù)集群中的節(jié)點(diǎn)數(shù)量。如圖所示:

          注意:使用Turbine做服務(wù)集群監(jiān)控的時(shí)候,必須先啟動(dòng)application client集群,再啟動(dòng)Turbine。保證Turbine啟動(dòng)的時(shí)候,可以在eureka注冊(cè)中心中發(fā)現(xiàn)要監(jiān)控的服務(wù)集群。

          1. 場(chǎng)景+案例分析,SQL優(yōu)化這么做就對(duì)了!

          2. 老板要我開(kāi)發(fā)一個(gè)簡(jiǎn)單的工作流引擎 !

          3. 面試題必問(wèn): 遇到過(guò)線(xiàn)上問(wèn)題沒(méi),你是怎么排查的?

          4. 精選 21道 Redis 最常問(wèn)面試題!收藏一波 !

          最近面試BAT,整理一份面試資料Java面試BATJ通關(guān)手冊(cè),覆蓋了Java核心技術(shù)、JVM、Java并發(fā)、SSM、微服務(wù)、數(shù)據(jù)庫(kù)、數(shù)據(jù)結(jié)構(gòu)等等。

          獲取方式:點(diǎn)“在看”,關(guān)注公眾號(hào)并回復(fù) Java 領(lǐng)取,更多內(nèi)容陸續(xù)奉上。

          文章有幫助的話(huà),在看,轉(zhuǎn)發(fā)吧。

          謝謝支持喲 (*^__^*)

          瀏覽 74
          點(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>
                  人人妻日日摸狠狠躁视频 | 青青欧美,青青美女视频 | 一区二区三区成人 | 热视频精品| 免费看无码成人A片 |