This article is more than one year old. Older articles may contain outdated content. Check that the information in the page has not become incorrect since its publication.
Hystrix is designed to provide more robust fault tolerance by controlling the nodes that access remote systems, services, and third-party libraries, thus providing stronger resilience against latency and failures. Hystrix includes thread and signal isolation, fallback mechanisms, circuit breaker functionality, request caching, request bundling, as well as monitoring and configuration.
Dubbo is an open-source Java RPC framework from Alibaba and is currently the most popular in China.
This article describes how to combine Dubbo and Hystrix in a Spring application.
Demo address: https://github.com/dubbo/dubbo-samples/tree/master/4-governance/dubbo-samples-spring-boot-hystrix
For those unfamiliar with integrating Dubbo into Spring Boot applications, you can directly generate a Dubbo + Spring Boot project here: http://start.dubbo.io/
Spring Boot provides official integration with Hystrix. Simply add the dependency in your pom.xml:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>1.4.4.RELEASE</version>
</dependency>
Then add @EnableHystrix
on the Application class to enable the Hystrix starter:
@SpringBootApplication
@EnableHystrix
public class ProviderApplication {
Add @HystrixCommand
configuration on the Dubbo Provider, so the calls will go through the Hystrix proxy.
@Service(version = "1.0.0")
public class HelloServiceImpl implements HelloService {
@HystrixCommand(commandProperties = {
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2000") })
@Override
public String sayHello(String name) {
// System.out.println("async provider received: " + name);
// return "annotation: hello, " + name;
throw new RuntimeException("Exception to show hystrix enabled.");
}
}
For the Consumer side, an additional method call can be added, with @HystrixCommand
configured on the method. When a call fails, it will fall back to the fallbackMethod = "reliable"
.
@Reference(version = "1.0.0")
private HelloService demoService;
@HystrixCommand(fallbackMethod = "reliable")
public String doSayHello(String name) {
return demoService.sayHello(name);
}
public String reliable(String name) {
return "hystrix fallback value";
}
With the above configuration, the integration of Dubbo + Hystrix in Spring Boot is easily completed.
Demo address: https://github.com/dubbo/dubbo-samples/tree/master/4-governance/dubbo-samples-spring-hystrix
The configuration of a traditional Spring annotation application is also straightforward, differing from Spring Boot applications in that:
@EnableAspectJAutoProxy
HystrixCommandAspect
Bean via @Configuration
. @Configuration
@EnableDubbo(scanBasePackages = "com.alibaba.dubbo.samples.annotation.action")
@PropertySource("classpath:/spring/dubbo-consumer.properties")
@ComponentScan(value = {"com.alibaba.dubbo.samples.annotation.action"})
@EnableAspectJAutoProxy
static public class ConsumerConfiguration {
@Bean
public HystrixCommandAspect hystrixCommandAspect() {
return new HystrixCommandAspect();
}
}
In the example above, it can be seen that Hystrix integrates with Spring through Spring AOP. Let’s briefly analyze the implementation.
@Aspect
public class 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() {
}
@Around("hystrixCommandAnnotationPointcut() || hystrixCollapserAnnotationPointcut()")
public Object methodsAnnotatedWithHystrixCommand(final ProceedingJoinPoint joinPoint) throws Throwable {
Method method = getMethodFromTarget(joinPoint);
Validate.notNull(method, "failed to get method from joinPoint: %s", joinPoint);
if (method.isAnnotationPresent(HystrixCommand.class) && method.isAnnotationPresent(HystrixCollapser.class)) {
throw new IllegalStateException("method cannot be annotated with HystrixCommand and HystrixCollapser " +
"annotations at the same time");
}
MetaHolderFactory metaHolderFactory = META_HOLDER_FACTORY_MAP.get(HystrixPointcutType.of(method));
MetaHolder metaHolder = metaHolderFactory.create(joinPoint);
HystrixInvokable invokable = HystrixCommandFactory.getInstance().create(metaHolder);
ExecutionType executionType = metaHolder.isCollapserAnnotationPresent() ?
metaHolder.getCollapserExecutionType() : metaHolder.getExecutionType();
Object result;
try {
if (!metaHolder.isObservable()) {
result = CommandExecutor.execute(invokable, executionType, metaHolder);
} else {
result = executeObservable(invokable, executionType, metaHolder);
}
} catch (HystrixBadRequestException e) {
throw e.getCause() != null ? e.getCause() : e;
} catch (HystrixRuntimeException e) {
throw hystrixRuntimeExceptionToThrowable(metaHolder, e);
}
return result;
}
HystrixCommandAspect
defines two AspectJ Pointcuts for the annotations: @HystrixCommand
, @HystrixCollapser
. All Spring beans with these annotations will undergo AOP processing.@Around
AOP processing function, it can be seen that Hystrix will create a HystrixInvokable
, which is then executed through CommandExecutor
.@EnableHystrix
introduces @EnableCircuitBreaker
, and @EnableCircuitBreaker
introduces EnableCircuitBreakerImportSelector
.
@EnableCircuitBreaker
public @interface EnableHystrix {
}
@Import(EnableCircuitBreakerImportSelector.class)
public @interface EnableCircuitBreaker {
}
EnableCircuitBreakerImportSelector
extends SpringFactoryImportSelector<EnableCircuitBreaker>
, allowing Spring to load the configuration declared by EnableCircuitBreaker
in META-INF/spring.factories
.
In META-INF/spring.factories
, the following configuration can be found, which introduces HystrixCircuitBreakerConfiguration
.
org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker=\
org.springframework.cloud.netflix.hystrix.HystrixCircuitBreakerConfiguration
In HystrixCircuitBreakerConfiguration
, the creation of HystrixCommandAspect
can be found.
@Configuration
public class HystrixCircuitBreakerConfiguration {
@Bean
public HystrixCommandAspect hystrixCommandAspect() {
return new HystrixCommandAspect();
}
It can be seen that spring-cloud-starter-netflix-hystrix
effectively creates HystrixCommandAspect
to integrate Hystrix.
Additionally, spring-cloud-starter-netflix-hystrix
also includes metrics, health, dashboard, and other integrations.
@Service
is a Spring bean, and @HystrixCommand
can be configured directly on it.@Reference
, a simple Spring method wrapper can be added and @HystrixCommand
configured.HystrixCommandAspect
to integrate with Spring AOP, and Spring methods configured with @HystrixCommand
and @HystrixCollapser
will be processed by Hystrix.