首先记录一下Hystrix的底层是如何实现的?今天想了一下其实也不难,整体逻辑就是利用Aop实现的。源码:在HystrixCommandAspect
中,先看看切入点
@Pointcut("@annotation(com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand)")
public void hystrixCommandAnnotationPointcut() {
}
@Pointcut("@annotation(com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser)")
public void hystrixCollapserAnnotationPointcut() {
}
//设置了两个切点都是利用自定义注解切入的
然后接着执行methodsAnnotatedWithHystrixCommand
方法
public Object methodsAnnotatedWithHystrixCommand(ProceedingJoinPoint joinPoint) throws Throwable {
…代码省略…
Object result;
if (!metaHolder.isObservable()) {
result = CommandExecutor.execute(invokable, executionType, metaHolder);//当不可见,就会去执行fallbackMethod中的方法
} else {
result = this.executeObservable(invokable, executionType, metaHolder);
}
return result;
…代码省略…
}
最后会执行到HystrixCommand
public R execute() {
try {
return this.queue().get();//也就是这句代码取得了fallbackMethod返回的值
} catch (Exception var2) {
throw Exceptions.sneakyThrow(this.decomposeException(var2));
}
}
开篇
在分布式系统中,我们可能会有服务A调用服务B然后服务B再调用服务C的业务。那么如果服务C宕机了或者阻塞了,服务B同时也会阻塞,服务A也会阻塞。如果对此不做任务处理的话,那么服务ABC会全部宕机,这就是服务雪崩。
而hystrix的熔断、降级就是对付雪崩的有效处理方式。本篇就使用hystrix来处理这一问题…… 废话不多说,开始实战吧
Hystrix(服务降级、熔断)
在进行这一步的之前,先要将Spring Cloud搭建起来,如果还不知道如何搭建可以看看上一篇:
Spring Cloud 实战(一)以eureka作为服务注册中心
配置pom
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
2022年10月5日更新
由于spring2.x.x>=2.0.0已经去掉了org/springframework/boot/autoconfigure/web/ServerPropertiesAutoConfiguration.class
所以如果导入的Jar包需要依赖这个类就会报错
解决这个问题只需要加入版本号即可
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.2.9.RELEASE</version>
<type>pom</type>
</dependency>
配置好pom后,我们还需要在Application.java中增加注解@EnableHystrix
用于启用Hystrix,否则Hystrix是不生效的。
降级、熔断都是使用注解@HystrixCommand
来对某个方法进行标注,其中不同的点在于降级的注解需要一个fallbackMethod而熔断不用。
不过要注意的是,我们定义的fallbackMethod方法参数需要与@HystrixCommand标注的方法参数一致,否则调用就会报错。
进入正题……
服务降级
当服务B调用服务C时,时间太长阻塞了或者服务C宕机了,我们应该友好的给用户提示一些信息,这也是服务降级的作用。
代码:
@Autowired
RestTemplate restTemplate;
@RequestMapping("/do/{userId}")
@HystrixCommand(
fallbackMethod = "fallbackMethod"
)
public String doDriver(@PathVariable String userId){
try{
Thread.sleep(2900);
}catch(Exception e){
e.printStackTrace();
}
String url = "http://onlinecar-driver/driver/do/"+userId;
return restTemplate.getForObject(url,String.class);
}
public String fallbackMethod(String userId){
return "当前业务繁忙,请稍后重试……";
}
上面代码的意思是如果调用doDriver
超时了或者onlinecar-driver
宕机了,就会返回当前业务繁忙,请稍后重试……
。使用sleep就是为了模拟服务超时的背景。Hystrix默认的超时时间是1秒。如何配置,最后会给出。
服务熔断
熔断就会比降级的处理方式更加暴力。如果服务B调用服务C是阻塞了或者服务C宕机了,会直接将服务B于服务C之间的链接断掉,不会返回信息。
看代码:
@Autowired
RestTemplate restTemplate;
@RequestMapping("/do/{userId}")
@HystrixCommand(
commandProperties = {
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="2000")
}
)
public String doDriver(@PathVariable String userId){
try{
Thread.sleep(2900);
}catch(Exception e){
e.printStackTrace();
}
String url = "http://onlinecar-driver/driver/do/"+userId;
return restTemplate.getForObject(url,String.class);
}
上面代码的意思是如果调用doDriver
超时了或者onlinecar-driver
宕机了,就会直接报错。
配置Hystrix超时时间
一、配置全局默认超时时间
在properties中配置
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=3000
二、使用commandKey
在@HystrixCommand中增加commandKey
@HystrixCommand(
fallbackMethod="fallbackMethod"
,commandKey = "driverKey"
)
然后再在properties中配置
hystrix.command.driverKey.execution.isolation.thread.timeoutInMilliseconds=3000
三、使用commandProperties
在@HystrixCommand中增加commandProperties
@HystrixCommand(
fallbackMethod = "fallbackMethod",
commandProperties = {
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="2000")
}
)
以上就是使用Hystrix的简单实战啦