Microservices – Circuit Breaker

Why Circuit Breakers?

1. Failing fast – It’s better to fail fast than trying to establish connection and fail later.
2. Fallback functionality
3. Automatic recovery

How it works

1. Detect something is wrong.
2. Take temporary steps to avoid the situation getting worse
3. Deactivate the problem component so it doesn’t affect downstream components

Circuit Breaker Pattern

1. When to break circuit
2. What to do when circuit breaks
3. When to resume requests

Circuit Breaker Parameters

Before knowing Circuit Breaker parameters, let’s understand how request flow works.

Circuit Breaker Request Flow

As per above diagram, we have received total 7 requests out of those 3 got succeeded and 4 either timed out or throws an error.

Configuring when does the circuit trip?
1. Last n requests to consider for the decision
2. How many of those should fail?
3. Timeout duration

When does a circuit get back to normal?
1. How long a circuit trip to try again? – Retrying after circuit break

Example:
Last n requests to consider for the decision: 7
How many of those should fail? 3
Timeout duration: 2s
How long to wait (Sleep window): 10s

OK!

So now we have understood the theory of Circuit Breakers it’s time to implement. To implement Circuit Breaker pattern we have technology called Hystrix (provided by Netflix). Rest of the article focuses on setting up Hystrix in Spring Boot microservices.

What is Hystrix?

1. Open source library originally created by Netflix
2. Implements Circuit breaker pattern so you don’t have to
3. Give this configuration params and it does the work
4. Works well with Spring Boot

Steps to Add Hystrix to Spring Boot Microservices

Step 1: Add the below starter dependency in pom.xml

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

Step 2: Go to main class of your microservice and add @EnableCircuitBreaker annotation

package org.techlearnings;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker
public class UserDetailsServiceApplication {

	public static void main(String[] args) {
		SpringApplication.run(MovieCatalogServiceApplication.class, args);
	}
	
	@Bean
	@LoadBalanced
	public RestTemplate getRestTemplate() {
		return new RestTemplate();
	}
}

Step 3: Add below annotation to the methods that need circuit breakers.
@HystrixCommand
The way @HystrixCommand works is, it creates the proxy and breaks the circuit by not calling the method available in actual class based on the configuration (circuit breaker parameters) you provided.

Step 4: Add Circuit Breaker parameters
Example

@HystrixCommand(commandProperties = {
				@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2000"),
				@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "5"),
				@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50"),
				@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "5000")
		})
public UserDetails getUserDetails() {
	return restTemplate.getForObject("http://user-details-service/userdetails/" + 1, UserDetails.class);
}

Great! Now we have configured Circuit Breaker in our microservices. But what if requests keep coming for the services we have setup Circuit Breakers for? Well! We need Fallback mechanism in that case.

How Hystrix works?
Let’s say you have 3 microservices named app1, app2 and app3
One of the resources(r1) in app1 has a method named m1, which is consuming resources available in app2 and app3. If you annotate m1 with @HystrixCommand then Hystrix creates the proxy of r1. So if you consume 2 or more microservices from the same method then you cannot handle the fallback. So better, refactor it by creating the method(annotated with @HystrixCommand) in separate bean.

Hystrix Properties

@HystrixCommand(commandProperties = {
				@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2000"),
				@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "5"),
				@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50"),
				@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "5000")
		})
public UserDetails getUserDetails() {
	return restTemplate.getForObject("http://user-details-service/userdetails/" + 1, UserDetails.class);
}

Author: Mahesh

Technical Lead with 10 plus years of experience in developing web applications using Java/J2EE and web technologies. Strong in design and integration problem solving skills. Ability to learn, unlearn and relearn with strong written and verbal communications.