玩轉SpringCloud專題(十)-SpringCloud之Hystrix斷路器

1.Hystrix斷路器

1.1.分佈式系統面臨的問題

複雜分佈式體系結構中的應用程序有數十個依賴關係,每個依賴關係在某些時候將不可避免地失敗。
在這裏插入圖片描述

服務雪崩
多個微服務之間調用的時候,假設微服務A調用微服務B和微服務C,微服務B和微服務C又調用其它的微服務,這就是所謂的“扇出”。如果扇出的鏈路上某個微服務的調用響應時間過長或者不可用,對微服務A的調用就會佔用越來越多的系統資源,進而引起系統崩潰,所謂的“雪崩效應”.

示例:
在微服務架構中通常會有多個服務層調用,基礎服務的故障可能會導致級聯故障,進而造成整個系統不可用的情況,這種現象被稱爲服務雪崩效應。服務雪崩效應是一種因“服務提供者”的不可用導致“服務消費者”的不可用,並將不可用逐漸放大的過程。

什麼是災難性的雪崩效應?我們通過結構圖來說明,如下
在這裏插入圖片描述
正常情況下各個節點相互配置,完成用戶請求的處理工作
在這裏插入圖片描述
當某種請求增多,造成"服務T"故障的情況時,會延伸的造成"服務U"不可用,及繼續擴展,如下
在這裏插入圖片描述
最終造成下面這種所有服務不可用的情況
在這裏插入圖片描述
這就是我們講的災難性雪崩!

造成雪崩的原因可以歸納爲以下三個:

服務提供者不可用(硬件故障,程序Bug,緩存擊穿,用戶大量請求)
重試加大流量(用戶重試,代碼邏輯重試)
服務調用者不可用(同步等待造成的資源耗盡)

最終的結果就是一個服務不可用,導致一系列服務的不可用,而往往這種後果是無法預料的。

1.2.Hystrix概述

Hystrix [hɪst’rɪks]的中文含義是豪豬,因其背上長滿了刺而擁有自我保護能力。

Hystix,即熔斷器。類似保險絲角色!

主頁:https://github.com/Netflix/Hystrix/
在這裏插入圖片描述

Hystrix是一個用於處理分佈式系統的延遲和容錯的開源庫,在分佈式系統裏,許多依賴不可避免的會調用失敗,比如超時、異常等,Hystrix能夠保證在一個依賴出問題的情況下,不會導致整體服務失敗,避免級聯故障,以提高分佈式系統的彈性。

“斷路器”本身是一種開關裝置,當某個服務單元發生故障之後,通過斷路器的故障監控(類似熔斷保險絲),向調用方返回一個符合預期的、可處理的備選響應(FallBack),而不是長時間的等待或者拋出調用方無法處理的異常,這樣就保證了服務調用方的線程不會被長時間、不必要地佔用,從而避免了故障在分佈式系統中的蔓延,乃至雪崩。

在這裏插入圖片描述

1.3.熔斷器的工作機制:

在這裏插入圖片描述

正常工作的情況下,客戶端請求調用服務API接口:
在這裏插入圖片描述

當有服務出現異常時,直接進行失敗回滾,服務降級處理:
在這裏插入圖片描述

當服務繁忙時,如果服務出現異常,不是粗暴的直接報錯,而是返回一個友好的提示,雖然拒絕了用戶的訪問,但是會返回一個結果。

這就好比去買魚,平常超市買魚會額外贈送殺魚的服務。等到逢年過節,超時繁忙時,可能就不提供殺魚服務了,這就是服務的降級。

系統特別繁忙時,一些次要服務暫時中斷,優先保證主要服務的暢通,一切資源優先讓給主要服務來使用,在雙十一、618時,京東天貓都會採用這樣的策略。

2.Hystrix服務降級

2.1.場景介紹

先來看下正常服務調用的情況
在這裏插入圖片描述
當consumer調用provider服務出現問題的情況下:
在這裏插入圖片描述
此時我們對consumer的服務調用做降級處理
在這裏插入圖片描述

整體資源快不夠了,忍痛將某些服務先關掉,待渡過難關,再開啓回來。服務降級處理是在客戶端實現完成的,與服務端沒有關係。

Fallback相當於是降級操作。對於查詢操作,我們可以實現一個fallback方法,當請求後端服務出現異常的時候,可以使用fallback方法返回的值。 fallback方法的返回值一般是設置的默認值或者來自緩存。

2.2.引入依賴

首先在user-consumer中引入Hystix依賴:

<!--服務熔斷組件-->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

2.3.修改之前的Controller

在之前的Controller中添加熔斷機制:

@RequestMapping(value = "/get/{id}", method = RequestMethod.GET)
// 一旦調用服務方法失敗,會自動調用@HystrixCommand標註好的fallbackMethod調用類中的指定方法
@HystrixCommand(fallbackMethod = "processHystrix_Get")
public User get(@PathVariable("id") Long id) {
    User u = this.userService.get(id);
    return u;
}

//備選方案
public User processHystrix_Get(@PathVariable("id") Long id) {
    //模擬的備選數據,可以來源於緩存
    User u=new User();
    u.setId(110);
    u.setUsername("該ID:" + id + "沒有沒有對應的信息,null--@HystrixCommand");
    u.setNote("no this database in MySQL");
    return u;
}

2.4.修改主啓動類

修改consumer並添加新註解@EnableCircuitBreaker

@SpringBootApplication
@EnableDiscoveryClient // 開啓EurekaClient功能
@EnableFeignClients // 開啓Feign功能
@EnableCircuitBreaker//對hystrixR熔斷機制的支持
public class SpringcloudDemoConsumerApplication {

	public static void main(String[] args) {
		SpringApplication.run(SpringcloudDemoConsumerApplication.class, args);
	}
}

2.5. 服務熔斷測試

3個eureka先啓動
主啓動類SpringcloudDemoConsumerApplication

訪問測試
http://127.0.0.1:88/consumer/get/2
在這裏插入圖片描述
關閉服務提供者
在這裏插入圖片描述

3. 服務降級優化-徹底解耦

修改microservicecloud-api工程,根據已經有的DeptClientService接口新建一個實現FallbackFactory接口的類DeptClientServiceFallbackFactory

/**
 * @author bruceliu
 * @create 2019-08-04 15:11
 * @description
 */
@Component // 不要忘記添加
public class UserClientServiceFallbackFactory implements FallbackFactory<UserClientService> {


    @Override
    public UserClientService create(Throwable throwable) {
        return new UserClientService() {
            @Override
            public List<User> queryUsers() {
                return null;
            }

            @Override
            public User get(Long id) {
                User u=new User();
                u.setId(110);
                u.setUsername("該ID:\" + id + \"沒有沒有對應的信息,null--服務降級~~");
                u.setNote("no this database in MySQL----服務降級!!!");
                return u;
            }
        };
    }
}
  • 修改consumer工程,UserClientService接口在註解@FeignClient中添加fallbackFactory屬性值
/**
 * @author bruceliu
 * @create 2019-05-04 18:49
 * @description Feign客戶端
 */
@FeignClient(value = "SPRINGCLOUD-DEMO-SERVICE",fallbackFactory=UserClientServiceFallbackFactory.class)
public interface UserClientService {

    @RequestMapping("/all")
    public List<User> queryUsers();

    @RequestMapping("/get/{id}")
    public User get(@PathVariable("id") Long id);
}
  • 修改配置文件
# 開啓服務熔斷策略
feign.hystrix.enabled=true

3.1.測試

- 3個eureka先啓動
- 微服務提供者啓動
- 微服務消費者啓動

正常訪問測試:http://127.0.0.1:88/consumer/get/1
在這裏插入圖片描述
故意關閉微服務提供者
在這裏插入圖片描述
客戶端自己調用提示此時服務端provider已經down了,但是我們做了服務降級處理,讓客戶端在服務端不可用時也會獲得提示信息而不會掛起耗死服務器。

4. 服務熔斷

熔斷在降級的基礎之上

熔斷其實是在降級的基礎上引入了重試的機制。當某個時間內失敗的次數達到了多少次就會觸發熔斷機制。熔斷機制是應對雪崩效應的一種微服務鏈路保護機制。
在這裏插入圖片描述

斷路器很好理解,當Hystrix Command請求後端服務熔斷器在10秒內發現請求總數超過20,並且錯誤百分比超過50%,,斷路器會切換到開路狀態(Open)。這時所有請求會直接失敗而不會發送到後端服務。 斷路器保持在開路狀態一段時間後(默認5秒),自動切換到半開路狀態(HALF-OPEN)。這時會判斷下一次請求的返回情況, 如果請求成功,斷路器切回閉路狀態(CLOSED), 否則重新切換到開路狀態(OPEN)。 Hystrix的斷路器就像我們家庭電路中的保險絲,一旦後端服務不可用,斷路器會直接切斷請求鏈,避免發送大量無效請求影響系統吞吐量, 並且斷路器有自我檢測並恢復的能力。

熔斷器開關相互轉換的邏輯圖:
在這裏插入圖片描述
那麼當斷路器打開之後會發生什麼呢?當熔斷器在10秒內發現請求總數超過20,並且錯誤百分比超過50%,這個時候熔斷器打開。打開之後,再有請求調用的時候,將不會調用主邏輯,而是直接調用降級邏輯,返回fallback。通過斷路器,實現了自動地發現錯誤並將主邏輯切換爲降級邏輯,減少響應延遲的效果。

在斷路器打開之後,處理邏輯並沒有結束,我們的降級邏輯已經被成了主邏輯,那麼原來的主邏輯要如何恢復呢?對於這一問題,hystrix也爲我們實現了自動恢復功能。當斷路器打開,對主邏輯進行熔斷之後,hystrix會啓動一個休眠時間窗,在這個時間窗內,降級邏輯是臨時的成爲主邏輯,當休眠時間窗到期,斷路器將進入半開狀態,釋放一次請求到原來的主邏輯上,如果此次請求正常返回,那麼斷路器將繼續閉合,主邏輯恢復,如果這次請求依然有問題,斷路器繼續進入打開狀態,休眠時間窗重新計時。

通過上面的一系列機制,hystrix的斷路器實現了對依賴資源故障的端口、對降級策略的自動切換以及對主邏輯的自動恢復機制。這使得我們的微服務在依賴外部服務或資源的時候得到了非常好的保護,同時對於一些具備降級邏輯的業務需求可以實現自動化的切換與恢復,相比於設置開關由監控和運維來進行切換的傳統實現方式顯得更爲智能和高效。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章