Chapter 7 Detailed Explanation of Hystrix Circuit Breaker - Partial Downgrade of Service Downgrade

Continue to Chapter Six 

service downgrade

       When the service pressure increases sharply, some services and pages are strategically downgraded according to the current business situation and traffic, so as to relieve the pressure on the server and ensure the progress of core tasks. At the same time, it is guaranteed that some or even most customers can get the correct response. That is, if the current request cannot be processed or an error occurs, a default return is given. For example: non-core functions such as double 11 downgrade product evaluation, to ensure that the core tasks of support and orders are carried out.

Service circuit breaker

       It is to prevent the phenomenon of service avalanche, which is a special case of service degradation.

1.  Problems before using Hystrix's service

1. Method exception and timeout in ProductController

      Add exceptions and timeouts to the methods in the product service ProductController, and modify the methods in ProductController as follows:

package com.hwadee.springcloud.controller;
import com.hwadee.springcloud.entity.Product;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.math.BigDecimal;

@RestController
@RequestMapping("/product")
public class ProductController {
    //方便后面讲负载均衡,查看ip,此处获取配置中的端口号和ip
    @Value("${server.port}")
    private String port;
    @Value("${spring.cloud.client.ip-address}")
    private String ip;

    @RequestMapping("/buy/{id}")
    public Product findById(@PathVariable Long id) {
        Product product = new Product();
        product.setId(id);
        // 后面需要测试负载均衡,所以返回 ip 地址及端口号
        product.setName("当前访问商品服务地址:" + ip + ":" + port+"  "+"查询商品订单,订单号:"+id);
        product.setPrice(new BigDecimal(10000.0));
        System.out.println(product);

        //测试超时熔断
        try {
            Thread.sleep(5000);
            //测试并发熔断
            //Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        return product;
    }

    @RequestMapping(value = "/delete/{id}")
    public Product deleteOrderById(@PathVariable Long id){
        Product product = new Product();
        product.setId(id);
        // 后面需要测试负载均衡,所以返回 ip 地址及端口号
        product.setName("当前访问商品服务地址:" + ip + ":" + port+"  "+"从购物车删除订单,订单号:"+id);
        product.setPrice(new BigDecimal(10000.0));
        System.out.println(product);

        //测试异常熔断
        System.out.println(10/0);

        return product;
    }

}

2. Access to view the effect

      Visit  http://localhost:9000/order/buy/1

      Visit  http://localhost:9000/order/delete/1

      When the method in the product service ProductController is called in the OrderController in the order service, the method in the ProductController is abnormal and timed out. The abnormal result of accessing the browser and the internal exception in the order service are as follows:

3. Problem Analysis

  In the microservice architecture, we split the system into service units one by one, and the applications of each unit depend on each other through service registration and subscription. Since each unit runs in a different process, and the dependencies are executed through remote calls, there may be call failures or delays due to network reasons or the problems of the dependent services themselves, and these problems will directly cause delays in the external services of the caller. If the caller’s requests continue to increase at this time, there will be a backlog of tasks due to waiting for the response of the failed dependent party, and thread resources cannot be released, which eventually leads to the paralysis of its own services, and even the spread of faults eventually leads to the paralysis of the entire system. If such a structure has such serious hidden dangers, it will be more unstable than the traditional structure, as shown in the figure below.

 2. Partial downgrade of commodity service Hystrix

1. Downgrade configuration

     Annotation @HistrixCommand

     Add the downgrade configuration annotation @HistrixCommand to the findById( ) and deleteOrderById( ) methods in the commodity service ProductController

   —Once the call to the service method fails and a timeout or error message is thrown, it will automatically call the specified method in the fallbackMethod call class marked by @HystrixCommand.

   In @HistrixCommand, specify the method to be called back by timeout or exception, and you can also specify configuration parameters, for example, use the attribute commandProperties in @HistrixCommand to specify the default timeout time, such as:

fallbackMethod: Specify the callback method is findByIdTimeout
 commandProperties: Specify @HystrixProperty ​​​​The default value is the default timeout is 3s @HystrixCommand(fallbackMethod = "findByIdTimeout", commandProperties = { 
        @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = " 3000") } 
)


2. Callback (downgrade) method

Add callback methods findByIdTimeout( ) and  deleteOrderByIdException( )      in product service ProductController , when timeout or exception occurs when accessing findById( ) and deleteOrderById( ) in ProductController, the callback method will be called.

3. Specific code

     The specific code of the downgrade configuration and callback (downgrade) method is as follows:

import com.hwadee.springcloud.entity.Product;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;

@RestController
@RequestMapping("/product")
public class ProductController {
    //方便后面讲负载均衡,查看ip,此处获取配置中的端口号和ip
    @Value("${server.port}")
    private String port;
    @Value("${spring.cloud.client.ip-address}")
    private String ip;

    @RequestMapping("/buy/{id}")
    @HystrixCommand(fallbackMethod = "findByIdTimeout", commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
    })
    public Product findById(@PathVariable Long id) {
        Product product = new Product();
        product.setId(id);
        // 后面需要测试负载均衡,所以返回 ip 地址及端口号
        product.setName("当前访问商品服务地址:" + ip + ":" + port + "  " + "查询商品订单,订单号:" + id);
        product.setPrice(new BigDecimal(50000.0));
        System.out.println(product);

        //测试超时熔断
        try {
            Thread.sleep(5000);
            //测试并发熔断
            //Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        return product;
    }

    @RequestMapping(value = "/delete/{id}")
    @HystrixCommand(fallbackMethod = "deleteOrderByIdException")
    public Product deleteOrderById(@PathVariable Long id) {
        Product product = new Product();
        product.setId(id);
        // 后面需要测试负载均衡,所以返回 ip 地址及端口号
        product.setName("当前访问商品服务地址:" + ip + ":" + port + "  " + "从购物车删除订单,订单号:" + id);
        product.setPrice(new BigDecimal(10000.0));
        System.out.println(product);

        //测试异常熔断
        System.out.println(10 / 0);

        return product;
    }

    public Product findByIdTimeout(Long id) {
        Product product = new Product();
        product.setId(id);
        product.setName("当前访问商品服务地址:" + ip + ":" + port + "  " + "访问 超时 进行降级服务");
        product.setPrice(new BigDecimal(10000.0));
        System.out.println(product);
        return product;
    }

    public Product deleteOrderByIdException(Long id) {
        Product product = new Product();
        product.setId(id);
        product.setName("当前访问商品服务地址:" + ip + ":" + port + "  " + "访问 异常 进行降级服务");
        product.setPrice(new BigDecimal(10000.0));
        System.out.println(product);
        return product;
    }
}

4. The main startup class activates Hstrix

Use the annotation @EnableCircuitBreaker to activate Hystrix      in the main startup class ProductServerApplication of the commodity service , the code is as follows

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;

@SpringBootApplication
@EnableEurekaClient// 启动 eureka 客户端
@EnableCircuitBreaker // 主启动类激活 Hystrix
public class ProductServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProductServerApplication.class, args);
    }
}

5. Test

     Copy the ProductController and ProductServerApplication in the product service to all other product services to update the code.

     Visit respectively: http://localhost:9001/product/buy/1 and http://localhost:9001/product/delete/1 to view timeout and abnormal service degradation. Look at the browser and internal results.

3. Partial downgrade of order service Hystrix

1. Downgrade configuration

     Annotation @HistrixCommand

     Add the downgrade configuration annotation @HistrixCommand to the method in the order service OrderController

2. Callback (downgrade) method

    Define the callback methods buyTimeout(Long id) and deleteOrderException(Long id) in the order service OrderController, and set the timeout service, which is shorter than the timeout period of findById( ) in the product service ProductController. For example: the timeout time of findById( ) in ProductController is 3s, then the timeout time set by the callback method buyTimeout( ) defined in the order service OrderController should be <3s.

3. Specific code

     The specific code of the downgrade configuration and callback (downgrade) method is as follows:

import com.hwadee.springcloud.entity.Product;
import com.hwadee.springcloud.service.IOrderFeignService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/order")
public class OrderController {
    @Autowired
    IOrderFeignService orderFeignService;

    @RequestMapping("/buy/{id}")
    @HystrixCommand(fallbackMethod = "buyTimeout", commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")
    })
    public Product buy(@PathVariable Long id) {
        System.out.println("进入OrderController的buy方法, orderFeignService 准备调用远端接口 findById");
        Product product = orderFeignService.findOrderById(id);
        return product;
    }

    @RequestMapping(value = "/delete/{id}")
    @HystrixCommand(fallbackMethod = "deleteOrderException")
    public Product deleteOrderById(@PathVariable Long id) {
        System.out.println("进入OrderController的deleteOrderById方法, orderFeignService 准备调用远端接口deleteOrderById");
        Product product = orderFeignService.deleteOrderById(id);
        int i =10/0;
        return product;
    }

    public Product buyTimeout( Long id) {
        Product product = new Product();
        product.setId(id);
        product.setName("当前订单服务访问/order/buy/1 超时:"+id);
        return product;
    }

    public Product deleteOrderException( Long id) {
        Product product = orderFeignService.deleteOrderById(id);
        product.setName("当前订单服务访问/order/delete/1 10/0异常:"+id);
        return product;
    }

}

4. Set the timeout period in the commodity service to normal

      Set the timeout time of findById( ) in the commodity service ProductController to normal, that is, the program timeout time is 2s, and the fuse waiting time is 3s, which is longer than the fuse time in the callback method buyTimeout( ) defined in the order service OrderController. The code is as follows:

    @HystrixCommand(fallbackMethod = "findByIdTimeout", commandProperties = {

           // The normal timeout is 3s longer than the timeout defined in OrderController.
            @HystrixProperty(name = "execution. isolation. thread. timeoutInMilliseconds", value = "3000")
    })
    public Product findById(@PathVariable Long id) {      . . . . .

             // Timeout 2s Thread.sleep( 2000);        . . . . .
           

        return product;
    }

The complete code is as follows:

import com.hwadee.springcloud.entity.Product;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.math.BigDecimal;

@RestController
@RequestMapping("/product")
public class ProductController {
    //方便后面讲负载均衡,查看ip,此处获取配置中的端口号和ip
    @Value("${server.port}")
    private String port;
    @Value("${spring.cloud.client.ip-address}")
    private String ip;

    @RequestMapping("/buy/{id}")
    @HystrixCommand(fallbackMethod = "findByIdTimeout", commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
    })
    public Product findById(@PathVariable Long id) {
        Product product = new Product();
        product.setId(id);
        // 后面需要测试负载均衡,所以返回 ip 地址及端口号
        product.setName("当前访问商品服务地址:" + ip + ":" + port + "  " + "查询商品订单,订单号:" + id);
        product.setPrice(new BigDecimal(10000.0));
        System.out.println(product);

        //测试超时熔断
        try {
            Thread.sleep(5000);
            //测试并发熔断
            //Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        return product;
    }

    @RequestMapping(value = "/delete/{id}")
    @HystrixCommand(fallbackMethod = "deleteOrderByIdException")
    public Product deleteOrderById(@PathVariable Long id) {
        Product product = new Product();
        product.setId(id);
        // 后面需要测试负载均衡,所以返回 ip 地址及端口号
        product.setName("当前访问商品服务地址:" + ip + ":" + port + "  " + "从购物车删除订单,订单号:" + id);
        product.setPrice(new BigDecimal(10000.0));
        System.out.println(product);

        //测试异常熔断
        System.out.println(10 / 0);

        return product;
    }

    public Product findByIdTimeout(Long id) {
        Product product = new Product();
        product.setId(id);
        product.setName("当前访问商品服务地址:" + ip + ":" + port + "  " + "访问 超时 进行降级服务");
        product.setPrice(new BigDecimal(10000.0));
        System.out.println(product);
        return product;
    }

    public Product deleteOrderByIdException(Long id) {
        Product product = new Product();
        product.setId(id);
        product.setName("当前访问商品服务地址:" + ip + ":" + port + "  " + "访问 异常 进行降级服务");
        product.setPrice(new BigDecimal(10000.0));
        System.out.println(product);
        return product;
    }

}

5. The main startup class activates Hstrix

Use the annotation @EnableCircuitBreaker or the annotation @EnableHystrix      in the main startup class OrderServerApplication of the order service to activate Hystrix. Note: @EnableHystrix includes the annotation @EnableCircuitBreaker , the code is as follows

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.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableEurekaClient// 启动 eureka 客户端
@EnableFeignClients  // 启动 feign
@EnableCircuitBreaker // 或 @EnableHystrix  启动 Hystrix
public class OrderServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderServerApplication.class, args);
    }
}

6. Test    

     Visit respectively: http://localhost:9000/order/buy/1 and http://localhost:9000/order/delete/1 to view timeout and abnormal service degradation.

Chapter 6: Detailed explanation of Hystrix circuit breaker + environment construction

Chapter 8: Detailed Explanation of Hystrix Circuit Breaker - Global Service Downgrade of Service Downgrade

Guess you like

Origin blog.csdn.net/qq_41946216/article/details/127361815