Teach you how to build a SpringCloud project (10) Integrate Hystrix service downgrade

What are microservices? A series will be seen at a glance!

1. Teach you how to build a SpringCloud project (1) Detailed explanation with pictures and texts, fool-like operation

2. Teach you how to build a SpringCloud project (2) Producers and consumers

3. Teach you how to build a SpringCloud project (3) Integrate the Eureka service registration center

4. Teach you how to build the SpringCloud project (4) Eureka cluster version construction

5. Teach you how to build the SpringCloud project (5) Build the producer cluster version

6. Teach you how to build a SpringCloud project (6) Eureka realizes service discovery

7. Teach you how to build a SpringCloud project (7) Integrate the Consul service registration center

8. Teach you how to build a SpringCloud project (8) Integrated Ribbon load balancer

9. Teach you how to build a SpringCloud project (9) Integrate OpenFeign service interface calls

10. Teach you how to build a SpringCloud project (10) Integrate Hystrix service downgrade

11. Teach you to build a SpringCloud project (11) Integrating Hystrix's service fuse

12. Teach you how to build a SpringCloud project (12) Integrate Hystrix's graphical Dashboard real-time monitoring

13. Teach you how to build a SpringCloud project (13) Integrate a new generation of Gateway

14. Teach you how to build a SpringCloud project (14) Integrated Config Distributed Configuration Center

15. Teach you how to build a SpringCloud project (15) Integrated Bus message bus

16. Teach you how to build a SpringCloud project (16) Integrated Stream message driver

17. Teach you how to build a SpringCloud project (17) Integrating Sleuth distributed link tracking

Continue to update, welcome to like and follow!

1. Problems faced by distributed systems?

Applications in complex distributed architectures, with dozens of dependencies, each will inevitably fail at some point. To give us a better understanding of learning, look at the picture below:
insert image description here

From the figure above, we can see that the request needs to call four services A, H, P, and I. If everything goes well, there is no problem. The key is what happens if the service I times out? As shown below:

insert image description here

There will be an avalanche as shown in the figure, which we call a service avalanche.

What is Service Avalanche?

When multiple services are called, suppose microservice A calls microservice B and microservice C, and microservice B and microservice C call other microservices. This is the so-called "fan-out".
If the call response time of a certain microservice on the fan-out link is too long or unavailable, the call to microservice A will occupy more and more system resources, which will cause the system to crash, so the "avalanche effect"

For high-traffic applications, a single backend dependency can cause all resources on all servers to be saturated within seconds. Worse than failing, these applications can also cause increased latency between services, straining backup queues, threads, and other system resources, causing more cascading failures throughout the system. These all represent the need to isolate and manage failures and latencies so that failure of a single dependency does not bring down entire applications and systems. Therefore, usually when you find that a certain instance under a module fails, the module will still receive traffic at this time, and then the problematic module should call other modules, which will cause cascading failures, or avalanches.

2. Introduction to Hystrix

( Click on the official website to learn ) In order to solve this problem, the technology of Hystrix appeared. Hystrix is ​​an open source library used to deal with the delay and fault tolerance of distributed systems. In distributed systems, many dependencies will inevitably fail to call. For example, timeouts, exceptions, etc., Hystrix can ensure that in the case of a dependency problem, it will not cause the entire service to fail, avoid cascading failures, and improve the elasticity of the distributed system.

The "circuit breaker" itself is a development device. When a service unit fails, through the fault monitoring of the circuit breaker (similar to blowing a fuse), an expected and processable alternative response (FallBack) is returned to the caller. , instead of waiting for a long time or throwing an exception that the caller cannot handle, this ensures that the thread of the service caller will not be occupied for a long time and unnecessarily, thereby avoiding the spread of faults in the distributed system, and even avalanche.

The circuit breaker component in springcloud is Hystrix. Hystrix is ​​also part of the Netflix suite. Its function is that when the call to a service exceeds a certain number of times (default 20) and the failure rate exceeds a certain value (default 50%) within a certain period of time (default 10s), the circuit breaker of the service will be opened . Returns a fallback set by the developer. The fallback can be another service call protected by Hystrix, or it can be a fixed value. Fallback can also be designed as a chain call, first execute some logic, and then return to fallback.

Three functions of Hystrix:

服务降级(Fallback):比如当服务器忙,请稍后再试,不让客户端等待并立刻返回一个友好提示,Fallback,会发生降级的几种情况:程序运行异常、超时、服务熔断触发服务降级。

服务熔断(Break):类比保险丝达到最大服务访问后,直接拒绝访问,拉闸限电,然后调用服务降级的方法并返回友好提示。三个步骤先进行服务的降级、进而熔断、恢复调用链路。

实时的监控:会持续地记录所有通过Hystrix发起的请求执行信息,并以统计报表和图形的形式展示给用户,包括没秒执行多少成功,多少失败等。

Understand the service flow limit (Flowlimit): For example, operations such as seckill with high concurrency, it is strictly forbidden to crowd and arrange everyone to queue up, N requests per second, and proceed in an orderly manner.

3. Code example

Create a new module, the producer service port is 8001, and the service name is cloud-provider-hystrix-payment8001. After the creation is complete, configure the pom.xml file first. Mainly to introduce hystrix dependencies. As shown below:

<?xml version="1.0" encoding="UTF-8"?>
<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">
    <parent>
        <artifactId>mcroservice</artifactId>
        <groupId>com.study.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
 
    <artifactId>cloud-provider-hystrix-payment8001</artifactId>
    <dependencies>
        <!--hystrix-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
        <!--eureka client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <dependency>
            <groupId>com.study.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--监控-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!--热部署-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
 
</project>

Create a new yml file, as shown below:

server:
  port: 8001
spring:
  application:
    name: cloud-provider-hystrix-payment
eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:   
      defaultZone: http://eureka7001.com:7001/eureka

Create a new main startup class, as shown below:

package com.buba.springcloud;
 
import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
 
import javax.swing.*;
 
@SpringBootApplication
@EnableEurekaClient
public class PaymentHystrixMain8001 {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(PaymentHystrixMain8001.class, args);
    }
}

Create a new business class, as shown below:

package com.buba.springcloud.service;
 
import cn.hutool.core.util.IdUtil;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.stereotype.Service;
 
import java.util.concurrent.TimeUnit;
 
@Service
public class PaymentService {
    
    
    /**
     * 正常访问
     *
     * @param id
     * @return
     */
    public String paymentInfo_OK(Integer id) {
    
    
        return "线程池:" + Thread.currentThread().getName() + " paymentInfo_OK,id:" + id + "\t" + "O(∩_∩)O哈哈~";
    }
 
    /**
     * 超时访问
     *
     * @param id
     * @return
     */
   public String paymentInfo_TimeOut(Integer id) {
    
    
        int timeNumber = 3;
        try {
    
    
            // 暂停3秒钟
            TimeUnit.SECONDS.sleep(timeNumber);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        return "线程池:" + Thread.currentThread().getName() + " paymentInfo_TimeOut,id:" + id + "\t" +
                "O(∩_∩)O哈哈~  耗时(秒)" + timeNumber;
    }
       
  }

Create a new control layer, as shown below:

package com.buba.springcloud.controller;
 
import com.buba.springcloud.service.PaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
 
import javax.annotation.Resource;
 
@RestController
@Slf4j
public class PaymentController {
    
    
    @Autowired
    private PaymentService paymentService;
 
    @Value("${server.port}")
    private String servicePort;
 
    /**
     * 正常访问
     *
     * @param id
     * @return
     */
    @GetMapping("/payment/hystrix/ok/{id}")
    public String paymentInfo_OK(@PathVariable("id") Integer id) {
    
    
        String result = paymentService.paymentInfo_OK(id);
        log.info("*******************result:" + result);
        return result;
    }
 
    /**
     * 超时访问
     *
     * @param id
     * @return
     */
    @GetMapping("/payment/hystrix/timeout/{id}")
    public String paymentInfo_TimeOut(@PathVariable("id") Integer id) {
    
    
        String result = paymentService.paymentInfo_TimeOut(id);
        log.info("*********************result:" + result);
        return result;
 
    }
  
}

For the convenience of demonstration, only the stand-alone version of Eureka is used, and the port is 7001. Remember to modify the yml file of Eureka to point to yourself. Start Eureka, start cloud-provider-hystrix-payment8001, access the path http://localhost:8001/payment/hystrix/ok/1, the successful interface is as follows:

insert image description here

Visit http://localhost:8001/payment/hystrix/timeout/2, wait for 5 seconds, and successfully return to the interface as shown below:
insert image description here

Under normal circumstances, there is no problem with the project now, and both interfaces can be accessed normally. Using the above as the basic platform, we will demonstrate the situation from correct -> error -> downgrade fuse -> recovery. Next, let's conduct a high concurrency test to see if it is still normal. Use the test tool Jmeter to create a new thread group, and 20,000 concurrent requests will crush 8001, and all 20,000 requests will go to the interface service http://localhost:8001/payment/hystrix/timeout/2, as shown in the figure below:

insert image description here

Configure the http request, pay attention to the request method, port number, and interface, as shown in the figure below:

insert image description here

We start this thread group, and we can see that the thread group can access the interface, as shown in the figure below:

insert image description here

Then we visit these two interfaces by ourselves to see what will happen. We can get a response immediately, but both of them are circling around before we get a response, as shown in the figure below:

insert image description here

The following reason is that Tomcat's default worker threads are full, and there are no extra threads to break down the pressure and process. The above is only the test of the producer service itself 8001. If the external consumer service 80 also visits at this time, the consumer can only wait, which eventually leads to dissatisfaction with the consumer service 80, and the server 8001 is directly dragged to death.

Then we create a new Modeule to serve consumers, the port is 80, the service name is cloud-consumer-feign-hystrix-order, and the pom.xml file is configured, as shown below:

<?xml version="1.0" encoding="UTF-8"?>
<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">
    <parent>
        <artifactId>mcroservice</artifactId>
        <groupId>com.study.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
 
    <artifactId>cloud-consumer-feign-hystrix-order</artifactId>
    <dependencies>
        <!--openfeign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!--eureka client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>com.study.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--监控-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
 
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.netflix.hystrix</groupId>
            <artifactId>hystrix-javanica</artifactId>
            <version>1.5.18</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>
 
</project>

Create a new yml configuration file, as shown below:

server:
  port: 80
eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka

Create a new main startup class, as shown below:

package com.buba.springcloud;
 
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.cloud.openfeign.EnableFeignClients;
 
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
 
public class OrderHystrixMain {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(OrderHystrixMain.class, args);
    }
}

Create a new business class, as shown below:

package com.buba.springcloud.service;
 
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
 
@Component
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT")
public interface PaymentHystrixService {
    
    
 
    /**
     * 正常访问
     *
     * @param id
     * @return
     */
    @GetMapping("/payment/hystrix/ok/{id}")
    String paymentInfo_OK(@PathVariable("id") Integer id);
 
    /**
     * 超时访问
     *
     * @param id
     * @return
     */
    @GetMapping("/payment/hystrix/timeout/{id}")
    String paymentInfo_TimeOut(@PathVariable("id") Integer id);
 
}

Create a new control layer, as shown below:

package com.buba.springcloud.controller;
 
import com.buba.springcloud.service.PaymentHystrixService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
 
@RestController
@Slf4j
public class OrderHystirxController {
    
    
    @Autowired
    private PaymentHystrixService paymentHystrixService;
 
    @GetMapping("/consumer/hystrix/ok/{id}")
    String paymentInfo_OK(@PathVariable("id") Integer id){
    
    
        return  paymentHystrixService.paymentInfo_OK(id);
    }
 
 
    @GetMapping("/consumer/payment/hystrix/timeout/{id}")
    public String paymentInfo_TimeOut(@PathVariable("id") Integer id) {
    
    
       
        return paymentHystrixService.paymentInfo_TimeOut(id);
    }
}

Start the cloud-consumer-feign-hystrix-order consumer service. Under normal circumstances, perform an interface call test. We visit http://localhost/consumer/hystrix/ok/1, and you can see that you can get a response immediately. The successful interface is as follows:

insert image description here

Then let's test it under high concurrency to see what's going on, we start the thread group, and then visit http://localhost/consumer/hystrix/ok/1 again, sometimes it takes a few seconds to get a
response ,As shown below:

insert image description here

Then we visited http://localhost/consumer/hystrix/timeout/1, and a timeout error occurred directly, as shown below:

insert image description here

The above faults and the resulting phenomenon are because other interfaces at the same level of 8001 are trapped, because the worker threads in the tomcat thread pool have been squeezed out. At this time, the 80 consumer end calls the producer 8001 service, and the client access response is slow. It is precisely because of the above-mentioned faults and bad performance that our technologies such as downgrade, fault tolerance, and current limiting were born.

How to solve the above problems?

1、出现超时导致服务器变慢(转圈),超时不再等待
2、出错(宕机活程序运行出错),出错 要有兜底
当我们的生产者服务8001超时了,消费者(80)不能一直卡死等待,必须要服务降级
当我们的生产者服务8001宕机了,消费者(80)不能一直卡死等待,必须要服务降级
当我们的生产者服务8001正常,但是消费者(80)自己有故障或有自有要求(自己的等待时间小于生产者服务本身需要的时间)

4. Service downgrade configuration

1. Service degradation due to access timeout exception

We need to start with the producer 8001 service itself to find out the existing problems, set the peak value of its own call timeout period, and it can run normally within the peak value. If it exceeds the peak value, it needs to be dealt with in a comprehensive way, and the service downgrades Fallback. For example, the current access timeout method is set to pause for 2 seconds, and we set the peak value of this method to 3 seconds. If the access exceeds 3 seconds, we will do a service downgrade Fallback, and if it does not exceed, the value will be returned normally. As shown below:

/**
     * 超时访问
     *
     * @param id
     * @return
     */
   public String paymentInfo_TimeOut(Integer id) {
    
    
         try {
    
    
            // 暂停2秒钟
            TimeUnit.MILLISECONDS.sleep(2000);
 
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        return "线程池:" + Thread.currentThread().getName() + " paymentInfo_TimeOut,id:" + id + "\t" +
                "O(∩_∩)O哈哈~  耗时(秒)";
    }

For service downgrade Fallback, we need to write a bottom-up method in the business class, as shown in the following figure:

 /**
     * 超时访问到这里兜底
     *
     * @param id
     * @return
     */
    public String paymentInfo_TimeOutHabdler(Integer id) {
    
    
        return "线程池:" + Thread.currentThread().getName() + " paymentInfo_TimeOutHabdler,id:" + id + "\t" +
                "系统繁忙,请稍后再试****o(╥﹏╥)o" ;
    }

Then add the annotation @HystrixCommand to the paymentInfo_TimeOut method that accesses the timeout in the business class for configuration. Once the call to the service method fails and an error message is thrown, it will automatically call the specified method in the fallbackMethod call class marked by @HystrixCommand.

The fallbackMethod attribute is the name of the downgrading method, which means that after a problem occurs in this method, this method paymentInfo_TimeOutHabdler will take care of it.
The commandProperties property is in the form of an array, and multiple properties can be set. Add the annotation @HystrixProperty, and then configure the properties of name and value inside. The name attribute is the thread timeoutInMilliseconds, and the value is the set peak time. The specific configuration is as follows:

@HystrixCommand(fallbackMethod = "paymentInfo_TimeOutHabdler",commandProperties = {
    
    
                @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
            } )
    public String paymentInfo_TimeOut(Integer id) {
    
    
        try {
    
    
            // 暂停2秒钟
            TimeUnit.MILLISECONDS.sleep(2000);
 
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        return "线程池:" + Thread.currentThread().getName() + " paymentInfo_TimeOut,id:" + id + "\t" +
                "O(∩_∩)O哈哈~  耗时(秒)";
  
  }

Then add the annotation @EnableCircuitBreaker to the main startup class to indicate the annotation added to the activation business class @HystrixCommand. As shown below:

package com.buba.springcloud;
 
import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
 
import javax.swing.*;
 
@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker//激活
public class PaymentHystrixMain8001 {
    
    
    public static void main(String[] args) {
    
    
 
        SpringApplication.run(PaymentHystrixMain8001.class, args);
    }
}

We restart the producer service 8001 and visit http://localhost:8001/payment/hystrix/timeout/1, which can be accessed normally

insert image description here

Next, we change the pause time in the business class from 2 seconds to 5 seconds, and the peak time is 3 seconds. If it exceeds the peak time, see if you can return to the paymentInfo_TimeOutHabdler method of the set Fallback, as shown in the figure below:

@HystrixCommand(fallbackMethod = "paymentInfo_TimeOutHabdler",commandProperties = {
    
    
                @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
            } )
    public String paymentInfo_TimeOut(Integer id) {
    
    
        try {
    
    
            // 暂停2秒钟
            TimeUnit.MILLISECONDS.sleep(5000);
 
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        return "线程池:" + Thread.currentThread().getName() + " paymentInfo_TimeOut,id:" + id + "\t" +
                "O(∩_∩)O哈哈~  耗时(秒)";
  
  }

After restarting, visit http://localhost:8001/payment/hystrix/timeout/1 again, and you can see that when the peak value is exceeded for 3 seconds, the service is downgraded, and it goes directly to the paymentInfo_TimeOut method we wrote. As shown below:

insert image description here

2. Abnormal service downgrade

Modify the method of paymentInfo_TimeOut in the business class, as shown in the figure below:

/**
     * 超时访问
     *
     * @param id
     * @return
     */
    @HystrixCommand(fallbackMethod = "paymentInfo_TimeOutHabdler",commandProperties = {
    
    
                @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
            } )
    public String paymentInfo_TimeOut(Integer id) {
    
         
       //异常错误的演示代码
       int age = 10/0;
       return "线程池:" + Thread.currentThread().getName() + " paymentInfo_TimeOut,id:" + id + "\t" +"O(∩_∩)O哈哈~  耗时(秒)" ;
  }

Then restart the service and visit http://localhost:8001/payment/hystrix/timeout/1 again. You can see that the service has been downgraded directly, and it goes directly to the paymentInfo_TimeOut method we wrote, as shown in the figure below:

insert image description here

We have now downgraded the service of the producer service 8001. Next, we will downgrade the service of the consumer service 80.
First, add the Hystrix dependency in the pom.xml file , as shown below:

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

Add the configuration of Hystrix in the yml configuration file, as shown below:

feign:
  hystrix:
    enabled: true

Add annotations to the main startup class @EnableCircuitBreakerto indicate the annotations added to the activation business class @HystrixCommand. As shown below:

package com.buba.springcloud;
 
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.cloud.openfeign.EnableFeignClients;
 
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
@EnableCircuitBreaker//回路
public class OrderHystrixMain {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(OrderHystrixMain.class, args);
    }
}

Then add annotations and related configurations to the OrderHystirxController business class, and then add the service downgrade method, as shown in the following figure:

    @GetMapping("/consumer/hystrix/timeout/{id}")
    @HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod", commandProperties = {
    
    
           @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", 
  value = "1000")
  })
      
    public String paymentInfo_TimeOut(@PathVariable("id") Integer id) {
    
    
        //int age = 10/0;
        return paymentHystrixService.paymentInfo_TimeOut(id);
    }
 
    //服务降级的兜底的方法
    public String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id) {
    
    
        return "我是消费者80,对方支付系统繁忙请10秒种后再试或者自己运行出错请检查自己,o(╥﹏╥)o";
    }

When accessing the consumer 80 service, it is necessary to ensure that the producer 8001 service can run normally without degraded services. Modify the producer 8001 service as follows:

/**
     * 超时访问
     *
     * @param id
     * @return
     */
    @HystrixCommand(fallbackMethod = "paymentInfo_TimeOutHabdler",commandProperties = {
    
    
                @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "5000")
            } )
    public String paymentInfo_TimeOut(Integer id) {
    
    
        try {
    
    
            // 暂停2秒钟
            TimeUnit.MILLISECONDS.sleep(2000);
 
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        return "线程池:" + Thread.currentThread().getName() + " paymentInfo_TimeOut,id:" + id + "\t" +
                "O(∩_∩)O哈哈~  耗时(秒)";
 
  }

Access the producer 8001 service, http://localhost:8001/payment/hystrix/timeout/1, without service downgrade, the success interface is as follows:
insert image description here

The producer 8001 service test has no problem, then the consumer 80 service, we have downgraded the service, because the producer service timeout method needs to wait until the pause is 2 seconds, and when we consume the 80 service to call the interface, we only wait for 1 second, all will be Consumer 80 service degradation occurs, as shown in the figure below:
insert image description here

Now both the producer 8001 service and the consumer 80 service have been downgraded, and there is no problem. But we can find the current problem. If each business corresponds to a bottom-up method, code expansion occurs. To solve this problem, if it is not a special business, we will use the global service downgrade method. If it is a special business, there must be a corresponding dedicated service downgrade method.

5. Optimize the code expansion problem

To start the integration, a global service downgrade method is required in the business class OrderHystirxController served by consumers 80, as shown in the figure below:

 /**
     * 全局fallback
     *
     * @return
     */
    public String payment_Global_FallbackMethod() {
    
    
        return "Global异常处理信息,请稍后重试.o(╥﹏╥)o";
    }

Then add the default global service downgrade method to the class, as shown in the figure below:
insert image description here

Then add annotations to the methods that require service degradation, as shown in the following figure:

@HystrixCommand//默认的fallback注解
public String paymentInfo_TimeOut(@PathVariable(“id”) Integer id) {
//int age = 10/0;
return paymentHystrixService.paymentInfo_TimeOut(id);
}

Now restart the consumer 80 service and visit http://localhost/consumer/hystrix/timeout/1 again. This method has used the global default service downgrade method and the following interface appears:

insert image description here

6. Chaotic integration of business logic and code

Regarding the downgrading of services, it is the consumer service that calls the producer service. If the producer service is down or shut down, then we have to downgrade the consumer service. It has nothing to do with the producer service. The value needs to be Feign customers Decoupling can be achieved by adding an implementation class for service degradation processing to the interface defined by the client. In order to prevent it from being mixed with business logic and code, it looks particularly confusing, so a new class PaymentFallbackService is created to implement the PaymentHystrixService interface of the business class, and the methods in the interface are unified for exception handling. As shown below:

package com.buba.springcloud.service;
 
import org.springframework.stereotype.Component;
 
@Component
    public class PaymentFallbackService implements PaymentHystrixService{
    
    
    @Override
    public String paymentInfo_OK(Integer id) {
    
    
        return "PaymentFallbackService fall  paymentInfo_OK 服务器出现故障,o(╥﹏╥)o";
    }
 
    @Override
    public String paymentInfo_TimeOut(Integer id) {
    
    
        return "PaymentFallbackService fall  paymentInfo_TimeOut 服务器出现故障,o(╥﹏╥)o";
    }
}

Also add the @FeignClient annotation to the PaymentHystrixService business class, indicating that the target of the FeignClient annotation is on the interface, as shown below:

package com.buba.springcloud.service;
 
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
 
@Component
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT",fallback = PaymentFallbackService.class)
//value属性是从该服务中获取,fallback属性当服务出现故障时,该类进行服务降级处理
public interface PaymentHystrixService {
    
    
 
    /**
     * 正常访问
     *
     * @param id
     * @return
     */
    @GetMapping("/payment/hystrix/ok/{id}")
    String paymentInfo_OK(@PathVariable("id") Integer id);
 
    /**
     * 超时访问
     *
     * @param id
     * @return
     */
    @GetMapping("/payment/hystrix/timeout/{id}")
    String paymentInfo_TimeOut(@PathVariable("id") Integer id);
 
}

Then we start the service, and http://localhost/consumer/hystrix/ok/1the method of access can be accessed successfully, as shown in the figure below:
insert image description here

Then we close the producer 8001 service, visit http://localhost/consumer/hystrix/ok/1 again, you can see that the service downgrade process is enabled, so that when the producer service is unavailable, the consumer service will also prompt information instead of Will hang and consume the server. As shown below:
insert image description here

It can be seen that the paymentInfo_OK method does not downgrade the configuration service, but when the producer service is closed, the service is also downgraded. Here, because we configure it in the PaymentFallbackService class, this solves the problem of mixing business logic and code .

@GetMapping("/consumer/hystrix/ok/{id}")
    String paymentInfo_OK(@PathVariable("id") Integer id){
    
    
        return  paymentHystrixService.paymentInfo_OK(id);
    }

Isn't it so easy to learn all the configurations!
insert image description here

Next articleContinue to learn service circuit breaker, continue to update, welcome to pay attention!

おすすめ

転載: blog.csdn.net/weixin_39570655/article/details/131810543
おすすめ