每天學點SpringCloud(六):Hystrix使用

 

 

Hystrix是一個實現斷路器模式的庫。什麼是斷路器模式呢?就像我們家庭中的電閘一樣,如果有那一處出現意外,那麼電閘就會立刻跳閘來防止因爲這一處意外而引起更大的事故,直到我們確認處理完那一處意外後纔可以再打開電閘。而Hystrix的存在就是爲了預防程序中出現這種問題而導致程序不可用的情況。

 

 

 

比如說我們有三個微服務 A、B、C,其中A依賴於B,B依賴於C,如果這時候C出現了問題,那麼就導致B不可用,緊接着A也不可用,更有可能導致整個系統不可用。我們接下來就來看看如何利用Hystrix預防這種情況

 

 

創建項目

首先我們複製一份cloud-demo-consumer項目,改名爲cloud-demo-consumer-hystrix

引入Hystrix的依賴

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

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

 

application.xml不用變

spring:
  application:
    name: consumer-demo-hystrix
server:
  port: 8090
eureka:
  client:
    healthcheck:
      enabled: true
    serviceUrl:
      defaultZone: http://root:root@localhost:8761/eureka
  instance:
    prefer-ip-address: true

  application:
    name: consumer-demo-hystrix
server:
  port: 8090
eureka:
  client:
    healthcheck:
      enabled: true
    serviceUrl:
      defaultZone: http://root:root@localhost:8761/eureka
  instance:
    prefer-ip-address: true

 

CloudDemoConsumerApplication改名爲CloudDemoConsumerHystrixApplication,並且它的註解應該是

@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreake

@EnableEurekaClient
@EnableCircuitBreake

上方我們不認識的這個@EnableCircuitBreake註解就是表示開啓斷路器模式的註解

 

然後我們看一下controller

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/getUser/{id}")
    @HystrixCommand(fallbackMethod = "getUserFallback")
    public User getUser(@PathVariable Long id){
         return restTemplate.getForObject("http://provider-demo/user/getUser/"+id,User.class);
    }
    public User getUserFallback(Long id) {
        User user = new User();
        user.setName("王五");
        return user;
    }
}

@RequestMapping("/user")
public class UserController {

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/getUser/{id}")
    @HystrixCommand(fallbackMethod = "getUserFallback")
    public User getUser(@PathVariable Long id){
         return restTemplate.getForObject("http://provider-demo/user/getUser/"+id,User.class);
    }
    public User getUserFallback(Long id) {
        User user = new User();
        user.setName("王五");
        return user;
    }
}

它相比較於原先的controller僅僅是多了一個@HystrixCommand(fallbackMethod = "getUserFallback")註解和一個方法,這個註解呢就是指定Hystrix在此方法超時時調用的方法。

 

測試

首先啓動我們代表Eureka服務的項目,然後啓動cloud-demo-provider項目,緊接着啓動我們現在的項目。

 

項目啓動以後我們打開瀏覽器訪問localhost:8088/user/getUser/2的時候發現一切正常,網頁上返回了張三這個用戶。如果我們沒有引入Hystrix的時候如果這時候把服務提供者停掉的話在訪問會出現什麼情況呢,是不是會報錯,或者超時呀。

但是現在不一樣了,我們引入了Hystrix,所以我們現在停掉提供者訪問的時候會發現程序走了註解指定的fallbackMethod,也就是方法getUserFallBack,這個時候我們瀏覽器得到的結果是王五。

 

Hystrix默認的超時時間是1秒,也就是說它在等待服務提供者1秒後如果得不到結果的話就會認爲提供者掛了,緊接着調用fallbackMethod。

這個時間其實我們可以控制,只需要在yml文件中配置一個屬性就可以自定義這個時間

hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 1000 #1000毫秒
.command.default.execution.isolation.thread.timeoutInMilliseconds: 1000 #1000毫秒

 

 

Feign的支持

接下來我們看一下Feign是怎麼使用Hystrix,

這次我們改造cloud-demo-consumer-feign項目,項目名稱改爲cloud-demo-consumer-feign-hystrix,同樣向上述 方式一樣引入Hystrix的依賴,

接着 CloudDemoConsumerFeignApplication類名改爲 CloudDemoConsumerFeignHystrixApplication,同樣的加入@EnableCircuitBreaker註解

有一點不一樣的地方是我們需要在yml文件中配置一下來開啓Hystrix

feign.hystrix.enabled: true
.hystrix.enabled: true

 

這裏controller中需要改造的不再是指定單個方法,而是指定接口的實現類

@FeignClient(name = "provider-demo", fallback = HystrixClientFallback.class)
name = "provider-demo", fallback = HystrixClientFallback.class)

來看一下這個實現類

@Component
public class HystrixClientFallback implements UserFeignClient {
    @Override
    public User getUser(Long id) {
        User user = new User();
        user.setName("王五");
        return user;
    }
}


public class HystrixClientFallback implements UserFeignClient {
    @Override
    public User getUser(Long id) {
        User user = new User();
        user.setName("王五");
        return user;
    }
}

 

這樣的話如果接口中有多個方法的話我們就不必爲每一個方法取指定了。

 

現在我們已經解決了服務提供者掛掉的事情了,但是有點不好的是,我們現在還不能知道服務提供者到底是咋掛的,要是能捕獲到服務提供者

拋的異常就好了,其實Hystrix對這個是支持的,我們接下來看一下

 

fallbackFactory

 

UserFeignClient上方的註解需要變一下

@FeignClient(name = "provider-demo", fallbackFactory = HystrixClientFactory.class)
name = "provider-demo", fallbackFactory = HystrixClientFactory.class)

這次使用的是fallbackFactory這個屬性,我們看一下它指定的這個類又是怎麼實現的呢

 

@Component
public class HystrixClientFactory implements FallbackFactory<UserFeignClient> {

    private static final Logger LOGGER = LoggerFactory.getLogger(HystrixClientFactory.class);

    @Override
    public UserFeignClient create(Throwable cause) {
        HystrixClientFactory.LOGGER.info("the provider error is: {}", cause.getMessage());
        return new UserFeignClient() {
            @Override
            public User getUser(Long id) {
                User user = new User();
                user.setName("王五");
                return user;
            }
        };
    }
}

public class HystrixClientFactory implements FallbackFactory<UserFeignClient> {

    private static final Logger LOGGER = LoggerFactory.getLogger(HystrixClientFactory.class);

    @Override
    public UserFeignClient create(Throwable cause) {
        HystrixClientFactory.LOGGER.info("the provider error is: {}", cause.getMessage());
        return new UserFeignClient() {
            @Override
            public User getUser(Long id) {
                User user = new User();
                user.setName("王五");
                return user;
            }
        };
    }
}

 

我們可以看到,在這個create的工廠方法中,它的入參就是服務提供者的異常,得到了這個異常以後纔會去做實現。這樣是不是更加靈活了呢?

 

GitHub:https://github.com/2388386839/spring-cloud-demo

碼雲:https://gitee.com/zhixiang_blog/spring-cloud-demo

 

如果對您有所幫助,請記得幫忙點一個star哦

 

 

 

本文出自https://zhixiang.org.cn,轉載請保留。

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