天天看點

模拟實戰(2) - 一文秒懂Ribbon、Hystrix實作服務負載均衡、資源隔離與熔斷降級

前言:本篇為SpringCloud Greenwich版本模拟業務實戰系列文章第二篇,上篇文章主要講了服務治理、高可用安全的服務注冊中心,那麼本文将對ribbon、hystrix進行介紹,對其如何實作服務負載均衡,以及如何保證服務之間調用資源的隔離、以及發生緊急情況時對服務進行熔斷降級操作進行詳細講解

一、元件介紹

1、Ribbon

ribbon是屬于Netflix的一款基于用戶端http、tcp負載均衡的一個小架構,何為用戶端負載均衡,簡單了解就是用戶端擷取了服務注冊中心的所有注冊數緩存在本地,并定時維護本地緩存的注冊資料;用戶端發起遠端服務請求,則采用一系列的負載均衡政策從本地擷取一個服務的位址資料并對其發送網絡請求。

我們平常所了解的SpringCloud ribbon則是對Netflix的ribbon進行了一系列的封裝,使其無縫對接SpringCloud環境開發,并且能夠無縫對接各大主流服務治理架構,如Eureka、Consul等;就比如我們采用RestTemplate結合Ribbon對遠端服務進行通路隻需要加一個注解@LoadBalanced就可以起到對注冊中心的所有服務進行負載均衡的作用,我們根本察覺不到其實他們已經自動整合了,這也歸功于SpringCloud對其進行了如此完美的封裝。也正因如此,許多入門小白會滿頭霧水,後續我也會針對SpringCloud各個元件的源碼進行一系列的講解。

2、Hystrix

Hystrix也是Netflix開源的一款,針對服務之間調用限制其可使用的 線程資源 、以及服務調用失敗可以調用指定的 降級處理 方法、包括調用的目标服務執行個體如果不可通路了,會針對設定的熔斷門檻值(預設調用失敗超過50%)對該服務執行個體進行 熔斷處理 ,所有的服務在短期設定的時間内直接傳回調用失敗,如果設定了降級方法則會調用降級方法。

二、為何使用?

1、為什麼要使用ribbon

其實這個問題相信大家已經都明白了,ribbon的主要功能就是用戶端負載均衡,并且是對服務注冊中心已經注冊了的服務進行負載均衡,沒有ribbon的話 我們得自己編寫一套負載均衡機制,除非你的服務執行個體是單個的,但是這不太現實!還有 就是後面的feign 也是基于ribbon來進行服務執行個體的負載均衡調用。

2、為什麼要使用hystrix

很簡單

1、熔斷機制 保證了阻斷了不可用的服務,直接響應請求失敗,不會再去重重複請求占用資源。

2、資源隔離 可以保證對某個依賴服務進行調用時哪怕請求再多,隻耗費屬于其的線程資源,并不會影響别的服務的調用。

3、降級政策 可設定服務調用失敗後執行的方法。

是以正應為hystrix的強大,才使其成為高可用、穩定、健壯的SpringCloud微服務系統中必不可少的元件之一。

三、ribbon的使用

在使用ribbon之前(這裡指SpringCloud 封裝過後的ribbon),我們可以先了解一下原始的netfix ribbon大概是如何使用的

模拟實戰(2) - 一文秒懂Ribbon、Hystrix實作服務負載均衡、資源隔離與熔斷降級
模拟實戰(2) - 一文秒懂Ribbon、Hystrix實作服務負載均衡、資源隔離與熔斷降級
模拟實戰(2) - 一文秒懂Ribbon、Hystrix實作服務負載均衡、資源隔離與熔斷降級

看上去還是挺簡單的,但是當我們的SpringCloud給ribbon畫龍點睛了一下,你會發現隻要短短兩三行代碼,外加兩三行配置,就可以無縫對接eureka乃至consul,并且隻需要一個注解就可以為注冊中心的各個服務進行負載均衡操作!

1、restTemplate + @LoadBalanced 使用ribbon負載均衡調用服務

在之前的 user-server 服務稍作修改,引入restTemplate,restTemplate是spring提供的一個非常強大的調用http rest接口的一款工具,不了解的可以去Google一下,這裡不做贅述。

@RestController
@SpringBootApplication
@EnableEurekaClient
public class App {

    @Bean
    @LoadBalanced //加上此注解增加負載均衡功能,并使其能直接用服務名來進行調用
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

    @Autowired
    RestTemplate restTemplate;

    @GetMapping("/test")
    @ResponseBody
    public Object test(){
        //使用restTemplate根據服務名調用,預設的restTemplate是沒有此功能的
       String str = restTemplate.getForObject("http://provider-goods-service/test",String.class);
       return str;
    }
   
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}
           
2、給 goods-server 加上一個測試controller,再複制一個goods-server run,并設定不同啟動端口

測試controller

@GetMapping("/test")
    @ResponseBody
    public Object test(HttpServletRequest request){
        return "調用成功 目前服務端口為:"+ request.getServerPort();
    }
           

啟動多個 goods-server

模拟實戰(2) - 一文秒懂Ribbon、Hystrix實作服務負載均衡、資源隔離與熔斷降級

啟動并檢視eureka server是否注冊上

模拟實戰(2) - 一文秒懂Ribbon、Hystrix實作服務負載均衡、資源隔離與熔斷降級
3、多次通路 user-server /test 測試位址,檢視結果
模拟實戰(2) - 一文秒懂Ribbon、Hystrix實作服務負載均衡、資源隔離與熔斷降級
模拟實戰(2) - 一文秒懂Ribbon、Hystrix實作服務負載均衡、資源隔離與熔斷降級

從請求結果我們可以看出我們的請求已經被負載均衡了。這裡并不需要重複引用ribbon的依賴,因為spring-cloud-starter-netflix-eureka-client 已經引入ribbon依賴了。

整個負載均衡請求流程為 (前方高能)

模拟實戰(2) - 一文秒懂Ribbon、Hystrix實作服務負載均衡、資源隔離與熔斷降級

看不太懂的小夥伴别急,先學會如何使用, 後續會有專門的源碼講解篇。

4、配置

–負載均規則略–

上面我們實作了對服務執行個體進行負載均衡,我們重複進行通路可以發現ribbon預設使用的輪詢請求的方式來進行負載均衡,除了輪詢請求(RoundRobinRule)外,還有一些其他比較常用的

  • RandomRule - 随機選擇服務
  • WeightedResponseTimeRule 根據響應時間來配置權重,響應最快的權重高,反之則少
  • BestAvailableRule 最少請求的服務

–常用配置項-

#針對單個服務配置路由規則,注意 配置的值 需要類全名(包名+類名);
provider-goods-service: #目标服務名
  ribbon:
    ConnectionTimeout: 400 #連結逾時
    ReadTimeout: 400 #讀取逾時
    MaxAutoRetries: 1 #重試目前執行個體的次數
    MaxAutoRetriesNextServer: 1 #服務執行個體切換重試次數
    ServerListRefreshInterval: 30000 #重新整理所服務清單間隔時間
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #配置對應的規則,其他ribbon自帶的規則 可檢視IRule接口的實作類

#ribbon:
#  ConnectionTimeout: 400 #連結逾時
#  ReadTimeout: 400 #讀取逾時
#  MaxAutoRetries: 1 #重試目前執行個體的次數
#  MaxAutoRetriesNextServer: 1 #服務執行個體切換重試次數
#  ServerListRefreshInterval: 30000 #重新整理所服務清單間隔時間
           

設為全局配置隻需要把服務名去掉 使ribbon變成頂級配置即可,注意:NFLoadBalancerRuleClassName 在全局配置中無效,全局負載均衡規則配置如下 ⬇️

//針對所有服務配置路由規則,配置config
    @Bean
    public IRule iRule(){
        return new RandomRule();//具體的負載均衡規則類
    }
           

四、Hystrix的使用

1、添加依賴

雖然eureka依賴中也進行hystrix的引用,但是裡面的引用在SpringCloud新版本中是無效的,依賴引用如下⬇️

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

2、注解方式使用hystrix、降級回調

  • 我們之前的服務調用放到一個service中,建立 GoodsService類
@Service
public class GoodsService {

    @Autowired
    RestTemplate restTemplate;

    @HystrixCommand(fallbackMethod = "testFallback")//服務調用失敗後 執行降級回調方法,方法名不需要加括号
    public String test(){
        return restTemplate.getForObject("http://provider-goods-service/test",String.class);
    }

    //降級回調方法,傳回參數和調用參數需要一緻
    public String testFallback(){
        return "請求失敗,此次請求已記錄!";
    }

}
           

如果在@HystrixCommand修飾的方法中有多個服務調用的話,任何一個服務的調用發生異常或者産生異常都會觸發fallbackMethod的調用,如果觸發了某些特定的異常不想觸發fallback,則需要指定抛出的特定異常繼承HystrixBadRequestException,或者在方法内部對可能抛出的異常進行try掉

  • controller改動一下
@Autowired
    GoodsService goodsService;

    @GetMapping("/test")
    @ResponseBody
    public Object test(){
       String str = goodsService.test();
       return str;
    }
           
  • 啟動類加如下注解 開啟hystrix

3、hystrix熔斷器、資源隔離、其他常用配置項

  • 局部配置(方法1),作用于單個 @HystrixCommand 修飾的方法(不太推薦使用)
@HystrixCommand(
            fallbackMethod = "testFallback", // 請求失敗降級回調方法,值為方法名,不需要括号
            commandProperties ={// 針對單個方法的配置
                    @HystrixProperty(name = "circuitBreaker.enabled", value = "true"),//開啟熔斷器,可不加預設為true
                    @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50"),//請求錯誤超過50%,開啟熔斷器
                    @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),//一個周期(十秒)内超過10個請求才進行進行容錯率判斷
                    @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"),//開啟熔斷器後過10秒再嘗試通路 
                    ...
            })

           
  • 局部配置(方法2),基于hystrix commandKey,和配置檔案來配置(推薦使用)

    我們把之前@HystrixCommand 裡面的配置都去掉,改動結果如下

@HystrixCommand(
            commandKey = "testCommand",//為修飾的方法定義一個 commandKey,不設定預設取方法名為commandKey
            fallbackMethod = "testFallback"// 請求失敗降級回調方法,值為方法名,不需要括号
    )
           
hystrix:
  command:
    testCommand: #commandKey,配置作用于指定的commandKey

      # **********************==》》  常用的熔斷器配置  《《==**********************
      circuitBreaker:
        enabled: true #預設為true,可不用配置
        errorThresholdPercentage: 50 #一個監測周期(預設10s),請求失敗率超過50%開啟熔斷器
        requestVolumeThreshold: 10 #一個監測周期内,超過10個請求才進行進行容錯率判斷
        sleepWindowInMilliseconds: 10000 #開啟熔斷器後過10s再嘗試通路,預設5s
      metrics:
        rollingStats:
          timeInMilliseconds: 10000 #請求監測周期時長(機關 ms),預設10000
          numBuckets: 10 #每個監測周期,分為10個buckets,說白了就是 10秒的監測周期 分為十個buckets,每個buckets 1秒;每過一秒進行一次請求計算
                         #注意 timeInMilliseconds % numBuckets 必須為0 否則會觸發異常

      # **********************==》》  常用的資源隔離配置  《《==**********************
      execution:
        isolation:
          strategy: THREAD # THREAD:線程隔離, SEMAPHORE:信号量隔離;預設線程隔離
          thread:
            timeoutInMilliseconds: 400 #占用線程調用接口的逾時時間
            interruptOnTimeout: true #占用線程逾時 是否中斷線程的執行
          timeout:
            enabled: true #開啟逾時限制
          semaphore:
            maxConcurrentRequests: 20 #信号量隔離下才有效,最大的信号量值,可以了解為 最大支援的并發數
      fallback:
        isolation:
          semaphore:
            maxConcurrentRequests: 20 #降級回調方法允許的最大調用
           
  • 全局配置,在commandKey同級配置下 添加default的配置
hystrix:
  command:
    testCommand: #配置作用于指定的commandKey 
      # 配置項...
    default: #配置作用于全局,但是優先級會比指定commandKey 的低
      # 配置項...
           

4、總結

得益于springcloud的功勞才使得我們使用hystrix能夠這麼友善,當然hystrix的本質是不變的,對于一些大部分常用的功能配置都列出來了,可對實際的業務進行設定并測試;除了這些常用的配置 還有 線程池、請求合并 等配置

  • 線程池(ThreadPoolProperties) 一般不太建議随便設定,除非你對自己的實力有 足夠的自信,使用預設的配置在百分之八九十的業務場景中是完全沒問題的
  • 請求合并(CollapserProperties) 這個配置還是比較牛逼的,但是這一塊的話除非的業務場景是并發請求量是特别大的可能會用得到,而且都是利弊性的;不過後續也會結合源碼一起進行講解,這樣才能對其原理進行更深入的了解

有不足或者疑惑之處歡迎在下方留言~~

繼續閱讀