06 熔断器Hystrix

本文详细介绍了Hystrix作为服务容错管理工具如何实现服务熔断和降级,以防止雪崩效应。通过线程隔离和熔断机制,Hystrix在服务故障时提供链路保护。同时,文章演示了服务consumer-demo的配置和测试,展示了在服务不可用时如何执行降级策略并恢复服务。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Hystrix是一个延迟和容错库,用于隔离访问远程服务,防止出现级联失败。
Hystrix解决雪崩效应:

  • 线程隔离:用户请求不直接访问服务,而是使用线程池中空闲的线程访问服务,加速失败判断时间。
  • 服务降级:及时返回服务调用失败的结果,让线程不因为等待服务而阻塞。
服务熔断
  • 熔断机制的注解是@HystrixCommand;启动类添加@EnableCircuitBreaker
  • 熔断机制是应对雪崩效应的一种【链路保护机制】,一般存在于服务端;
  • 当扇出链路的某个服务出现故障或响应超时,会进行【服务降级】,进而【熔断该节点的服务调用】,快速返回“错误”的相应信息(就是出现服务故障的预选方案),当检测到该节点微服务正常后,就恢复该节点的调用。
  • Hystrix的熔断存在阈值,缺省是5秒内20次调用失败就会触发;
    一般是某个服务故障或者异常引起,类似显示世界中的“保险丝”,当某个异常条件被触发,直接熔断整个服务,而不是一直等到此服务超时。
服务consumer-demo
导入坐标
  • pom.xml
<?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>springcloud_parent</artifactId>
        <groupId>li.chen.com</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>consumer_demo</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
    </dependencies>
</project>
配置文件
  • application.yml
spring:
  application:
    name: consumer_demo

eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka

    # 获取服务地址列表间隔时间,默认30秒
    registry-fetch-interval-seconds: 10

springboot启动类
  • ConsumerApplication
package li.chen.com.consumer;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@EnableDiscoveryClient   //开启Eureka客户端发现功能
@SpringBootApplication
@EnableCircuitBreaker  //开启服务熔断hystrix
public class ConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class,args);
    }

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

}

各层文件

pojo层

  • User
package li.chen.com.consumer.pojo;

import lombok.Data;

import java.util.Date;

/**
 * @ClassName: User
 * @Description 接收数据,不进行数据库交互,故不需要加user_service里的那些注解
 **/
@Data
public class User {

    private Integer id;

    private String userName;

    private String passWord;

    private Date birthday;
}

controller层

  • UserController
package li.chen.com.consumer.controller;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import javafx.beans.DefaultProperty;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.List;

@RestController
@RequestMapping("/ConsumerController")
public class ConsumerController {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private DiscoveryClient discoveryClient;

    @GetMapping("/{id}")
    @HystrixCommand(fallbackMethod = "queryByIdFallback")  //服务熔断后调用方法
    public String queryById(@PathVariable Long id) {
        String url = "http://UserService/UserController/" + id;
        return restTemplate.getForObject(url, String.class);
    }

    public String queryByIdFallback(@PathVariable Long id){
        return "对不起,网络太拥挤了!" + id;
    }

}

    /*
    注意:fallbackMethod 中的方法传参与返回值类型,必须与此注解的传参与返回值类型一致 ;
    否则一直报错
     com.netflix.hystrix.contrib.javanica.exception.FallbackDefinitionException: Incompatible return types. 
     */

在这里插入图片描述

测试

启动 EurekaServerApplication
启动UserApplication9090
启动 ConsumerApplication
访问 http://localhost:8080/ConsumerController/2
在这里插入图片描述

访问成功后 关闭UserApplication9090,
再次访问 http://localhost:8080/ConsumerController/2 //服务熔断–》不再请求UserApplication9090服务
在这里插入图片描述

服务降级
  • 当系统整体资源快不够的时候,忍痛将部分服务暂时关闭,待渡过难关后,再重新开启。
  • 降级处理是在【客户端】完成的,与服务端没有关系。
  • 降级针对的是服务熔断之后处理。
  • 降级一般是从【整体负荷】考虑,当某个服务熔断之后,服务器将不再被调用,此时客户端可以自己准备一个本地的FallBack回调, 返回 一个缺省值。这样做虽然服务水平下降,但好歹可用,比直接挂掉好。

如果按照上面的熔断案例来做的话,Controller下的每个方法,都要给其编写一个FallBack方法,当方法慢慢变多,就会造成代码膨胀,一个是增加编写的工作量,另外一个也会增大维护的难度,代码的耦合度也会高,是十分不合理的,所以要将其解耦。

因为服务端的是通过实现接口访端的,如果在父接口上实现了FallBack方法,通过这样一种方式去维护起来就能实现解耦,也顺便完成了降级的机制。

配置文件
  • application.yml
spring:
  application:
    name: consumer_demo

eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka

    # 获取服务地址列表间隔时间,默认30秒
    registry-fetch-interval-seconds: 10

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
          #  服务提供者的超时时间,2秒,如果请求服务提供者超过2秒,就服务降级和线程隔离
            timeoutInMilliseconds: 2000 
      circuitBreaker:
        errorThresholdPercentage: 50 # 触发熔断错误比例阈值,默认值50%
        sleepWindowInMilliseconds: 10000 # 熔断后休眠时长,默认值5秒
        requestVolumeThreshold: 10 # 熔断触发最小请求次数,默认值是20
  circuitBreaker:
    # 10次请求有5次是失败,就熔断,熔断后,每隔10秒,就打开半开状态
    # 如果半开状态,能访问服务提供者,关闭熔断,否则每隔10秒进行检测
    errorThresholdPercentage: 90 # 触发熔断错误比例阈值,默认值50%
    sleepWindowInMilliseconds: 10000 # 熔断后休眠时长,默认值5秒
    requestVolumeThreshold: 10 # 熔断触发最小请求次数,默认值是20

controller层

  • UserController
package li.chen.com.consumer.controller;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import javafx.beans.DefaultProperty;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.List;

@RestController
@RequestMapping("/ConsumerController")
@DefaultProperties(defaultFallback = "defaultFallback")
public class ConsumerController {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private DiscoveryClient discoveryClient;

    @GetMapping("/{id}")
    @HystrixCommand
    public String queryById(@PathVariable Long id) {
        if (id == 1) {
            throw new RuntimeException("太忙了");
        }

        String url = "http://UserService/UserController/" + id;
        return restTemplate.getForObject(url, String.class);
    }

    public String defaultFallback(){
        return "默认提示:对不起,网络太拥挤了!";
    }
}

测试

启动 EurekaServerApplication
启动 UserApplication9090
启动 ConsumerApplication
访问 http://localhost:8080/ConsumerController/1
在这里插入图片描述
访问 http://localhost:8080/ConsumerController/2
在这里插入图片描述
服务降级:访问 http://localhost:8080/ConsumerController/1 20次后,
再访问http://localhost:8080/ConsumerController/2 服务降级,直接调用降级的方法
在这里插入图片描述

Hystrix状态

在这里插入图片描述
Closed:关闭状态

  • 断路器关闭,所有请求都正常访问。

Open:打开状态

  • 断路器打开,所有请求都会被降级。
  • Hystrix会对请求情况计数,当一定时间内失败请求百分比达到阈值,则触发熔断,断路器会完全打开。
  • 默认
    • 失败比例的阈值是50%
    • 请求次数最少不低于20次。

Half Open:半开状态

  • 不是永久的,断路器打开后会进入休眠时间(默认是5S)。随后断路器会自动进入半开状态。此时会释放部分请求通过,若这些请求都是健康的,则会关闭断路器,否则继续保持打开,再次进行休眠计时。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

岿然如故

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值