Spring Cloud Hystrix Fuse Starting from Zero

Preface:

Spring Cloud Series Futures Point Here
In micro-service architecture, there are usually multiple service layer invocations. The failure of basic services may lead to cascade failures, which may result in the unavailability of the whole system. This phenomenon is called service avalanche effect. The service avalanche effect is a process in which the unavailability of the "service provider" leads to the unavailability of the "service consumer" and gradually enlarges the unavailability.
If the following figure shows: A as a service provider, B as a service consumer of A, C and D as a service consumer of B. When A is unavailable, B is unavailable and the unavailability is enlarged to C and D like a snowball, the avalanche effect is formed.

So how can we prevent this cascading effect from leading to the collapse of the whole service? Then we need a fuse, which can take certain measures to fuse directly after a module has problems. The fuse in Spring Cloud is Hystrix.

I. What is Hystrix

Hystrix is an open source library for dealing with delay and fault tolerance in distributed systems. Many dependent calls inevitably occur and fail in distributed systems. For example: timeout, abnormal. Hystrix can ensure that a dependency will not affect the whole micro-service system in case of problems, avoid cascading failures and improve the flexibility of distributed systems.

The fuse itself is a switching device. When a system fails to invoke, the fuse monitors the service (fuse) and returns a fallback to the invoked method, instead of waiting for a long time or throwing an exception. This ensures that threads will not be occupied for a long time, avoids the occupation of resources, and also prevents the spread of faults in micro-service systems and avalanches. Photo Source Official Website

In fact, fuses are a protection mechanism to deal with timeouts and exceptions during service invocation.

II. Construction of Hystrix Project

Setting goals
· 1. Creating Microservice_product_provider_hystrix 8004

The creation process refers to microservice_product_provider 8001 for details. Distributed Project Infrastructure Construction

(2) Introducing Hystrix dependencies

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

(3) application.yml is configured as follows

spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource #Using druid data source
    driver-class-name: com.mysql.jdbc.Driver
    username: root
    password: root
    url: jdbc:mysql://localhost:3306/springcloud001
  #   Other configurations of data sources
    initialSize: 5
    minIdle: 5
    maxActive: 20
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
  application:
    name: microservice-provider
server:
  port: 8004
mybatis:        #Basic configuration of mybatis
  config-location: classpath:mybatis/mybatis-config.xml
  mapper-locations:
    - classpath:mybatis/mapper/ProductMapper.xml

eureka:  #Setting up the address of eureka registration service
  client:
    service-url:
        defaultZone:  http://eureka7001:7001/eureka,http://eureka7003:7003/eureka,http://eureka7002:7002/eureka
  instance:
    instance-id: microservice-product-provider-hystrix8004 #Alias for Configuration Services
    prefer-ip-address: true # Use ip registration when registering

In fact, the provider s of each service have the same configuration except for different ports and different instance names.
**(4) Creating Fuse Services**
In the original ProductController layer method, a method is created to quickly fuse the return when an error occurs, so as to prevent the whole micro-service from being affected by the call failure. And add annotations to the method that the target needs to be fused.

    @HystrixCommand(fallbackMethod = "processHystrix")
    @GetMapping("/product/{id}")
    public Product get(@PathVariable Long id){
        Product product = productService.get(id);
        //Anomalies occurred in the simulation
        if (product==null){
            throw  new RuntimeException();
        }
        return product;
    }
    
    // The fuse service quickly returns an expected alternative corresponding,
    public Product processHystrix(@PathVariable Long id){
        return  new Product().setPid(id).setPName("I'm sorry."+id+"No information in the database");
    }

The @HystrixCommand (fallbackMethod = processHystrix) annotation is used in the get method of Inquiring Goods according to the commodity id above, which means that this method opens the fuse mechanism. It means that when the method call is not working, for example, when the call is made, the time-out occurs, the exception occurs, then the fuse mechanism will work and quickly return to one. An expected option. That is the processHystrix method we configure.

**(5)** Open Hystrix on the main boot class

@SpringBootApplication
@EnableEurekaClient
@EnableHystrix //Open Fuse Service
@MapperScan(basePackages = {"com.kuake.dao"}) //Scanning mapper interface
public class ProviderHystrix8004Application {
    public static void main(String[] args) {
        SpringApplication.run(ProviderHystrix8004Application.class,args);
    }
}

(6) Start testing
start-up

microservice_eureka_7001(Registry)
microservice_eureka_7002
microservice_eureka_7003
microservice_product_provider_hystrix8004(Producer with fuse mechanism)
microservice_product_consumer80 (Consumer)

First access the commodity ID that exists in the database http://localhost/consumer/product/1
Return:

{"pid":1,"dbSource":"springcloud001","pname":"Shufujia"}

Now query the id that does not exist in the database to simulate the exception. Access http://localhost/consumer/product/100
Return:

{"pid":100,"dbSource":null,"pname":"Sorry, the 100 has no information in the database."}

Instead of throwing exceptions that render the service inaccessible, the server returns an acceptable result that improves the fault tolerance of the service.
Disadvantages:
1. The @HystrixCommand annotation method expands, requiring a method for each annotation added.
2. Exceptions and business logic are bound together, and it is difficult to maintain them in the later stage when the coupling degree is relatively high.

Our fuse processing is operated on the server side, but we can also refer to the mechanism of fuse processing to the client side and extract all fuse methods into the product service client interface of the api module, so as to extract a layer up, and use a factory to manage our fast callback method in a unified way. Before explaining this method again, another scenario that Hystrix solves, service degradation, is introduced.

What is Service Degradation

Simply understand the degradation of services is: in the case of insufficient overall resources, painfully turn off some micro-services, wait to tide over the difficulties, and then turn on the service. After degrading, the client can also receive prompts when the server is unavailable, without hanging up and consuming the server.

For example, the bank has three windows A B C. Normally, every window can be served normally. But suddenly, it was told that window A should deal with more important business and need to send more people to it. All the strategies adopted are to transfer the people of window C to window A for help. But there will still be people queuing at window C, so we need to put up a notice to suspend the service.
To cope with the lack of resources, temporarily close a window, but even if the window is not available, we can get the information on the notice board, know that the service is suspended, rather than waiting all the time.

We revamped the Microservice_product_consumer 80_feign we used before, and used Hystrix to make the client degrade the service.

(1) Create a FallBackFactory interface implementation class under the api module. Product Client Service FallbackFactory. Java

public class ProductClientServiceFallbackFactory implements FallbackFactory<ProductClientService> {
    @Override
    public ProductClientService create(Throwable throwable) {


        return new ProductClientService() {
            //You can write some information in the arc value. Tell users that they are not accessible now
            @Override
            public List<Product> list() {
                return null;
            }

            @Override
            public Product get(Long id) {
                return new Product().setPid(id).setPName("Sorry, downgrading is under way. Wait a little while for further visits.");
            }

            @Override
            public boolean add(Product product) {
                return false;
            }
        };
    }
}

(2) Synchronize updates of api modules to local warehouses
`

(3) Configuring Fuse Degradation Service in feignservice
Add the following configuration: label factory

@FeignClient(value = "PROVIDER" ,fallbackFactory=DeptClientServiceFallbackFactory.class)
public interface DeptClientService {

    @GetMapping("/dept/list")
    List<Dept> list();

    @GetMapping("/dept/{id}")
    Dept get(@PathVariable(value = "id") Long id);

    @PostMapping("/dept")
    boolean add(@RequestBody Dept dept);

}

Be sure to inject this factory into microservice_product_consumer 80_feign

    @Bean
    public ProductClientServiceFallbackFactory productClientServiceFallbackFactory (){
        return new ProductClientServiceFallbackFactory();
    }

(4) Testing

Start up service
microservice_eureka_7001
microservice_eureka_7002
microservice_eureka_7003
microservice_product_consumer80_feign
microservice_product_provider_hystrix8004

1. Normal access to http://localhost/consumer/product/3
Return:

{"pid":3,"dbSource":"springcloud001","pname":"Pepsi Cola"}

Simulated downgrading process (as mentioned above, downgrading is to shut down some micro-services painfully when resources are not enough). Now let's turn off the service microservice_product_provider_hystrix8004
2. Visit http://localhost/consumer/product/3 again
Return:

{"pid":3,"dbSource":null,"pname":"Sorry, downgrading is under way. Wait a little while for further visits."}

Return message is our default information, so that although the service stopped, but also return valid information, can remind users, do not have to wait all the time. Because if the message is returned, the user may always operate frequently, resulting in the occupancy of system resources. This return information can reduce the occurrence of this kind of thing very well.

Fuse Summary

In the complex distributed system structure, there will be a large number of interdependencies, and each dependency will inevitably occur in the process of invoking, abnormal, timeout. When a large number of requests are waiting for the corresponding services, these applications may also lead to increased delay between services, thus backing up queues, threads and other system resources, resulting in more cascading failures throughout the system. Eventually, avalanches may even occur.

Fuse mechanism: When an exception occurs to a service, a handled result is returned through @HystrixCommand, so that the service does not always wait for the service with an exception. When an exception condition is triggered, the whole service is fused directly instead of waiting for the service to expire. (On the server side)

Degradation mechanism: Consider the overall load to shut down some services, but the closed services will also have requests for subsequent access, all to return a fallback information, indicating that the service is not available, has been degraded. In this way, the user who sees the message will not visit it again, avoiding the occupation of resources, resource hanging and tension. (Client)

Keywords: Mybatis Spring Database Druid

Added by freeloader on Tue, 30 Jul 2019 18:36:35 +0300