Enterprise Java

Spring Cloud Rest Client with Netflix Ribbon – Basics

In an earlier blog post I had covered the different options for a REST client in the Spring Cloud world. All the options wrap around a Netflix OSS based component called Ribbon which handles the aspects related to loadbalancing the calls across different instances hosting a service, handling failovers, timeouts etc. Here I will cover a few ways to customize the behavior of underlying Ribbon components when used with Spring Cloud and follow it up with more comprehensive customizations.

Creating a Rest Client

To recap, first consider a case where a simple service needs to be called:

SampleServiceCall

A typical way to make this call using Spring is to inject in a RestTemplate and use it make this call, the following way:

public class RestTemplateBasedPongClient implements PongClient {

    @Autowired
    private RestTemplate restTemplate;

    @Override
    public MessageAcknowledgement sendMessage(Message message) {
        String pongServiceUrl = "http://serviceurl/message";
        HttpEntity<Message> requestEntity = new HttpEntity<>(message);
        ResponseEntity<MessageAcknowledgement> response =  this.restTemplate.exchange(pongServiceUrl, HttpMethod.POST, requestEntity, MessageAcknowledgement.class, Maps.newHashMap());
        return response.getBody();
    }

}

There is nothing special here. When using Spring Cloud however the same code behaves differently, now the RestTemplate internally uses Netflix OSS Ribbon libraries to make the call. This helps as the typical call flow is to first find the instances running the service and then to loadbalance the calls across the instances and to maintain this state.

Rest Client With Ribbon

Let me digress a little to touch on Ribbon, Ribbon uses an abstraction called a “Named client” to control the behavior of a remote service call – the name by which the service has registered with Eureka, timeout for service calls, how many retries in case of failures etc. These are specified through configuration files, and the entries are typically along these lines, note that the “Named client” here is “samplepong” and the properties have this as a prefix:

samplepong.ribbon.MaxAutoRetries=2
samplepong.ribbon.MaxAutoRetriesNextServer=2
samplepong.ribbon.OkToRetryOnAllOperations=true
samplepong.ribbon.ServerListRefreshInterval=2000
samplepong.ribbon.ConnectTimeout=5000
samplepong.ribbon.ReadTimeout=90000
samplepong.ribbon.EnableZoneAffinity=false
samplepong.ribbon.DeploymentContextBasedVipAddresses=sample-pong
samplepong.ribbon.NIWSServerListClassName=com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList

Coming back to Spring Cloud, it supports the concept of a “Named Client” in a very clever way through the Url hostname, so the RestTemplate call would now look like this:

ResponseEntity<MessageAcknowledgement> response =  this.restTemplate.exchange("http://samplepong/message", HttpMethod.POST, requestEntity, MessageAcknowledgement.class, Maps.newHashMap());

The “samplepong” in the url is the “Named client” and any customization for the behavior of the underlying Ribbon can be made by specifying the properties using this prefix. Since this is a Spring Cloud applications the properties can be specified cleanly in a yaml format along these lines:

samplepong:
  ribbon:
    DeploymentContextBasedVipAddresses: sample-pong
    ReadTimeout: 5000
    MaxAutoRetries: 2

Conclusion

This covers the basics of how Spring Cloud abstracts out the underlying the Ribbon libraries to provide a very intuitive facade to make remote service calls in the Cloud environment. There are some details that I have skimmed over on some of the customizations, I will cover these in a newer post.

  • Here is my github repo with the code that I have used for the article.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

5 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Tyler Van Gorder
Tyler Van Gorder
8 years ago

Please note that the current version of the RestTemplate will not respect the retry options that you setup in your configuration. Currently, the RestTemplate just uses Eureka to get a node from the logical name. If the Rest call fails (because that node happens to be down), the template will NOT retry or attempt to fail over to the next client. I have an enhancement request logging already here : https://github.com/spring-cloud/spring-cloud-netflix/issues/648

Biju Kunjummen
8 years ago

Awesome, I did not know that Retry properties don’t work out of the box, assumed that it would work as it does with Ribbon. I will watch your PR.

Abhijit Sarkar
6 years ago

Hi,

1. How is ‘samplepong’ resolved? I don’t see a `samplepong.ribbon.listOfServers` configured, are you using Eureka? Ribbon will try to resolve the name from Eureka unless A) Eureka is not on the classpath, or B) samplepong.eureka.enabled=false
2. With the latest version of Spring Cloud, a RestTemplate bean is no longer created via auto configuration. It must be created by the application and qualified with @LoadBalanced.
3. I find Ribbon retry pretty lacking. You can’t do conditional retries (not much point in retrying if you got a 40x), or retries with exponential backoff.

Biju Kunjummen
6 years ago
Reply to  Abhijit Sarkar

Yes, I am using Eureka @Abhijeet D – the configuration is here, https://github.com/bijukunjummen/spring-cloud-ping-pong-sample/blob/master/sample-ping/src/main/resources/application.yml, it has been a while since I looked at that, so it is likely to be dated. Yes, you are right about it using Eureka if Eureka is not explicitly disabled. At a different place I am using list of servers, but after explicitly overriding the Eureka configuration using this configuration – https://github.com/bijukunjummen/spring-cloud-ping-pong-sample/blob/master/sample-ping/src/main/java/org/bk/noscan/consumer/ribbon/PongDirectCallRibbonConfiguration.java Yes, on your second point, the sample I have is old. Yes, on the third point also, may be a cleaner solution could to not use Ribbon for retries and move it to something… Read more »

Rohit
Rohit
6 years ago

Using @postconstruct, autowiring a loadbalancer client does not seem to load the list of servers configured in property file, I get back null servers when I start the embedded server. I need to set an aws endpoint on startup, is there any other alternative

Back to top button