赞
踩
Hystrix的功能主要有缓存、熔断(断路器)、隔离(线程池或信号量)、限流(线程池或信号量)、降级处理、请求合并等。
缓存:避免频繁请求资源
熔断:当失败率过高时进行降级处理
隔离:服务隔离,避免A服务的失败影响无关的B服务调用
限流:防止大量的请求冲垮服务,当请求大于阈值时降级处理
降级处理:当服务出现异常时返回友好的处理结果
请求合并:多个单次请求合并成一个请求,减少网络资源等的消耗
下图虽然拙劣,但大概能表达这些功能
接下来通过一个HelloWorld演示Hystrix的使用,然后再按图索骥逐步分析Hystrix的源码
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> <version>2.2.10.RELEASE</version> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
@SpringBootApplication
@EnableCircuitBreaker // (1)声明式开启Hystrix
public class HystrixApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixApplication.class, args);
}
}
public interface CommandService {
public String command(String command, long delay);
}
@Service public class CommandServiceImpl implements CommandService { @Override // (2)Hystrix命令声明 @HystrixCommand( // 设置超时时间 commandProperties = { @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "500")}, // 超时后的降级处理 fallbackMethod = "fallbackMethod") public String command(String command, long delay) { try { Thread.sleep(delay); } catch (InterruptedException e) { e.printStackTrace(); } return "消息" + command + ",正常: " + delay; } public String fallbackMethod(String command, long delay) { return "消息" + command + ",超时了: " + delay; } }
@RestController
public class HystrixController {
@Autowired
CommandService commandService;
@GetMapping("/commands/{id}")
public String getCommand(@PathVariable("id")String id) throws ClassNotFoundException {
// 随机生成时延
long delay = (long) (Math.random() * 1000);
return commandService.command(id, delay);
}
}
代码编写好后启动,在浏览器输入http://localhost:8080/commands/11,结果会有两种,delay小于500ms则正常显示,大于500ms则显示超时。这个简单的例子展示了Hystrix的服务降级功能,那么它是怎么做到的呢?
从例子的代码中我们看到(1)和(2)处用到了Hystrix的代码,那么这两个annotation就成为了研究Hystrix源码的入口。
@Deprecated
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(EnableCircuitBreakerImportSelector.class)
public @interface EnableCircuitBreaker {
}
@EnableCircuitBreaker中什么代码都没有,它只是用到了@Import(EnableCircuitBreakerImportSelector.class),我们继续分析EnableCircuitBreakerImportSelector
@Order(Ordered.LOWEST_PRECEDENCE - 100)
public class EnableCircuitBreakerImportSelector extends SpringFactoryImportSelector<EnableCircuitBreaker> {
@Override
protected boolean isEnabled() {
return getEnvironment().getProperty("spring.cloud.circuit.breaker.enabled", Boolean.class, Boolean.TRUE);
}
}
从EnableCircuitBreakerImportSelector的代码中我们看到它设置了spring.cloud.circuit.breaker.enabled
的值,也就是开启了Hystrix断路器。那么我们就能得出了结论:@EnableCircuitBreaker
的功能就是开启Hystrix功能。如果没有这个注解,后面的@HystrixCommand是不起作用的
对于注解一般是使用aspect拦截嵌入功能,而@HystrixCommand
也是这样工作的。真正的逻辑是在HystrixCommandAspect
类里,我们看下HystrixCommandAspect的源码,为了方便我们把琐碎的代码去掉
// 拦截@HystrixCommand @Pointcut("@annotation(com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand)") public void hystrixCommandAnnotationPointcut() { } // 拦截@HystrixCollapser @Pointcut("@annotation(com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser)") public void hystrixCollapserAnnotationPointcut() { } @Around("hystrixCommandAnnotationPointcut() || hystrixCollapserAnnotationPointcut()") public Object methodsAnnotatedWithHystrixCommand(final ProceedingJoinPoint joinPoint) throws Throwable { Method method = getMethodFromTarget(joinPoint); ...... // 1、根据注解获取MetaHolderFactory【3】 MetaHolderFactory metaHolderFactory = META_HOLDER_FACTORY_MAP.get(HystrixPointcutType.of(method)); // /2、创建MetaHolder,存储被拦截方法的所有信息,包括方法本身以及@HystrixCommand的信息【4】 MetaHolder metaHolder = metaHolderFactory.create(joinPoint); // /3、创建Hystrix命令【5】 HystrixInvokable invokable = HystrixCommandFactory.getInstance().create(metaHolder); ...... Object result; ...... // /4、执行命令【6】 if (!metaHolder.isObservable()) { result = CommandExecutor.execute(invokable, executionType, metaHolder); } else { result = executeObservable(invokable, executionType, metaHolder); } ...... return result; }
@HystrixCommand
的工作流程大致如下
那么我们按照这四个步骤继续往下探究Hystrix的源码
未完待续
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。