Spring Cloud Getting Started Series 4: Using Hystrix to Implement Circuit Breakers for Service Fault Tolerance Protection

In microservices, we divide the system into many service units, and each unit depends on each other through service registration and subscription consumption. But what if some services fail?

For example, there are three services (ABC), A calls B, B calls C. Due to network delay or a problem with C's own code, B can't get a response for a long time, so B's request to call C will be suspended and wait.

In the case of high concurrent access, these suspended threads cannot be released, blocking subsequent requests, and eventually causing B to hang up. And so on, A may also hang up, thereby causing the entire system to crash.

In order to solve the whole problem, Spring Cloud uses Hystrix for service fault tolerance protection, including a series of protection functions such as circuit breakers and thread isolation. Today we will see how to implement circuit breakers through Hystrix.

1. What is Spring Cloud Hystrix? What is a circuit breaker?

Spring Cloud Hystrix is ​​based on Netflix's open source framework Hystrix, and its purpose is to provide strong fault tolerance to delays and failures by controlling those nodes that access remote systems, services, and third parties.

The circuit breaker is similar to the leakage circuit breaker used in the strong electric box in our home. When the service unit fails (similar to a short circuit in an electrical appliance), the circuit breaker's fault monitoring function (similar to a fuse) returns a Respond to errors and avoid long waits, thereby preventing failures from spreading to the entire system.

2. In the case of no circuit breaker, the page displays

Remember the spring cloud introductory series 2 we wrote earlier: use Eureka for three services in service governance (eureka/hello-service/hello-consumer)? We conduct experiments based on this.

  1. Start the eureka service registry, port number 1111
  2. Start the hello-service service provider, here we start two services, the port numbers are 9090, 9091
  3. Start the hello-consumer service consumer, the port number is 9999; at this time, we have no problem accessing http://localhost:9999/hello-consumer many times
  4. Turn off the service whose hello-service port number is 9091, and then visit http://localhost:9999/hello-consumer several times, and an error is reported

    PS: The reason why we need to visit multiple times is because we have achieved load balancing through ribbon. When visiting http://localhost:9999/hello-consumer, we will poll the two services of hello-service. When An error is reported only when accessing the service whose port number is 9091, and there will be no problem accessing the service of 9090.

Three, circuit breaker code implementation

Next, let's see how to implement the code. We don't need to modify the service registry and service provider, but only need to modify the service consumer hello-consumer .

  1. Modify the POM file and introduce Hystrix dependencies
    <project xmlns="http://maven.apache.org/POM/4.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.sam</groupId>
        <artifactId>hello-consumer</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>1.5.1.RELEASE</version>
        </parent>
    
        < properties > 
            < javaVersion > 1.8 </ javaVersion > 
        </ properties >
    
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>Camden.SR6</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
    
        </dependencyManagement>
    
        < dependencies > 
            <!-- Introduce eureka client dependencies --> 
            < dependency > 
                < groupId > org.springframework.cloud </ groupId > 
                < artifactId > spring-cloud-starter-eureka </ artifactId > 
            </ dependency > 
            <! --Introduce ribbon dependency to achieve load balancing, we just use it here without any other introduction --> 
            < dependency > 
                < groupId > org.springframework.cloud </ groupId > 
                < artifactId >spring-cloud-starter-ribbon</ artifactId > 
            </ dependency > 
            <!-- Introduce hystrix dependencies to implement service fault tolerance protection --> 
            < dependency > 
                < groupId > org.springframework.cloud </ groupId > 
                < artifactId > spring-cloud-starter-hystrix </ artifactId > 
            </ dependency >
    
        </dependencies>
    </project>
  2. Modify the startup class, add the annotation @EnableCircuitBreaker, and open the circuit breaker
    @EnableDiscoveryClient
    @SpringBootApplication
    @EnableCircuitBreaker
    public class ConsumerApp {
    
    
        // @Bean is applied to the method to set the return value of the method to bean 
        @Bean
        @LoadBalanced   // @LoadBalanced implements load balancing 
        public RestTemplate restTemplate() {
             return  new RestTemplate();
        }
        
        public static void main(String[] args) {
            SpringApplication.run(ConsumerApp.class, args);
        }
    }

    At this time, you will find that this startup class has three annotations added. Is this very troublesome? It doesn't matter, we can use the annotation @SpringCloudApplication

    @SpringCloudApplication
    public class ConsumerApp {
    
    
        // @Bean is applied to the method to set the return value of the method to bean 
        @Bean
        @LoadBalanced   // @LoadBalanced implements load balancing 
        public RestTemplate restTemplate() {
             return  new RestTemplate();
        }
        
        public static void main(String[] args) {
            SpringApplication.run(ConsumerApp.class, args);
        }
    }

    @SpringCloudApplication = @EnableDiscoveryClient +@SpringBootApplication+@EnableCircuitBreaker, as can be seen from the source code:

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @SpringBootApplication
    @EnableDiscoveryClient
    @EnableCircuitBreaker
    public @interface SpringCloudApplication {
    }
  3. Additional service
    @Service
    public class ConsumerService {
        
        @Autowired
        RestTemplate restTemplate;
    
        @HystrixCommand(fallbackMethod = "errorMsg" )
         public String consumer() {
             // Call the hello-service service, note that the service name is used here, not the specific ip+port 
            restTemplate.getForObject("http://hello-service /hello", String.class );
             return "hello consumer finish !!!" ;
        }
    
        public String errorMsg() {
            return "error!!!";
        }
    }

    We put the implementation of calling RestTemplate in the original controller into the service, and specify the callback method through @HystrixCommand, and call the method when an error occurs.

  4. modify the controller
    /**
     *The restTemplate is no longer called directly here,
     * Instead, it is implemented by calling the service
     *
     */
    @RestController
    public  class ConsumerController {
    
        @Autowired
    //     RestTemplate restTemplate; 
        Consumer Service service;
        
        
        @RequestMapping( "/hello-consumer" )
         public String helloConsumer() {
     //         // Call the hello-service service, note that the service name is used here, not the specific ip+port
     //         restTemplate.getForObject(" http: //hello-service/hello ", String.class); 
            return service.consumer() ;
        }
    }
  5. Test, visit multiple times, when an error is reported, the following content will be displayed

     

You're done!

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325047958&siteId=291194637