自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

快速入門 | 輕松掌握Hystrix實現(xiàn)資源隔離保護系統(tǒng)穩(wěn)定

開發(fā) 前端
當(dāng)有大量的請求調(diào)用時我們的所有線程都會被阻塞T的時間。本身Tomcat線程池的線程數(shù)量是有限的,這就會造成很多的客戶端只能等待,尤其是越是后來的請求等待的時間會越長,同時由于這一個接口把所有的tomcat線程全部占用完,導(dǎo)致了其他的所有服務(wù)不可用全部處于等待狀態(tài),從而會拖垮整個tomcat,而這種現(xiàn)象我們稱誒雪崩效應(yīng)。

先看下如下圖,兩個服務(wù)之間的調(diào)用 A服務(wù)調(diào)用另外一個B服務(wù)。

圖片圖片

在這個圖當(dāng)中有個接口A需要調(diào)用另外一個服務(wù)的接口B。這里看似沒有什么問題。

例如,本身A服務(wù)接口執(zhí)行邏輯需要5ms執(zhí)行完后再調(diào)用B服務(wù)接口的,調(diào)用B接口執(zhí)行完成需要4s,比如下面的下定單扣庫存的流程:

圖片圖片

這里整個接口調(diào)用鏈執(zhí)行完成需要實際T=4s+5ms;

當(dāng)有大量的請求調(diào)用時我們的所有線程都會被阻塞T的時間。本身Tomcat線程池的線程數(shù)量是有限的,這就會造成很多的客戶端只能等待,尤其是越是后來的請求等待的時間會越長,同時由于這一個接口把所有的tomcat線程全部占用完,導(dǎo)致了其他的所有服務(wù)不可用全部處于等待狀態(tài),從而會拖垮整個tomcat,而這種現(xiàn)象我們稱誒雪崩效應(yīng)。

對于服務(wù)之間的調(diào)用我們也應(yīng)該能夠設(shè)置一個超時時間,不能讓其一直等待下去。當(dāng)超過了給定的時間后我們也能夠給予用戶一個響應(yīng),通過這種方式來避免這種級聯(lián)的故障。如上所述,當(dāng)整個A服務(wù)不可用的時候 這時候的B服務(wù)也就不可用了,這種現(xiàn)象被稱為雪崩效應(yīng)。

雪崩效應(yīng)常見場景

  • 硬件故障:如服務(wù)器宕機,機房斷電,光纖被挖斷等。
  • 流量激增:如異常流量,重試加大流量等。
  • 緩存穿透:一般發(fā)生在應(yīng)用重啟,所有緩存失效時,以及短時間內(nèi)大量緩存失效時。大量的緩存不命中,使請求直擊后端服務(wù),造成服務(wù)提供者超負荷運行,引起服務(wù)不可用。
  • 程序BUG:如程序邏輯導(dǎo)致內(nèi)存泄漏,JVM長時間FullGC等。
  • 同步等待:服務(wù)間采用同步調(diào)用模式,同步等待造成的資源耗盡。

雪崩效應(yīng)應(yīng)對策略

針對造成雪崩效應(yīng)的不同場景,可以使用不同的應(yīng)對策略,沒有一種通用所有場景的策略,參考如下:

  • 硬件故障:多機房容災(zāi)、異地多活等。
  • 流量激增:服務(wù)自動擴容、流量控制(限流、關(guān)閉重試)等。
  • 緩存穿透:緩存預(yù)加載、緩存異步加載等。
  • 程序BUG:修改程序bug、及時釋放資源等。
  • 同步等待:資源隔離、MQ解耦、不可用服務(wù)調(diào)用快速失敗等。資源隔離通常指不同服務(wù)調(diào)用采用不同的線程池;不可用服務(wù)調(diào)用快速失敗一般通過熔斷器模式結(jié)合超時機制實現(xiàn)。

在程序中我們能通過Hystrix來實現(xiàn)資源的隔離,保護我們的服務(wù),不至于導(dǎo)致整個tomcat服務(wù)不可用。

Hystrix是Netflix開源的一款針對分布式系統(tǒng)的延遲和容錯庫,目的是用來隔離分布式服務(wù)故障。它提供線程和信號量隔離,以減少不同服務(wù)之間資源競爭帶來的相互影響;提供優(yōu)雅降級機制;提供熔斷機制使得服務(wù)可以快速失敗,而不是一直阻塞等待服務(wù)響應(yīng),并能從中快速恢復(fù)。Hystrix通過這些機制來阻止級聯(lián)失敗并保證系統(tǒng)彈性、可用。通過下圖來理解:

圖片圖片

也就是在調(diào)用B服務(wù)接口的時候我們放到另外的一個線程中去執(zhí)行,防止出現(xiàn)上面說的問題。

接下來我們來通過程序代碼來看看如何使用hystrix。

這里我們以調(diào)用訂單服務(wù)為例

pom.xml加入依賴

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    <version>2.2.1.RELEASE</version>
</dependency>

方式1:

通過繼承HystrixCommand

public class OrdersCommand extends HystrixCommand<Orders> {


  private RestTemplate restTemplate ;
  private Long id ;


  public OrdersCommand(RestTemplate restTemplate, Long id) {
    super(buildSetter()) ;
    this.restTemplate = restTemplate ;
    this.id = id ;
  }
  private static Setter buildSetter() {
    com.netflix.hystrix.HystrixThreadPoolProperties.Setter threadPoolProp = com.netflix.hystrix.HystrixThreadPoolProperties.Setter() ;
    threadPoolProp.withCoreSize(5)
      .withKeepAliveTimeMinutes(5)
      .withMaxQueueSize(Integer.MAX_VALUE)
      .withQueueSizeRejectionThreshold(1000) ;


    com.netflix.hystrix.HystrixCommandProperties.Setter commandProp = com.netflix.hystrix.HystrixCommandProperties.Setter() ;
    commandProp.withCircuitBreakerEnabled(true)
      .withExecutionTimeoutInMilliseconds(6000)
      .withRequestCacheEnabled(true)
      .withExecutionIsolationStrategy(ExecutionIsolationStrategy.THREAD);


    return Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("orders"))
           .andCommandKey(HystrixCommandKey.Factory.asKey("getOrder"))
           .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("order-pool"))
           .andThreadPoolPropertiesDefaults(threadPoolProp)
           .andCommandPropertiesDefaults(commandProp) ;
  }


  @Override
  protected Orders run() throws Exception {
    return restTemplate.getForObject("http://localhost:9810/orders/queryOrder/{1}", Orders.class, id);
  }


  @Override
  protected Orders getFallback() {
    return new Orders() ;
  }
  @Override
  protected String getCacheKey() {
    return "order-" + this.id ;
  }


}

這里我們實現(xiàn)了父類的getFallback方法

該方法為當(dāng)服務(wù)調(diào)用失敗或者超時會被調(diào)用。

這里通過buildSetter方法來構(gòu)建hystrix相關(guān)的配置。說明:

threadPoolProp.withCoreSize(5)
      .withKeepAliveTimeMinutes(5)
      .withMaxQueueSize(Integer.MAX_VALUE)
      .withQueueSizeRejectionThreshold(1000) ;

以上是對線程池的配置。

其它設(shè)置:

RequestVolumeThreshold

HystrixCommandProperties.Setter().withCircuitBreakerRequestVolumeThreshold(int)表示在滑動窗口中,至少有多少個請求,才可能觸發(fā)斷路。Hystrix 經(jīng)過斷路器的流量超過了一定的閾值,才有可能觸發(fā)斷路。比如說,要求在 10s 內(nèi)經(jīng)過斷路器的流量必須達到 20 個,而實際經(jīng)過斷路器的流量才 10 個,那么根本不會去判斷要不要斷路。

ErrorThresholdPercentage

HystrixCommandProperties.Setter().withCircuitBreakerErrorThresholdPercentage(int)表示異常比例達到多少,才會觸發(fā)斷路,默認值是 50(%)。如果斷路器統(tǒng)計到的異常調(diào)用的占比超過了一定的閾值,比如說在 10s 內(nèi),經(jīng)過斷路器的流量達到了 30 個,同時其中異常訪問的數(shù)量也達到了一定的比例,比如 60% 的請求都是異常(報錯 / 超時 / reject),就會開啟斷路。

SleepWindowInMilliseconds

HystrixCommandProperties.Setter().withCircuitBreakerSleepWindowInMilliseconds(int)斷路開啟,也就是由 close 轉(zhuǎn)換到 open 狀態(tài)(close -> open)。那么之后在 SleepWindowInMilliseconds 時間內(nèi),所有經(jīng)過該斷路器的請求全部都會被斷路,不調(diào)用后端服務(wù),直接走 fallback 降級機制。而在該參數(shù)時間過后,斷路器會變?yōu)?half-open 半開閉狀態(tài),嘗試讓一條請求經(jīng)過斷路器,看能不能正常調(diào)用。如果調(diào)用成功了,那么就自動恢復(fù),斷路器轉(zhuǎn)為 close 狀態(tài)。

EnabledHystrixCommandProperties.Setter().withCircuitBreakerEnabled(boolean)控制是否允許斷路器工作,包括跟蹤依賴服務(wù)調(diào)用的健康狀況,以及對異常情況過多時是否允許觸發(fā)斷路。默認值是 true。

ForceOpen

HystrixCommandProperties.Setter().withCircuitBreakerForceOpen(boolean)如果設(shè)置為 true 的話,直接強迫打開斷路器,相當(dāng)于是手動斷路了,手動降級,默認值是 false。

ForceClosedHystrixCommandProperties.Setter().withCircuitBreakerForceClosed(boolean)

如果設(shè)置為 true,直接強迫關(guān)閉斷路器,相當(dāng)于手動停止斷路了,手動升級,默認值是 false。

參考:

圖片圖片

com.netflix.hystrix.HystrixCommandProperties.Setter commandProp = com.netflix.hystrix.HystrixCommandProperties.Setter() ;
    commandProp.withCircuitBreakerEnabled(true)
      .withExecutionTimeoutInMilliseconds(6000)
      .withRequestCacheEnabled(true)
      .withExecutionIsolationStrategy(ExecutionIsolationStrategy.THREAD);

以上是對命令屬性的配置。

withCircuitBreakerEnabled:控制是否允許斷路器工作,包括跟蹤依賴服務(wù)調(diào)用的健康狀況,以及對異常情況過多時是否允許觸發(fā)斷路。默認值是 true。

withExecutionTimeoutInMilliseconds:執(zhí)行超時時間的設(shè)置。如果一個 command 運行時間超過了設(shè)定的時長,那么就被認為是 timeout,然后 Hystrix command 標識為 timeout,同時執(zhí)行 fallback 降級邏輯。

withExecutionIsolationStrategy:執(zhí)行隔離的策略,這里設(shè)置為線程。還可以設(shè)置為基于信號量的

ExecutionIsolationStrategy.SEMAPHORE:一般如果并發(fā)量比較大的情況下我們用信號量,性能要好。如果并發(fā)量大你還用線程池,那么你該創(chuàng)建多少的線程呢?而過多的線程帶來了更多線程的切換而影響性能。

return Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("orders"))
   .andCommandKey(HystrixCommandKey.Factory.asKey("getOrder"))
   .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("order-pool"))
   .andThreadPoolPropertiesDefaults(threadPoolProp)
   .andCommandPropertiesDefaults(commandProp) ;

withGroupKey:服務(wù)分組;比如這里調(diào)用訂單系統(tǒng)就是一個服務(wù)分組。模塊;

andCommandKey:服務(wù)標識;比如這里訂單系統(tǒng)有一個獲取訂單信息服務(wù)。子模塊;

andThreadPoolKey:線程池名稱;

andThreadPoolPropertiesDefaults:線程池配置;

andCommandPropertiesDefaults:命令屬性配置;

示例:

@GetMapping("/custom/{id}")
public Object custom(@PathVariable Long id) {
  HystrixRequestContext ctx = HystrixRequestContext.initializeContext() ;
  try {
    OrdersCommand command = new OrdersCommand(restTemplate, id) ;
    System.out.println(Thread.currentThread().getName() + ": " + System.currentTimeMillis()) ;
    Orders res = command.execute() ;
  } finally {
    ctx.shutdown() ;
  }
  return null ;
}

注意:HystrixRequestContext ctx =HystrixRequestContext.initializeContext() ;這行代碼必須調(diào)用。

方式2:

通過注解的方式。

@Service
public class RemoteHystrixService {
  @Resource
  private RestTemplate restTemplate ;
  /**
   *  <p>
   *    groupKey: 服務(wù)分組;比如這里調(diào)用訂單系統(tǒng)就是一個服務(wù)分組。模塊
   *    commandKey: 服務(wù)標識;比如這里訂單系統(tǒng)有一個獲取訂單信息服務(wù)。子模塊
   *    threadPoolKey: 線程池名稱;
   *    threadPoolProperties:線程池配置
   *  </p>
   * @author 爺爺
   * @param id
   * @return Orders
   */
  @HystrixCommand(fallbackMethod = "defaultOrder", 
      groupKey = "orders", 
      commandKey = "getOrder",
      threadPoolKey = "order-pool",
      threadPoolProperties = {
          @HystrixProperty(name = "coreSize", value = "10"),
          @HystrixProperty(name = "keepAliveTimeMinutes", value = "5"),
          @HystrixProperty(name = "maxQueueSize", value = "1000000"),
          @HystrixProperty(name = "queueSizeRejectionThreshold", value = "1000")
      },
      commandProperties = {
          @HystrixProperty(name = "execution.isolation.strategy", value = "THREAD"),
          @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "6000")
      }
    )
  public Orders getOrder(Long id) {
    System.out.println(Thread.currentThread() + ", start") ;
    Orders res = restTemplate.getForObject("http://localhost:9810/orders/queryOrder/{1}", Orders.class, id);
    System.out.println(Thread.currentThread() + ", end") ;
    return res ;
  }


  public Orders defaultOrder(Long id) {
    return new Orders() ;
  }


}

這里具體注解屬性的說明與方式1中 一一對應(yīng)。

責(zé)任編輯:武曉燕 來源: Spring全家桶實戰(zhàn)案例源碼
相關(guān)推薦

2020-01-10 11:18:17

Hystrix架構(gòu)系統(tǒng)

2017-04-03 21:52:30

隔離線程池分布式

2017-07-04 17:35:46

微服務(wù)架構(gòu)Spring Clou

2024-04-16 00:00:00

Spring微服務(wù)架構(gòu)

2011-04-14 10:18:20

數(shù)據(jù)遷移

2024-02-27 08:22:56

2013-02-18 08:36:51

powershell

2010-01-13 17:47:59

VB.NET拖放

2009-12-17 14:36:57

Ruby on Rai

2023-06-29 07:55:52

Quartz.Net開源

2020-10-09 07:56:52

Linux

2023-10-20 08:01:08

2010-01-07 13:53:43

Linux入門

2010-01-18 19:36:52

VB.NET調(diào)整控件

2024-06-12 00:00:01

Java函數(shù)式接口

2024-02-28 10:20:08

2010-08-05 16:08:12

輕松掌握DB2 9.5

2023-08-31 08:34:07

Users對象序列化

2024-06-27 10:50:01

2009-11-02 11:37:37

點贊
收藏

51CTO技術(shù)棧公眾號