1. 程式人生 > >SpringCloud(五):斷路器(Hystrix)

SpringCloud(五):斷路器(Hystrix)

一、簡介 http://projects.spring.io/spring-cloud/spring-cloud.html#_circuit_breaker_hystrix_clients

Netflix開源了Hystrix元件,實現了斷路器模式,SpringCloud對這一元件進行了整合。 在微服務架構中,一個請求需要呼叫多個服務是非常常見的。

hystrix主要是用來防止服務雪崩效應的。

服務雪崩效應:是一種因服務提供者的不可用導致服務呼叫者的不可用,並將不可用逐漸放大的過程。

舉例:A為服務提供者, B為A的服務呼叫者, C和D是B的服務呼叫者. 當A的不可用,引起B的不可用,並將不可用逐漸放大C和D時, 服務雪崩就形成了。

如圖一個API可能同時呼叫多個微服務。

較低級別的服務中的服務故障可能導致服務級聯故障。當對特定服務的呼叫達到一定閾值時(Hystrix中的預設值為5秒內的20次故障),斷路器開啟。

斷路開啟後,回退可以是另一個Hystrix保護的呼叫,靜態資料或一個正常的空值。

二、Ribbon+Hystrix

依賴:

        <dependency>             <groupId>org.springframework.boot</groupId>             <artifactId>spring-boot-starter-web</artifactId>         </dependency>         <dependency>             <groupId>org.springframework.cloud</groupId>             <artifactId>spring-cloud-starter-eureka</artifactId>         </dependency>         <dependency>             <groupId>org.springframework.cloud</groupId>             <artifactId>spring-cloud-starter-ribbon</artifactId>         </dependency>         <dependency>             <groupId>org.springframework.cloud</groupId>             <artifactId>spring-cloud-starter-hystrix</artifactId>         </dependency> application.properties

spring.application.name=hello-consumer-ribbon-hystrix server.port=8041

eureka.client.serviceUrl.defaultZone=http://localhost:8001/eureka/ HelloService

package cn.saytime.service;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate;

@Service public class HelloService {

    @Autowired     private RestTemplate restTemplate;

    @HystrixCommand(fallbackMethod = "fallback")     public String hello (String name) {         return restTemplate.getForEntity("http://HELLO-SERVICE/hello?name=" + name, String.class).getBody();     }

    public String fallback (String name) {         return "hello, hystrix       === fail name:" + name;     }

} application

package cn.saytime;

import cn.saytime.service.HelloService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.cloud.netflix.hystrix.EnableHystrix; import org.springframework.context.annotation.Bean; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate;

@SpringBootApplication @EnableDiscoveryClient @EnableHystrix @RestController public class HelloConsumerRibbonHystrixApplication {

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

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

    @Autowired     private HelloService helloService;

    @RequestMapping("hello")     public String hello (String name) {         return helloService.hello(name);     }

} 測試:

啟動eureka-server:8001, hello-service:8012,8002,hello-consumer-ribbon-hystrix:8041

訪問:http://localhost:8041/hello?name=ribbon_hystrix

hello, ribbon_hystrix 訪問正常,接下來我們把hello-service服務停了,再次訪問:

hello, hystrix === fail name:ribbon_hystrix 成功觸發熔斷。

然後我們再次啟動hello-service服務,然後訪問:

hello, ribbon_hystrix 沒有觸發熔斷,正常。

同樣我們測試訪問超時觸發熔斷的情況,我們在hello-service介面加上執行緒等待1s

    @RequestMapping("hello")     public String hello (String name) throws InterruptedException {         Thread.sleep(1000);         System.out.println("hello, " + name);         return "hello, " + name;     } 訪問,發現同樣觸發熔斷,因為hystrix預設超時1s觸發熔斷,我們可以通過修改屬性來改變超時時間。

這裡我們把超時時間修改為2s

    @HystrixCommand(fallbackMethod = "fallback", commandProperties = {             @HystrixProperty(name= "execution.isolation.thread.timeoutInMilliseconds", value="2000")     })     public String hello (String name) {         return restTemplate.getForEntity("http://HELLO-SERVICE/hello?name=" + name, String.class).getBody();     } 再次訪問,發現沒有觸發熔斷。

三、Feign With Hystrix Feign預設是自帶Hystrix的,所以依賴Jar的時候無需再依賴hystrix

pom.xml

        <dependency>             <groupId>org.springframework.boot</groupId>             <artifactId>spring-boot-starter-web</artifactId>         </dependency>         <dependency>             <groupId>org.springframework.cloud</groupId>             <artifactId>spring-cloud-starter-eureka-server</artifactId>         </dependency>         <dependency>             <groupId>org.springframework.cloud</groupId>             <artifactId>spring-cloud-starter-feign</artifactId>         </dependency> application.properties

spring.application.name=hello-consumer-feign-hystrix server.port=8051

eureka.client.serviceUrl.defaultZone=http://localhost:8001/eureka/

## 開啟hystrix feign.hystrix.enabled=true

## hystrix熔斷觸發預設超時時間 hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=2000 HelloService

package cn.saytime.service;

import org.springframework.cloud.netflix.feign.FeignClient; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam;

@FeignClient(value = "hello-service", fallback = HelloServiceFallBack.class) public interface HelloService {

    @RequestMapping("hello")     String hello(@RequestParam(value = "name") String name) ; } 熔斷觸發類HelloServiceFallBack

package cn.saytime.service;

import org.springframework.stereotype.Component;

@Component public class HelloServiceFallBack implements HelloService{

    @Override     public String hello(String name) {         return "hello, hystrix      == fail name : " + name;     } } 啟動類

package cn.saytime;

import cn.saytime.service.HelloService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.netflix.feign.EnableFeignClients; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication @EnableDiscoveryClient @EnableFeignClients @RestController public class HelloConsumerFeignHystrixApplication {

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

    @Autowired     private HelloService helloService;

    @RequestMapping("hello")     public String hello(String name){         return helloService.hello(name);     } } 測試:

啟動eureka-server:8001, hello-service:8011,hello-consumer-feign-hystrix:8051

訪問:http://localhost:8051/hello?name=feign_hystrix

hello, feign_hystrix 訪問成功

接下來關閉hello-service服務,再次訪問:

hello, hystrix == fail name : feign_hystrix 成功觸發熔斷

將hello-service服務重新啟動,訪問正常,沒有觸發熔斷。

將hello-service服務介面加上執行緒等待3s,重啟hello-service服務,再次呼叫

同樣成功觸發熔斷

修改application.properties裡面熔斷超時時間為4s,再次呼叫,沒有觸發熔斷。

四、Hystrix Dashboard (Hystrix 儀表盤) ribbon-hystrix 與 feign-hystrix 兩個專案的pom檔案都新增以下依賴

        <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> 啟動類都加上如下註解:

@EnableHystrixDashboard 然後訪問

http://localhost:8041/hystrix  http://localhost:8051/hystrix  

輸入連結:http://localhost:8041/hystrix.stream

同理,如果是feign-hystrix專案,輸入 http://localhost:8051/hystrix.stream

點選Monitor Stream

然後我們訪問一下 http://localhost:8041/hello?name=ribbon_hystrix

會出現如下監控介面:  

具體監控介面內容情況,就不詳細描述了