Apache Camel - using service call EIP with EUREKA and spring boot.


Apache Camel, Service EIP, Eureka, Ribbon and Springboot.

This article deals with advanced topic on the use of camel, service discovery, auto balancing and springboot.  This is not introductory blog for these topics.

I have been playing with Apache Camel for few weeks now and every day I am getting more and more impressed with the capabilities of this tool.

Camel has very easy to use http4 component that can be used to call other services.  Using this component is straight forward.  Here is example:


from("direct:callme").to("http4://" + uRL);

This is works very well in traditional development when the url of the receiving system is know in advance.  However, in cloud environment with microservices one does not have a luxury of having that knowledge.  In this case a recommended approach is to use some sort of service discovery mechanism. Service discovery, is simple tool whose sole function is to keep track of what services are running and where do they reside.  One of better known service discoveries is Netflix Eureka which allows your service to register itself using VIP (virtual address ID).  Other services that are interested in using your service will use VIP to call Eureka to get details on where the service is running and call the service with that detail.

Springboot makes it very easy to use Eureka client via its implementation of DiscoveryClient interface.  For example to find out URL of service whose VIP is "STORES" you'll simply code:

    @Autowired
    private DiscoveryClient discoveryClient;

    public URI serviceUrl() {
        List<ServiceInstance> list = discoveryClient.getInstances("STORES");
        if (list != null && list.size() > 0) {
            return list.get(0).getUri();
        }
        return null;

    }

Note how the discovery client return a list of all available services.  In this example, I've chosen first service in the list to call.  This is NOT a good practice.

Calling other service using VIPs instead of hardcoded url solves the issue of a service going up and down dynamically. However, in the world of cloud computing and fault tolerant microservices having one instance of service is often not enough.  In all likelihood you'll have multiple instances running.  It becomes apparent rather quickly that one needs the ability on the client site to be able to do client side service balancing.

Simplest way of accomplishing is to get list of all available services matching VIP and just call each in turn until you succeed:

    private DiscoveryClient discoveryClient;

    public List<ServiceInstance>  serviceUrl() {

        List<ServiceInstance> list = discoveryClient.getInstances("STORES");
        if (list != null && list.size() > 0) {
            return list;
        }
        return null;
    }
    
    public void CallStoreService(String payLoad){
        List<ServiceInstance> allServices = serviceUrl();
        for(ServiceInstance si: allServices){
            try{
                //Call each instnace with the payload
                //until successfull
                return;
            }catch{
                //do nothing
            }
        }
        throw new RuntimeException("failed calling service");

    }

This approach will work, but it is very very smart.  Enter Netflix Ribbon. Ribbon provides the following features:

  • Multiple and pluggable load balancing rules
  • Integration with service discovery
  • Built-in failure resiliency
  • Cloud enabled
  • Clients integrated with load balancers
  • Archaius configuration driven client factory
Using Ribbon with Eureka and Springboot is trivial here you'll find great example of how to do it.

But in all likelihood you'll came here to see how to use Camel Service Calls with Eureka and Ribbon?

Camel-Service call EIP.  This pattern makes it very easy to call services using VIPs.  Camel has multiple options for pluggin in service discoveries like Consul, DNS, Etcd, Kubernetes, StaticServiceDiscovery.  Camel also has Ribbon component if you are using any of the above  services.  It does not however, have support for using Eureka as service discovery client (at the time of writing I could not locate one despite hours of searching).

This said however, there are ways of making it work.  If your project is using Spring boot with camel and ribbon, you're all set because camel allows you to use Springboot's discovery service (and if is eureka then you'll be using eureka).

To use it add camel-spring-cloud dependency.

<dependency>
    <groupId>org.apache.camel</groupId>
    <artifactId>camel-spring-cloud</artifactId>
    <!-- use the same version as your Camel core version -->
    <version>x.y.z</version>
</dependency>

Then all you need to do is to configure the service to use the discovery client with VIP.

     @Bean(name = "routeBuilder")
    public RouteBuilder route() {
        return new RouteBuilder() {

            @Override
            public void configure() throws Exception {
                from("direct:callMe").serviceCall()
                        .name("EUREKACLIENT").expression()
.simple("http4:${header.CamelServiceCallServiceHost}:${header.CamelServiceCallServicePort}/ack")
                        .end();
            }
        };
    }

And that's it!! Through the magic of SpringBoot your route will now call services based on dynamically discovered URL rather than hardcoded ones and in addition if will use the default client side auto balancing offered to you by Ribbon. 

Find a working example here.  Simply clone the service, start eureka-service then start eureka-client.
You can hit localhost:8689/initialInput/ with POST (pass any string).  The service will go to a route which in which it will discover where it lives and hit itself using VIP.




Comments