Synchronous communication

As the name says, in synchronous communication, communication happens between two services, and a timely response is expected. The consumer server waits or blocks until the response from the remote server is received. In synchronous communication, receivers instantly know whether the call is successful or unsuccessful, and a decision can be taken on that. It is very easy to implement this approach. Because of the request/response architecture, REST becomes the best choice for synchronous communication. Although microservice developers consider JSON to be the best approach over HTTP, SOAP, XMLPRC, and socket programming are all candidates of synchronous communication. To understand this better, we will go through the example inventory management system.

Consider a sunglasses website http://myeyewear.com/, assuming that it is very popular for shades. Let's assume that the website has announced a Christmas sale. At a particular moment, there is the possibility of many people looking at one product and trying to add shades to their shopping cart. In this scenario, companies want to check whether the item is available and only then let customers add it to their shopping carts. Companies may also block the inventory for this product until either the customers buy it or their cart time expires. There are many ways to handle this situation, but for the sake of the example here, we will assume that the microservices are communicating over REST. This process will take place in the following steps:

  1. The client/consumer goes to the API Gateway to add the product to their shopping cart.
  2. The API Gateway goes to the cart management service with the product ID to add to the user's cart.
  3. The cart service hits the inventory service to block the inventory of the given product ID.
  4. At this level, the cart management service waits for a response from the inventory service. Meanwhile, the inventory service checks the availability of the product, and if found in stock, it blocks one and responds to the cart management service.
  5. Based on the response received, the cart service adds the product to the cart and responds to the consumer.

In this communication, the calling service has to know the existence of the inventory service, which, as a result, creates some kind of dependency between them. Also, the calling service blocks the call until it receives a response from the called server. This is an example of tight coupling. The calling service has to handle various errors that are raised from the called service, or perhaps the calling service is down. Although timeouts are there to handle these kinds of situations, they are a waste of system resources. Also, the last few call systems get no result from the called service, but this time out will be there in each call and will limit the resource consumption and delay the response time.

A circuit breaker pattern helps deal with errors from the calling service or when there is no response from the calling service. In the previous chapter, we introduced the topic of a circuit breaker. This time, let's go into more detail.

A circuit breaker pattern identifies the failure based on some rules/threshold defined. Then, it prevents the calling service from calling the infected service again for a certain period of time, or it can go to any fall back method. In the circuit breaker pattern, there could be three states of circuit or call:

  • Closed state
  • Open state
  • Half-open state

In the closed state, the call executes perfectly, and the calling service gets the result from the called service. In the open state, the called service does not respond and has crossed the threshold. In this case, that circuit will be marked open. It will not entertain more requests to the infected service for the configured amount of time and fall back to another configured method. There is the last state, which is the half-open state. In this state, whenever the configured time is over for the open state, the circuit breaker makes it the half-open state. In this state, the calls are passed to the infected service occasionally to check whether the issue is fixed. If it is a fixed circuit, it will be again marked as closed else it will revert back to open state.

To implement this pattern, interceptors are used at the side of the calling service. The interceptor keeps an eye on every request going out and responses coming in. If any request fails for the predefined threshold, it stops sending requests outside and responds with a predefined response or method. It will initiate the timer to maintain the open state of the service.

Spring also provides support for Netflix Hystrix. One can use this facility by adding some annotation, and it is done. Consider an online movie ticket booking site. If the booking of one ticket failed or responds in time out (due to heavy traffic), we want to recommend another movie showing at that time to the users so that they can book tickets for that.

There will be a ticket booking application and there be a calling application, say consuming application. The consuming application will be calling the exposed URL http://<application Ip:port>/bookingapplication/{userId}/{movieId} from the ticket booking application. In the case of this URL failure, we can configure a fall back method with some simple annotation. This will be the code-consuming application:

package com.practicalMicroservice.booking; 
 
import org.springframework.boot.SpringApplication; 
import org.springframework.boot.autoconfigure.SpringBootApplication; 
import org.springframework.web.bind.annotation.RestController; 
import org.springframework.web.bind.annotation.RequestMapping; 
 
@RestController 
@SpringBootApplication 
@EnableCircuitBreaker 
 
public class ConsumingApplication { 
 
  @Autowired 
  private ConsumingService consumingService; 
 
  @RequestMapping(method = RequestMethod.POST,value = "/book/{movieId}",produces = "application/json") 
  public String book ticket(@PathVariable("userId") String userId,@PathVariable("movieId") String movieId){ 
    return  consumingService.bookAndRespond(userId,movieId); 
  } 
 
  public static void main(String[] args) { 
    SpringApplication.run( ConsumingApplication .class, args); 
  } 
} 

The @EnableCircuitBreaker annotation enables the use of the circuit breaker pattern in the Spring Boot application. To use Hytrix in your application as the circuit breaker pattern, there is another annotation @HystrixCommand. However, it can be used only in classes that are annotated with @service or @component. So, we will create a service class here:

@Service 
public class ConsumingService { 
 
  @Autowired 
   private  RestTemplate restTemplate; 
 
 @HystrixCommand(fallbackMethod = "getAnotherCurentlyShowingMovie") 
  public String bookAndRespond() { 
    URI uri = URI.create("http://<application Ip:port>/bookingapplication/{userId}/{movieId}"); 
 
    return this.restTemplate.getForObject(uri, String.class); 
  } 
 
  public String getAnotherCurentlyShwoingMovie() { 
    return "We are experiencing heavy load on booking of your movie. There are some other movies are running on same time, please check if you are interested in any one. " + getSameShowtimeMovieList() ; 
  } 
 
  public String getSameShowtimeMovieList() { 
       return "fast and Furious 8, The Wolverine3"; 
    } 
} 

In the preceding class, whenever the circuit fails, it will not call the infected service anymore; rather it will call another method getAnotherCurentlyShowingMovie and show the user another running movie at the same time.

The circuit breaker pattern is good to handle failure in synchronous communication, but it doesn't resolve other issues in synchronous communication. Knowing the existence of other services enables coupling between services, and too much coupling converts the microservice to a monolithic application.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset