天天看點

SpringCloud學習Day03

注:本教程均是參考"程式猿DD"大佬的SpringCloud教程:http://blog.didispace.com/spring-cloud-learning/實踐結合自己的了解和總結編寫

服務降級、線程隔離

相較于傳統架構,微服務架構,由于每個服務在不同的程序中運作,服務間通過http協定進行調用,如果依賴服務出現故障或者阻塞将會導緻對外的服務延遲,如果此時請求數量繼續增加,可能會出現因等待故障而形成請求積壓、線程資源無法釋放,導緻服務癱瘓。Spring Cloud Hystrix實作了線程隔離、斷路器、服務降級、服務熔斷等功能,給我們的微服務架構添加了可靠性的保障。

服務降級機制

1.添加pom.xml

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

2.在啟動類上添加注解@EnableCircuitBreaker

@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
public class EurekaRibbonHystrixConsumerApplication {

    public static void main(String[] args) {
        new SpringApplicationBuilder(EurekaRibbonHystrixConsumerApplication.class).web(true).run(args);
    }

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}
           

其實啟動類上的三個注解等同于@SpringCloudApplication注解

3.改造Controller

@RestController
public class DcController {

    @Resource
    private ConsumerService consumerService;

    @GetMapping("/consumer")
    public String dc() {
        return consumerService.consumer();
    }
}
           

4.添加ConsumerService

@Service
public class ConsumerService {

    @Autowired
    private RestTemplate restTemplate;

    @HystrixCommand(fallbackMethod = "fallback")
    public String consumer() {
        return restTemplate.getForObject("http://eureka-client/dc", String.class);
    }

    public String fallback() {
        return "fallback";
    }
}
           

5.對eureka-client對應的服務方法添加Thread.sleep(5000);啟動服務進行測試,然後通路GET http://ip:port/consumer,此時傳回結果為fallback。這是由于服務消費方出發了請求逾時異常,服務消費方通過HystrixCommand注解指定的降級邏輯執行。這樣便可以對自身服務提供了保護。

線程隔離:

我對線程池隔離的了解:

比如a服務的接口a-interface需要調用b,c服務b-interface,c-interface實作自身的業務;在沒有做線程隔離的情況下,每次調用a-interface接口a服務的tomcat都會建立一個線程執去調用b-interface,c-interface,如果調用b-interface或者c-interface阻塞了(或者接口延遲高),這個時候又有大量的a-interface調用,,那麼容器的線程數量會持續增加導緻CPU耗盡導緻整個服務不可用,Hystrix通過指令模式将每個類型的請求封裝為一個command請求,b-interface封裝為b-interface-command,c-interface封裝為b-interface-command,每個類型的command對應一個線程池,建立好的線程池是被放入到ConcurrentHashMap中。執行依賴代碼的線程與請求線程分離,請求線程可以自由控制離開時間,即異步。Hystrix是結合RxJava來實作的異步程式設計。通過設定線程池大小來控制并發通路量,當線程飽和的時候可以拒絕服務,防止依賴問題擴散。

通過對依賴服務的線程池隔離實作,有以下優勢:

[1]:應用程式會被完全保護起來,即使依賴的一個服務的線程池滿了,也不會影響到應用程式的其他部分。

[2]:我們給應用程式引入一個新的風險較低的用戶端lib的時候,如果發生問題,也是在本lib中,并不會影響到其他内容,是以我們可以大膽的引入新lib庫。

[3]:當依賴的一個失敗的服務恢複正常時,應用程式會立即恢複正常的性能。

[4]:如果我們的應用程式一些參數配置錯誤了,線程池的運作狀況将會很快顯示出來,比如延遲、逾時、拒絕等。同時可以通過動态屬性實時執行來處理糾正錯誤的參數配置。

[5]:如果服務的性能有變化,進而需要調整,比如增加或者減少逾時時間,更改重試次數,就可以通過線程池名額動态屬性修改,而且不會影響到其他調用請求。

[6]:除了隔離優勢外,hystrix擁有專門的線程池可提供内置的并發功能,使得可以在同步調用之上建構異步的外觀模式,這樣就可以很友善的做異步程式設計(Hystrix引入了Rxjava異步架構)。

線程隔離的缺點:

[1]:線程池的主要缺點就是它增加了計算的開銷,每個業務請求(被包裝成指令)在執行的時候,會涉及到請求排隊,排程和上下文切換。不過Netflix公司内部認為線程隔離開銷足夠小,不會産生重大的成本或性能的影響。

The Netflix API processes 10+ billion Hystrix Command executions per day using thread isolation. Each API instance has 40+ thread-pools with 5–20 threads in each (most are set to 10).

Netflix API每天使用線程隔離處理10億次Hystrix Command執行。 每個API執行個體都有40多個線程池,每個線程池中有5-20個線程(大多數設定為10個)。

信号量機制

信号量的資源隔離隻是起到一個開關的作用,比如,服務 A 的信号量大小為 10,那麼就是說它同時隻允許有 10 個 tomcat 線程來通路服務 A,其它的請求都會被拒絕,進而達到資源隔離和限流保護的作用。

适用場景:

線程池技術,适合絕大多數場景,比如說我們對依賴服務的網絡請求的調用和通路、需要對調用的 timeout 進行控制(捕捉 timeout 逾時異常)。

信号量技術,适合說你的通路不是對外部依賴的通路,而是對内部的一些比較複雜的業務邏輯的通路,并且系統内部的代碼,其實不涉及任何的網絡請求,那麼隻要做信号量的普通限流就可以了,因為不需要去捕獲 timeout 類似的問題。

參考:https://www.jianshu.com/p/fcbc5de24153

代碼:https://github.com/SpringStudent/study-spring-cloud

繼續閱讀