spring cloud(学习)--Hystrix

本文详细介绍了Spring Cloud Hystrix在服务雪崩场景下的应用,包括Hystrix的介绍、服务熔断机制、代码实现服务熔断以及服务降级的处理。通过示例展示了如何在服务提供者和服务消费者端配置和使用Hystrix,以实现服务的高可用性和弹性。

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

1.服务雪崩

2、Hystrix介绍

  • Hystrix 是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时、异常等,Hystrix 能够保证在一个依赖出问题的 情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。 
  • “断路器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个符合预期的、可处理的备选响应 (FallBack),而不是长时间的等待或者抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要地占用,从而避免了故障在分布式系统中的蔓延, 乃至雪崩。
  • Hytrix 能够提供服务降级、服务熔断、服务限流、接近实时的监控等方面的功能。


    3、服务熔断机制
  • 熔断机制是应对雪崩效应的一种微服务链路保护机制。 当扇出链路的某个微服务不可用或者响应时间太长时,会进行服务的降级,进而熔断该 节点微服务的调用,快速响应错误信息。当检测到该节点微服务调用响应正常后恢复调用链 路。在 SpringCloud 框架里熔断机制通过 Hystrix 实现。Hystrix 会监控微服务间调用的状况,当失败的调用到一定阈值,缺省是 5 秒内 20 次调用失败就会启动熔断机制。熔断机制的注解是@HystrixCommand。

    4.熔断-代码部分
    熔断指的是provider方的熔断,如果provider方出现的问题,熔断后别的就不在调用这个方法。
    1. provider工程中添加依赖
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>
    2. 在provider主启动类上添加 @EnableCircuitBreaker 注解
    /**
     * @date: 
     * @author: 
     * 下面两个注解功能大致相同,但是这个版本不需要添加
     *      @EnableDiscoveryClient: 启用发现服务功能,不局限于Eureka注册中心
     *      @EnableEurekaClient: 启用Eureka客户端功能,必须是Eureka注册中心
     *
     * @EnableCircuitBreaker: 启用断路器功能【服务熔断】
     */
     
    @EnableCircuitBreaker
    @SpringBootApplication
    public class ApplicationProvider {
        public static void main(String[] args) {
            SpringApplication.run(ApplicationProvider.class);
        }
    }
    
    3. common 工程中添加一个 ResultEntity ,统一作为AJAX请求和远程服务调用返回值
    package com.atguigu.spring.cloud.util;
    
    /**
     * 整个项目统一使用这个类型作为Ajax请求或远程方法调用返回响应的数据格式
     * @author 
     *
     * @param <T>
     */
    public class ResultEntity<T> {
            
            public static final String SUCCESS = "SUCCESS";
            public static final String FAILED = "FAILED";
            public static final String NO_MESSAGE = "NO_MESSAGE";
            public static final String NO_DATA = "NO_DATA";
            
            /**
             * 操作成功,不需要返回数据
             * @return
             */
            public static ResultEntity<String> successWithoutData() {
                    return new ResultEntity<String>(SUCCESS, NO_MESSAGE, NO_DATA);
            }
            
            /**
             * 操作成功,需要返回数据
             * @param data
             * @return
             */
            public static <E> ResultEntity<E> successWithData(E data) {
                    return new ResultEntity<>(SUCCESS, NO_MESSAGE, data);
            }
            
            /**
             * 操作失败,返回错误消息
             * @param message
             * @return
             */
            public static <E> ResultEntity<E> failed(String message) {
                    return new ResultEntity<>(FAILED, message, null);
            }
            
            private String result;
            private String message;
            private T data;        
            public ResultEntity() {
                    
            }
            public ResultEntity(String result, String message, T data) {
                    super();
                    this.result = result;
                    this.message = message;
                    this.data = data;
            }
            @Override
            public String toString() {
                    return "ResultEntity [result=" + result + ", message=" + message + ", data=" + data + "]";
            }
            public String getResult() {
                    return result;
            }
            public void setResult(String result) {
                    this.result = result;
            }
            public String getMessage() {
                    return message;
            }
            public void setMessage(String message) {
                    this.message = message;
            }
            public T getData() {
                    return data;
            }
            public void setData(T data) {
                    this.data = data;
            }
    
    }

    4. provider工程中的controller方法

    /**
     * @HystrixCommand 注解通过 fallbackMethod属性指定断路情况下要调用的备用方法
     * @param name
     * @return
     */
    @HystrixCommand(fallbackMethod= "getUserBackUp")
    @RequestMapping("/provider/get/user")
    public ResultEntity<User> getUser(@RequestParam String name){
    	// 如果这个方法出现 错误/超时 就会去调用备用方法 【超时默认为1秒】
        return ResultEntity.successWithData(new User(1,"aaa","男"));
    }
    /**
     * 备选方案
     * @param name
     * @return
     */
    public ResultEntity<User> getUserBackUp(@RequestParam String name){
        return ResultEntity.failed("熔断机制触发!");
    }
      /**
         * 超时访问,设置自身调用超时的峰值,峰值内正常运行,超过了峰值需要服务降级 自动调用fallbackMethod 指定的方法
         * 超时异常或者运行异常 都会进行服务降级
         *  设置3秒钟,3秒钟内正常运行,超过了3秒钟执行fallbackMethod 的方法
         * @param id
         * @return
         */
        @HystrixCommand(fallbackMethod = "paymentInfoTimeOutHandler", commandProperties = {
                @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
        })
        public String paymentInfoTimeOut(Integer id) {
    //        int age = 10/0;  //运行报错一进来就执行fallbackMethod 的方法
            int second = 5;
            long start = System.currentTimeMillis();
            try {
                TimeUnit.SECONDS.sleep(second);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            long end = System.currentTimeMillis();
            System.out.println(end - start);
            return "线程池:  " + Thread.currentThread().getName() + " paymentInfoTimeOut,id:  " + id + "\t"
                    + "O(∩_∩)O哈哈~" + "  耗时(秒): " + second;
        }
    
    
      /**
         * paymentInfoTimeOut 方法失败后 自动调用此方法 实现服务降级 告知调用者 
          paymentInfoTimeOut 目前无法正常调用
         *
         * @param id
         * @return
         */
        public String paymentInfoTimeOutHandler(Integer id) {
            return "线程池:  " + Thread.currentThread().getName() + "  
         paymentInfoTimeOutHandler8001系统繁忙或者运行报错,请稍后再试,id:  " + id + "\t"
                    + "o(╥﹏╥)o";
        }


    5.注意:

  • 这只是熔断部分,没有远程调用,所以不用在commonservice中写同名接口
  • 浏览器访问的时候直接访问provider的controller【测试】

5.服务的降级
整体资源快不够了,忍痛将某些服务先关掉,待渡过难关,再开启回来

  • 当某个Consumer访问一个provider却迟迟得不到响应时预先设定好一个解决方案,而不是一直等待。

 5.1.common工程添加 Hystrix依赖

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

5.2. common工程中需要定义一个工厂类
实现 FallbackFactory 接口【泛型为Common中的远程调用Service】

/**
 * 1.实现Consumer端服务降级的功能
 * 2.实现FallbackFactory接口时要传入@FeignClient接口类型
 * 3.在create()方法中返回一个@FeignClient注解标注的接口类型的对象,当Provider调用失败后,会执行这个对象的对应方法
 */
@Component
public class MyFallBackFactory implements FallbackFactory<UserRemoteService> {
    @Override
    public UserRemoteService create(Throwable throwable) {
        return new UserRemoteService() { 
            @Override
            public ResultEntity<User> getUser(String name) {
                return ResultEntity.failed("consumer端降级!!");
            }
        };
    }
}


3. 修改common的远程 调用接口

common工程中原来的远程调用接口 UserRemoteService 的@FeignClients要添加 FallbackFactory属性为自己写的工厂.class ,fallbackFactory属性指定provider不可用时提供备用方案的工厂对象

4.feign-consumer端启动hystrix

【在配置文件中启动】

feign:
  hystrix:
    enabled: true

主启动类上:

@SpringBootApplication
@EnableFeignClients // 启动 feign
@EnableHystrix // 启动 hystrix
public class CloudConsumerFeignHystrixOrder80Application {
    public static void main(String[] args) {
        SpringApplication.run(CloudConsumerFeignHystrixOrder80Application.class, args);
        System.out.println("启动成功");
    }
}

消费端也有服务降级,如果超时和报错,一样是执行fallbackMethod里的方法
 

   @GetMapping("/payment/hystrix/timeout/{id}")
   @HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod", commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "5000")
    })
    @HystrixCommand
    public String paymentInfoTimeOut(@PathVariable("id") Integer id) {
        int age = 10 / 0;
        String result = paymentHystrixService.paymentInfoTimeOut(id);
        return result;
    }

    /**
     * 超时访问,设置自身调用超时的峰值,峰值内正常运行,超过了峰值需要服务降级 自动调用fallbackMethod 指定的方法
     * <br/>
     * 超时异常或者运行异常 都会进行服务降级
     *
     * @param id
     * @return
     */
    public String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id) {
        return "我是消费者80,对方支付系统繁忙请10秒钟后再试或者自己运行出错请检查自己,o(╥﹏╥)o";
    }

还有hystrix监控,看这篇文章:hystrixDashboard(服务监控) - 风止雨歇 - 博客园

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值