Circuit Breaker, Fallback and Load Balancing with Apache Camel
Apache Camel has just released a new version of their framework – 2.19. In one of my previous articles on DZone, I described details about microservices support which was released in the Camel 2.18 version. There are some new features in ServiceCall
EIP component, which is responsible for microservice calls. You can see example source code which is based on the sample from my article on DZone. It is available on GitHub under new branch fallback.
In the code fragment below you can see the DLS route’s configuration with support for Hystrix circuit breaker, Ribbon load balancer, and Consul service discovery and registration. As a service discovery in the route definition you can also use some other solutions instead of Consul like etcd (etcServiceDiscovery
) or Kubernetes (kubernetesServiceDiscovery
).
from("direct:account")
.to("bean:customerService?method=findById(${header.id})")
.log("Msg: ${body}").enrich("direct:acc", new AggregationStrategyImpl());
from("direct:acc").setBody().constant(null)
.hystrix()
.hystrixConfiguration()
.executionTimeoutInMilliseconds(2000)
.end()
.serviceCall()
.name("account//account")
.component("netty4-http")
.ribbonLoadBalancer("ribbon-1")
.consulServiceDiscovery("http://192.168.99.100:8500")
.end()
.unmarshal(format)
.endHystrix()
.onFallback()
.to("bean:accountFallback?method=getAccounts");
We can easily configure all Hystrix’s parameters just by calling hystrixConfiguration
method. In the sample above Hystrix waits max 2 seconds for the response from remote service. In case of timeout fallback @Bean
is called. Fallback @Bean
implementation is really simple – it return empty list.
@Service
public class AccountFallback {
public List<Account> getAccounts() {
return new ArrayList<>();
}
}
Alternatively, the configuration can be implemented using object declarations. Here is a service call configuration with Ribbon and Consul. Additionally, we can provide some parameters to Ribbon like client read timeout or max retry attempts. Unfortunately, it seems they don’t work in this version of Apache Camel 🙂 (you can try to test it by yourself). I hope this will be corrected soon.
ServiceCallConfigurationDefinition def = new ServiceCallConfigurationDefinition();
ConsulConfiguration config = new ConsulConfiguration();
config.setUrl("https://192.168.99.100:8500");
config.setComponent("netty4-http");
ConsulServiceDiscovery discovery = new ConsulServiceDiscovery(config);
RibbonConfiguration c = new RibbonConfiguration();
c.addProperty("MaxAutoRetries", "0");
c.addProperty("MaxAutoRetriesNextServer", "1");
c.addProperty("ReadTimeout", "1000");
c.setClientName("ribbon-1");
RibbonServiceLoadBalancer lb = new RibbonServiceLoadBalancer(c);
lb.setServiceDiscovery(discovery);
def.setComponent("netty4-http");
def.setLoadBalancer(lb);
def.setServiceDiscovery(discovery);
context.setServiceCallConfiguration(def);
I described a similar case for Spring Cloud and Netflix OSS in one of my previous article. Just like in the example presented there, I also set here a delay inside the account-service
, which depends on the port on which the microservice was started.
@Value("${port}")
private int port;
public List<Account> findByCustomerId(Integer customerId) {
List<Account> l = new ArrayList<>();
l.add(new Account(1, "1234567890", 4321, customerId));
l.add(new Account(2, "1234567891", 12346, customerId));
if (port%2 == 0) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return l;
}
Results for the Spring Cloud sample were much more satisfying. The introduced configuration parameters such as read timeout for Ribbon worked and in addition Hystrix was able to automatically redirect a much smaller number of requests to slow service – only 2% of the rest to the non-blocking thread instance for 5 seconds. This shows that Apache Camel still has a few things to improve if wants to compete in microservice’s support with the Sprint Cloud framework.
Leave a Reply