广告位联系
返回顶部
分享到

SpringCloud hystrix断路器与局部降级全面介绍

java 来源:互联网 作者:佚名 发布时间:2022-10-26 22:22:07 人浏览
摘要

服务降级 服务压力剧增的时候,根据当前的业务情况及流量对一些服务和页面有策略的降级,以此缓解服务器的压力,以保证核心任务的进行。同时保证部分甚至大分客户能得到正确的

服务降级

服务压力剧增的时候,根据当前的业务情况及流量对一些服务和页面有策略的降级,以此缓解服务器的压力,以保证核心任务的进行。同时保证部分甚至大分客户能得到正确的响应。也就是当前的请求处理不了或者出错了,给一个默认的返回。例如:双11降级产品评价等非核心功能,保证支持和订单的核心任务进行。

服务熔断

就是防止服务雪崩现象出现,是服务降级的一种特殊情况。

一、Hystrix的服务使用前的问题

1、ProductController 中方法异常和超时

在商品服务 ProductController 中的方法中增加异常和超时,ProductController 中方法修改如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

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、访问查看效果

访问http://localhost:9000/order/buy/1

访问http://localhost:9000/order/delete/1

订单服务中OrderController 中 调用商品服务 ProductController 中方法时,ProductController 中方法出现异常和超时,访问浏览器的异常结果和订单服务中的内部异常如下:

?

?

?

?

3、问题分析

在微服务架构中,我们将系统拆分成了一个个的服务单元,各单元应用间通过服务注册与订阅的方式互相依赖。由于每个单元都在不同的进程中运行,依赖通过远程调用的方式执行,这样就有可能因为网络原因或是依赖服务自身问题出现调用故障或延迟,而这些问题会直接导致调用方的对外服务也出现延迟,若此时调用方的请求不断增加,最后就会出现因等待出现故障的依赖方响应而形成任务积压,线程资源无法释放,最终导致自身服务的瘫痪,进一步甚至出现故障的蔓延最终导致整个系统的瘫痪。如果这样的架构存在如此严重的隐患,那么相较传统架构就更加的不稳定,如下图。

?

二、 商品服务 Hystrix的 局部降级

1、降级配置

注解 @HistrixCommand

在商品服务 ProductController 中的 findById( )和deleteOrderById( ) 方法上增加降级配置的注解 @HistrixCommand

—旦调用服务方法失败并抛出了超时或错误信息后,会自动调用@HystrixCommand标注好的fallbackMethod调用类中的指定方法。

在@HistrixCommand 指定超时或异常要回调的方法,同时可以指定配置参数,例如使用@HistrixCommand 中的属性commandProperties 指定默认超时时间,如:

fallbackMethod:指定回调方法是findByIdTimeout
commandProperties: 指定@HystrixProperty??? ?的默认值是默认超时时间是3s

@HystrixCommand(fallbackMethod = "findByIdTimeout", commandProperties = {
        @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
})

2、回调(兜底降级)方法

在商品服务ProductController 中增加回调方法findByIdTimeout( ) 和deleteOrderByIdException( ),当访问ProductController 中的 findById( )和deleteOrderById( ) 发生超时 或 异常时,会调用回调方法。

3、具体代码

降级配置 和回调(兜底降级)方法的具体代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

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、主启动类激活Hstrix

在商品服务的主启动类 ProductServerApplication 中使用注解@EnableCircuitBreaker 进行激活Hystrix,代码如下

1

2

3

4

5

6

7

8

9

10

11

12

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、进行测试

将商品服务中ProductController 和 ProductServerApplication复制到 其他所有 商品服务中,进行更新代码。

分别访问:http://localhost:9001/product/buy/1 和 http://localhost:9001/product/delete/1 查看超时和异常服务降级。看浏览器和内部结果。

?

?

三、 订单服务 Hystrix的 局部降级

1、降级配置

注解 @HistrixCommand

在订单服务 OrderController 中的方法上增加降级配置的注解 @HistrixCommand

2、回调(兜底降级)方法

在订单服务 OrderController 定义 回调方法 buyTimeout( Long id) 、deleteOrderException( Long id),并设置超时服务,超时服务要比将商品服务ProductController 中的 findById( ) 超时时间短。例如:ProductController 中的 findById( ) 超时时间是 3s ,则订单服务 OrderController 定义 回调方法 buyTimeout( ) 设定的超时时间应是 <3s 。

3、具体代码

降级配置 和回调(兜底降级)方法的具体代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

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、将商品服务中的超时时间为正常

将商品服务ProductController 中的 findById( ) 超时时间为正常,即程序超时时间是2s,熔断等待时间是3s,并且要比 订单服务 OrderController 定义 回调方法 buyTimeout( ) 中的熔断时间大,代码如下:

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

// 正常超时时间是 3s 比OrderController 中定义的超时时间长。

@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000") }) public Product findById(@PathVariable Long id) { 。。。。。

// 超时时间 2s

Thread.sleep(2000); 。。。。。

return product;

}

完整代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

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、主启动类激活Hstrix

在订单服务的主启动类 OrderServerApplication 中使用注解@EnableCircuitBreaker 或 注解@EnableHystrix进行激活Hystrix,注意:@EnableHystrix包括了注解@EnableCircuitBreaker ,代码如下

1

2

3

4

5

6

7

8

9

10

11

12

13

14

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、进行测试

分别访问:http://localhost:9000/order/buy/1 和 http://localhost:9000/order/delete/1 查看超时和异常服务降级。

?


版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。
原文链接 : https://blog.csdn.net/qq_41946216/article/details/127361815
相关文章
  • Spring Retry 重试实例详解

    Spring Retry 重试实例详解
    spring-retry是什么? spring-retry是spring提供的一个重试框架,原本自己实现的重试机制,现在spring帮封装好提供更加好的编码体验。 重试的使用
  • SpringCloud hystrix断路器与局部降级全面介绍

    SpringCloud hystrix断路器与局部降级全面介绍
    服务降级 服务压力剧增的时候,根据当前的业务情况及流量对一些服务和页面有策略的降级,以此缓解服务器的压力,以保证核心任务的进
  • SpringCloud hystrix断路器与全局解耦全面介绍

    SpringCloud hystrix断路器与全局解耦全面介绍
    第七章中在ProductController 和OrderController 中都使用了局部服务降级,但同时也导致两个问题, 通过观察两个局部降级的案例,可以发现: 每
  • SpringBoot自定义错误处理逻辑介绍

    SpringBoot自定义错误处理逻辑介绍
    1. 自定义错误页面 将自定义错误页面放在 templates 的 error 文件夹下,SpringBoot 精确匹配错误信息,使用 4xx.html 或者 5xx.html 页面可以打印错误
  • Java实现手写一个线程池的代码

    Java实现手写一个线程池的代码
    线程池技术想必大家都不陌生把,相信在平时的工作中没有少用,而且这也是面试频率非常高的一个知识点,那么大家知道它的实现原理和
  • Java实现断点续传功能的代码

    Java实现断点续传功能的代码
    题目实现:网络资源的断点续传功能。 二、解题思路 获取要下载的资源网址 显示网络资源的大小 上次读取到的字节位置以及未读取的字节
  • 你可知HashMap为什么是线程不安全的
    HashMap 的线程不安全 HashMap 的线程不安全主要体现在下面两个方面 在 jdk 1.7 中,当并发执行扩容操作时会造成环形链和数据丢失的情况 在
  • ArrayList的动态扩容机制的介绍

    ArrayList的动态扩容机制的介绍
    对于 ArrayList 的动态扩容机制想必大家都听说过,之前的文章中也谈到过,不过由于时间久远,早已忘却。 所以利用这篇文章做做笔记,加
  • JVM基础之字节码的增强技术介绍

    JVM基础之字节码的增强技术介绍
    字节码增强技术 在上文中,着重介绍了字节码的结构,这为我们了解字节码增强技术的实现打下了基础。字节码增强技术就是一类对现有字
  • Java中的字节码增强技术

    Java中的字节码增强技术
    1.字节码增强技术 字节码增强技术就是一类对现有字节码进行修改或者动态生成全新字节码文件的技术。 参考地址 2.常见技术 技术分类 类
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计