(八)hystrix-服务熔断和降级

微服务调用链

微服务很多的情况下,调用链也会特别长。其中某个服务出现问题,很可能会导致整个微服务不可用。这种情况下,就需要将出现问题的服务隔离开来,就好比现在发现哪里有新冠疫情,就得赶紧隔离,防止传播给其他人。
在这里插入图片描述
上图中,日志服务调用分析服务,当分析服务不可用时,采取熔断。分析服务可以提供一个备用的机制如返回一个空对象,这就是服务的降级。

hystrix的熔断和降级

提供容错机制,避免微服务系统雪崩。
一、手动模拟服务异常
还是采用前面几章节的案例,假设用户服务调用订单服务出现异常,这里我手动模拟一个空指针异常,然后使用hystrix的熔断和降级。

  1. pom.xml引入hystrix依赖包。
 <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
 </dependency>
  1. 订单服务OrderController.java
@RestController
public class OrderController implements OrderControllerApi {

    @Value("${server.port}")
    private String port;
	
	// 当该方法出现异常不可用时,触发熔断,走降级方法。
    @HystrixCommand(fallbackMethod = "findOrderListFallBack")
    @Override
    public JSONArray findOrderList() throws Exception {
        // 1.手动触发异常
        int a = 9 / 0;

        JSONArray orderList = new JSONArray();
        JSONObject o1 = new JSONObject();
        o1.put("ordNo", "001");
        o1.put("ordName", "鼠标");
        JSONObject o2 = new JSONObject();
        o2.put("ordNo", "002");
        o2.put("ordName", "键盘");
        JSONObject o3 = new JSONObject();
        o3.put("port", port);
        System.out.println("port=" + port);
        orderList.add(o1);
        orderList.add(o2);
        orderList.add(o3);
        return orderList;
    }

    /**
     * 订单服务降级方法
     *
     * @return
     * @throws Exception
     */
    public JSONArray findOrderListFallBack() throws Exception {
        System.out.println("进入降级方法findOrderListFallBack...");
        JSONArray orderList = new JSONArray();
        JSONObject o3 = new JSONObject();
        o3.put("port", port);
        System.out.println("port=" + port);
        orderList.add(o3);
        return orderList;
    }


    @Autowired
    public String hello() {
        return "hello order!!!";
    }

}

3.订单服务启动类ApplicationOrder.java开启熔断机制。

@SpringBootApplication
@EnableEurekaClient // 开启eureka client 注册到server中
@EnableCircuitBreaker // 开启Hystrix的熔断机制
public class ApplicationOrder {

    public static void main(String[] args) {
        SpringApplication.run(ApplicationOrder.class, args);
    }

}
  1. postman调用结果。
    在这里插入图片描述
  2. 订单服务控制台日志。
    在这里插入图片描述

三、模拟调用超时异常

  1. 订单服务OrderController.java
@RestController
public class OrderController implements OrderControllerApi {

    @Value("${server.port}")
    private String port;

    // 当该方法出现异常不可用时,触发熔断,走降级方法。
    @HystrixCommand(fallbackMethod = "findOrderListFallBack")
    @Override
    public JSONArray findOrderList() throws Exception {
        // 1.手动触发异常
//        int a = 9 / 0;

        // 2.调用超时
        Thread.sleep(6000);

        JSONArray orderList = new JSONArray();
        JSONObject o1 = new JSONObject();
        o1.put("ordNo", "001");
        o1.put("ordName", "鼠标");
        JSONObject o2 = new JSONObject();
        o2.put("ordNo", "002");
        o2.put("ordName", "键盘");
        JSONObject o3 = new JSONObject();
        o3.put("port", port);
        System.out.println("port=" + port);
        orderList.add(o1);
        orderList.add(o2);
        orderList.add(o3);
        return orderList;
    }

    /**
     * 订单服务降级方法
     *
     * @return
     * @throws Exception
     */
    public JSONArray findOrderListFallBack() throws Exception {
        System.out.println("进入降级方法findOrderListFallBack...");
        JSONArray orderList = new JSONArray();
        JSONObject o3 = new JSONObject();
        o3.put("port", port);
        System.out.println("port=" + port);
        orderList.add(o3);
        return orderList;
    }


    @Autowired
    public String hello() {
        return "hello order!!!";
    }

}
  1. 订单服务application.yml配置
############################################################
#
# 订单微服务
# web访问端口号  约定:8002
#
############################################################
server:
  # 动态设置端口号,方便部署集群
  port: ${port:8002}
  tomcat:
    uri-encoding: UTF-8

############################################################
#
# 配置项目信息
#
############################################################
spring:
  application:
    name: order

############################################################
#
# eureka配置信息
#
############################################################
eureka:
  server:
    hostname: localhost
    port: 7000
  client:
    # 所有的微服务都必须注册到eureka中
    register-with-eureka: true
    # 从注册中心获得检索服务实例,用户服务需要配置为true
    # 用户服务要去获得其他服务的实例,然后去调用
    fetch-registry: true
    # 注册中心的服务地址
    service-url:
#      defaultZone: http://${eureka.server.hostname}:${eureka.server.port}/eureka/
      # 订单服务注册到eureka集群中
      defaultZone: http://eureka-cluster-7001:7001/eureka/,http://eureka-cluster-7002:7002/eureka/,http://eureka-cluster-7003:7003/eureka/
  instance:
    lease-renewal-interval-in-seconds: 3 # 调整微服务(eureka-client)和注册中心(eureka-server)之间的心跳时间
    lease-expiration-duration-in-seconds: 5 # eureka距离最近的一次心跳等待剔除的时间(假设是3s发送一次心跳,但是某次3s后eureka没有收到心跳,则距离上次心跳5s后,eureka会剔除该节点)默认90s,当前设置为5s


# 配置hystrix
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 2000   # 设置hystrix超时时间,超过2秒触发降级


其余配置同“手动模拟服务异常”步骤1、3、4、5。
hystrix超时时间设置为2s,但是方法里sleep了6s,所以超过了2s,触发服务降级。

二、模拟服务端直接挂掉了
由于服务端直接挂掉了,所以没法在服务端降级了。客户端访问后永远都是报错500。这时候,就需要采用客户端的降级策略,具体的看下面客户端降级的介绍。

全局降级

上面的OrderController对方法findOrderList指定了降级方法,假设还有100个方法都需要做同样的降级,那么每个方法都需要配置一遍。可以统一配置全局的降级方法,如果某个方法没有指定特定的降级方法,那么就采用默认的全局降级方法。

  1. OrderController.java
@RestController
// 配置全局降级方法
@DefaultProperties(defaultFallback = "defaultFallback")
public class OrderController implements OrderControllerApi {

    // 当该方法出现异常不可用时,触发熔断,走降级方法。
    @HystrixCommand
    @Override
    public JSONArray findOrderList() throws Exception {
        // 1.手动触发异常
//        int a = 9 / 0;

        // 2.调用超时
        Thread.sleep(5000);

        JSONArray orderList = new JSONArray();
        JSONObject o1 = new JSONObject();
        o1.put("ordNo", "001");
        o1.put("ordName", "鼠标");
        JSONObject o2 = new JSONObject();
        o2.put("ordNo", "002");
        o2.put("ordName", "键盘");
        JSONObject o3 = new JSONObject();
        o3.put("port", port);
        System.out.println("port=" + port);
        orderList.add(o1);
        orderList.add(o2);
        orderList.add(o3);
        return orderList;
    }

    /**
     * 订单服务全局降级方法
     *
     * @return
     * @throws Exception
     */
    public JSONArray defaultFallback() throws Exception {
        System.out.println("进入全局降级方法defaultFallback...");
        JSONArray orderList = new JSONArray();
        JSONObject o3 = new JSONObject();
        o3.put("status", 500);
        o3.put("msg", "系统繁忙,请稍后再试");
        orderList.add(o3);
        return orderList;
    }


    @Autowired
    public String hello() {
        return "hello order!!!";
    }

}
  1. postman调用结果。
    在这里插入图片描述

客户端降级

用户服务(客户端)调用订单服务(服务端),如果订单服务发生了异常,则可以直接走服务端降级。但是,如果订单服务直接挂掉了,则服务不可用,这时候就需要走客户端降级。

  1. 用户服务UserController.java
@RestController
public class UserController implements UserControllerApi {
    @Autowired
    private OrderControllerApi orderControllerApi;

    @HystrixCommand(fallbackMethod = "findOrderListFallback", commandProperties =
            {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",
                    value = "1500")})
    //name:属性名      value:属性值(当控制器运行时间超过该值时,将会进入降级方法)
    @Override
    public JSONArray findOrderList() throws Exception {
        // 发起调用订单服务
        JSONArray result = orderControllerApi.findOrderList();
        return result;
    }

    /**
     * 客户端降级方法
     *
     * @return
     * @throws Exception
     */
    public JSONArray findOrderListFallback() throws Exception {
        JSONArray orderList = new JSONArray();
        JSONObject o3 = new JSONObject();
        o3.put("status", 500);
        o3.put("msg", "系统繁忙,请稍后再试");
        o3.put("des", "客户端降级");
        orderList.add(o3);
        return orderList;
    }

    @Override
    public String hello() {
        return "hello user!!!";
    }
}
  1. 用户服务application.yml配置,打开feign客户端的内置hystrix。
# 配置feign
feign:
  client:
    config:
      # 配置服务提供方的名称
      order:
        loggerLevel: FULL
  hystrix:
    enabled: true   # 打开feign客户端的内置hystrix
  1. 用户服务ApplicationUser.java,开启hystrix。
@SpringBootApplication
@EnableEurekaClient // 开启eureka client 注册到server中
@EnableFeignClients({"com.ft"}) // 开启feign,别标明调用的api在哪个包下
@EnableHystrix  // 开启hystrix
public class ApplicationUser {

    public static void main(String[] args) {
        SpringApplication.run(ApplicationUser.class, args);
    }

}

4.postman测试,首先开启用户服务和订单服务,发起调用,由于超时会触发服务端降级。
在这里插入图片描述
此时,断掉订单服务,发起调用,由于订单服务500,触发客户端降级。
在这里插入图片描述

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值