版權聲明:本文為部落客原創文章,未經部落客允許不得轉載。部落格源位址為zhixiang.org.cn https://blog.csdn.net/myFirstCN/article/details/81048280
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,轉載請保留。