Hystrix是springcloud中的断路器也叫熔断器组件。它的功能是,当对某个服务的调用在一定的时间内,有超过一定次数,并且失败率超过一定值,该服务的断路器会打开。Hystrix的目标就是能够在1个或多个模块出现问题时,系统依然可以稳定的运行
基本用法
创建项目,并选择依赖
image
添加如下配置,将Hystrix注册到Eureka上:
spring.application.name=hystrix
server.port=3000
eureka.client.service-url.defaultZone=http://localhost:1111/eureka
在启动类添加@EnableCircuitBreaker开启断路器,或者直接添加@SpringCloudApplication注解,代替@SpringBootApplication、@EnableCircuitBreaker两个注解,并添加RestTemplate的实例
@SpringCloudApplication
public class HystrixApplication {
@Bean
@LoadBalanced
RestTemplate restTemplate(){
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(HystrixApplication.class, args);
}
}
创建一个Service
@Service
public class HelloService {
@Autowired
RestTemplate restTemplate;
/*
*再此方法中,发起一个远程调用,调用provider中的/hello接口
* 但这个调用可能会失败
* 在这个方法上添加HystrixCommand注解,配置fallbackMethod
* 这个属性表示方法调用失败时候的临时替代方法
*
* */
@HystrixCommand(fallbackMethod = "error")
public String hello(){
return restTemplate.getForObject("http://provider/hello",String.class);
}
/*
* 这个方法名要和fallbackMethod一致
* 返回值也要和对应方法一致
* */
public String error(){
return "error";
}
}
提供接口调用Service中的方法
@RestController
public class HelloController {
@Autowired
HelloService helloService;
@GetMapping("/hello")
public String hello(){
return helloService.hello();
}
}
接下来进行测试,首先打包provider,分别在1113和1114两个端口启动,启动后使用consumer中的hello2接口调用,由于该接口带有负载均衡功能,可以看到,两个接口都能被访问
image image
关闭1113端口后,发现不会再定位到1113端口,仅1114端口可以正常访问。但是Eureka收到服务下线通知之前,访问hello2接口仍然会定位到1113端口,这是系统就会报错。而使用Hystrix就可以在这段时间内,不让用户看到错误界面。
重新启动两个provider服务,启动Hystrix,在注册中心可以看到,所有服务准备就绪
image
访问Hystrix中的hello接口,可以看到两个provider都能正常被访问,接下来关闭一个provider服务,刷新页面
image
image
可以看到本应定位到1113端口的界面返回值变成了我们在Hystrix中设置的erro,而1114端口仍然可以正常被访问。在Eureka接到下线通知后,仅访问1114端口。这个过程就被称为服务降级。
实现异步调用
在HelloService中定义方法,返回值为Future<String>
@HystrixCommand(fallbackMethod = "error")
public Future<String> hello2(){
return new AsyncResult<String>() {
@Override
public String invoke() {
return restTemplate.getForObject("http://provider/hello",String.class);
}
};
}
这里AsyncResult需要导入的包是com.netflix.hystrix.contrib.javanica.command.AsyncResult
在controller中调用这个方法,即可实现Hystrix的异步调用
@GetMapping("/hello3")
public void hello3(){
Future<String> hello2 = helloService.hello2();
try {
String s = hello2.get();
System.out.println(s);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
异常处理
若想要在服务降级同时捕获发生的异常,可以在fallbackMethod返回的方法中传入Throwable参数捕获异常,这样在服务降级时就可以知道异常的详细信息并及时处理:
public String error(Throwable e){
return "error"+e.getMessage();
}
还可以在 @HystrixCommand注解中添加IgnoreException=xxx属性,告诉Hystrix当发生xxx异常时知抛出异常而不进行服务降级。
请求缓存
在Hystrix请求方法中调用@CacheResult注解,该注解表示方法请求结果会被缓存,默认情况下,缓存的key为方法参数,value为方法返回值
@HystrixCommand(fallbackMethod = "error2")
@CacheResult//该注解表示方法请求结果会被缓存,默认情况下,缓存的key为方法参数,value为方法返回值
public String hello3(String name){
return restTemplate.getForObject("http://provider/hello2?name={1}",String.class,name);
}
public String error2(String name){
return "error:withCache";
}
配置完成后,缓存并不会马上生效,需要初始化HystrixRequestContext,初始化完成后,缓存生效,HystrixRequestContext关闭,缓存失效。
@GetMapping("/hello4")
public void hello4(){
HystrixRequestContext ctx = HystrixRequestContext.initializeContext();
String name = helloService.hello3("zby");
ctx.close();
}
ctx.close()执行之前,缓存有效,之后缓存失效。在这个接口中访问一次hello4接口调用了两次hello3方法,但provider只会被调用一次(第二次使用缓存)
修改provider中的hello2接口,用于检测缓存是否生效
@GetMapping("/hello2")
public String hello2(String name){
System.out.println(new Date()+">>>"+name);
return "hello "+name;
}
可以看到只打印出了一条消息,说明provider只被调用了一次
image
其他关于缓存注解:
- @CacheKey:加在参数前,表示以某个key作为缓存
- @CacheRemove:使用时要使用commandKey属性,commandKey是缓存方法的名字,表示删除指定方法的缓存,
请求合并
通过@HystrixCollapser注解可以实现请求的合并,在注解中指定批处理方法即可
@HystrixCollapser(batchMethod = "getUsersByIds",collapserProperties = {@HystrixProperty(name = "timerDelayInMilliseconds",value = "200")})
public Future<User> getUserById(Integer id){
return null;
}
网友评论