SpringCloud Hystrix介绍以及基于RestTemplate与Feign的改造

一、Hystrix介绍

Hystrix 是Netfix的一个开源的延迟和容错库,用于隔离访问远程系统、服务或者第三方库,防止服务级联失败,从而提升系统的可用性与容错性。Hystrix主要通过以下几点实现延迟和容错。

  • 包裹请求:使用@HystrixCommand注解将接口进行包装成一个对象,对第三方系统或者外部依赖进行提供。并且包装的对象将单独运行在一个线程中。此处采用命令模式(设计模式)。
  • 跳闸机制:当某个服务的错误率超过一定阈值时,Hystrix可以自动或手动跳闸,停止请求改服务一段时间。
  • 资源隔离:Hystrix为每个依赖(依赖即接口,微服务中接口在其上游接口下即为上游接口的依赖)都维护了一个小型的线程池(或者信号量)。如果改线程池已满,发往该依赖的请求会被立即拒绝,而不是排队等待,从而加速失败判定。
  • 监控:Hystrix可以近乎实施的监控运行指标和配置的变化,例如成功、失败、超时、以及拒绝的请求信息。
  • 回退机制:当请求失败、超时、被拒绝,或当断路器打开时,执行回退逻辑(fallback)。回退逻辑由开发人员定义,例如可以返回一个缺省的返回值。
  • 自我修复:断路器打开一段时间后,会自动进入一个“半开”状态。

二、基于RestTemplate调用的消费者工程改造

1,pom引入hystrix的依赖 (新版本的Eureka也支持Hystrix,jar包中包含了Hystrix的模块依赖)

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

2,在启动类上添加@EnableCircuitBreaker激活Hystrix

@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker
public class RestOrderApplication {

3,配置熔断触发的降级逻辑

在Controller中添加接口降级逻辑,该方法需要与被保护降级的方法参数返回值一致。

   /**
     * 降级方法,需要和降级的方法入参和返回值一致
     * @param id
     * @return
     */
    public CommonResult<Payment> getPaymentFallBack( Long id){
        System.out.println("触发了降级逻辑");
        return new CommonResult<>(400,"触发了FallBack降级逻辑。。。",null);
    }

4,在需要保护的接口上配置@HystrixCommand注解

在需要保护降级的方法上使用@HystrixCommand注解,并指定其失败时的降级函数。

 /**
     * 使用注解配置熔断保护
     * @param id
     * @return
     */
    @HystrixCommand(fallbackMethod = "getPaymentFallBack")
    @GetMapping("/consumer/product/get/{id}")
    public CommonResult<Payment> getPayment(@PathVariable("id") Long id){
        CommonResult<Payment> commonResult = restTemplate.getForObject("http://cloud-payment-service/payment/get/"+id,CommonResult.class);
        return  commonResult;
    }

------- 本项目完整结构代码如下(本项目为消费者工程,注册中心使用的Eureka):--------

1.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</artifactId>
        <groupId>com.xiaohui.springCloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>hystrix_order_service_rest</artifactId>

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

        <dependency>
            <groupId>com.xiaohui.springCloud</groupId>
            <artifactId>cloud-api-common</artifactId>
            <version>${project.version}</version>
        </dependency>

        <!-- Eureka 客户端 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.retry</groupId>
            <artifactId>spring-retry</artifactId>
        </dependency>

        <!-- web依赖开始 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!-- web依赖结束 -->

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

2,application.yml

hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds 指定了触发降级时的超时时间

server:
  port: 80 #服务端口
spring:
  application:
    name: cloud-order-rest-service #服务名称
eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://eureka1.com:9000/eureka/
  instance:
    prefer-ip-address: true #使用ip进行注册
    instance-id: ${spring.cloud.client.ip-address}:${server.port} #向注册中心注册服务ID
    lease-renewal-interval-in-seconds: 5 #发送心跳间隔时间 秒
    lease-expiration-duration-in-seconds: 10 # 服务续约时间 10秒内没有发送心跳(宕机)

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 1000

3,主启动类

package com.xiaohui.hystrix;

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
@EnableCircuitBreaker
public class RestOrderApplication {

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

4,配置类

package com.xiaohui.hystrix.config;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

/**
 *
 * 相当于 spring的 application.xml bean注解相当于 bean 标签
 */
@Configuration
public class ApplicationContextConfig {

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

5,业务类(重点

在Controller中 

public CommonResult<Payment> getPaymentFallBack( Long id) 方法为 public CommonResult<Payment> getPayment(@PathVariable("id") Long id) 的降级方法。

public CommonResult<Payment> defaultFallBack() 方法为 该Controller的全局降级方法。

当方法指定了降级方法则会走方法指定的降级逻辑方法。没有指定的则走全局的降级方法。

package com.xiaohui.hystrix.controller;

import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.xiaohui.springcloud.entities.CommonResult;
import com.xiaohui.springcloud.entities.Payment;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
@DefaultProperties(defaultFallback = "defaultFallBack")
public class OrderController {

    @Autowired
    private RestTemplate restTemplate;

    /**
     * 使用注解配置熔断保护
     * @param id
     * @return
     */
    @HystrixCommand(fallbackMethod = "getPaymentFallBack")
    @GetMapping("/consumer/product/get/{id}")
    public CommonResult<Payment> getPayment(@PathVariable("id") Long id){
        CommonResult<Payment> commonResult = restTemplate.getForObject("http://cloud-payment-service/payment/get/"+id,CommonResult.class);
        return  commonResult;
    }
    @HystrixCommand
    @GetMapping("/consumer/product/get2/{id}")
    public CommonResult<Payment> getPayment2(@PathVariable("id") Long id){
        CommonResult<Payment> commonResult = restTemplate.getForObject("http://cloud-payment-service/payment/get/"+id,CommonResult.class);
        return  commonResult;
    }

    /**
     * 降级方法,需要和降级的方法入参和返回值一致
     * @param id
     * @return
     */
    public CommonResult<Payment> getPaymentFallBack( Long id){
        System.out.println("触发了降级逻辑");
        return new CommonResult<>(400,"触发了FallBack降级逻辑。。。",null);
    }

    /**
     * 统一降级方法不需要入参
     * @return
     */
    public CommonResult<Payment> defaultFallBack(){
        System.out.println("触发了统一降级逻辑");
        return new CommonResult<>(400,"触发了defaultFallBack降级逻辑。。。",null);
    }

}

三、基于Feign调用的消费者工程改造

1,依赖:由于Feign依赖中包含了Hystrix,已经对Hystrix有了支持,所以不需要在新引入依赖。

2,在配置文件中开启Hystrix。

    feign.hystrix.enabled=ture

3,添加feignclient接口实现类,实现降级方法

@Component
public class ProductFeignClientFallBack implements ProductFeignClient {

    @Override
    public CommonResult getPayment(Long id) {
        System.out.println("Feign 降级处理逻辑..");
        return new CommonResult(404,"Feign 降级处理逻辑..",null);
    }

    @Override
    public CommonResult getPaymentTimeout() {
        System.out.println("Feign timeOut降级处理逻辑...");
        return new CommonResult(404,"Feign timeOut降级处理逻辑....",null);
    }
}

4,Feignclient接口中使用@FeignClient注解添加指定 fallback实现类。其中name为feign的配置为调用接口服务名。

@FeignClient(name="CLOUD-PAYMENT-SERVICE" ,fallback = ProductFeignClientFallBack.class)
public interface ProductFeignClient {

    @RequestMapping(value="/payment/get/{id}",method = RequestMethod.GET)
    CommonResult getPayment(@PathVariable("id") Long id);

    @GetMapping("/payment/get/timeout")
    CommonResult getPaymentTimeout();
}

Feign的项目完整文件目录如下:

1,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</artifactId>
        <groupId>com.xiaohui.springCloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>openfeign_order_service</artifactId>

    <dependencies>
        <dependency>
            <groupId>com.xiaohui.springCloud</groupId>
            <artifactId>cloud-api-common</artifactId>
            <version>${project.version}</version>
        </dependency>

        <!-- springCloud 整合的openFeign -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        <!-- Eureka 客户端 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.retry</groupId>
            <artifactId>spring-retry</artifactId>
        </dependency>

        <!-- web依赖开始 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- web依赖结束 -->

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <!-- 健康检查监控 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
        </dependency>
    </dependencies>
</project>

2,application.yml

server:
  port: 9001

spring:
  application:
    name: openfeign-order-service

eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://eureka1.com:9000/eureka/
  instance:
    prefer-ip-address: true #使用ip进行注册
    instance-id: ${spring.cloud.client.ip-address}:${server.port} #向注册中心注册服务ID
    lease-renewal-interval-in-seconds: 5 #发送心跳间隔时间 秒
    lease-expiration-duration-in-seconds: 10 # 服务续约时间 10秒内没有发送心跳(宕机)

#CLOUD-PAYMENT-SERVICE:
#  ribbon:
#    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

#Feign 日志输出配置
feign:
  client:
    config:
      CLOUD-PAYMENT-SERVICE:
        loggerLevel: FULL
        connectTimeout: 5000
        readTimeout: 5000
  #开启对hystrix 支持,默认false
  hystrix:
    enabled: true

logging:
  level:
    com.xiaohui.springcloud.service.ProductFeignClient: debug

3,启动类(启动类可以不加@EnableCircuitBreaker注解)

package com.xiaohui.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableFeignClients
public class OrderApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class,args);
    }
}

4,业务类

Feign接口类

package com.xiaohui.springcloud.service;

import com.xiaohui.springcloud.entities.CommonResult;
import com.xiaohui.springcloud.service.impl.ProductFeignClientFallBack;
import org.springframework.cloud.openfeign.FeignClient;
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.RequestMethod;

@FeignClient(name="CLOUD-PAYMENT-SERVICE" ,fallback = ProductFeignClientFallBack.class)
public interface ProductFeignClient {

    @RequestMapping(value="/payment/get/{id}",method = RequestMethod.GET)
    CommonResult getPayment(@PathVariable("id") Long id);

    @GetMapping("/payment/get/timeout")
    CommonResult getPaymentTimeout();
}

Feign 接口降级实现类

package com.xiaohui.springcloud.service.impl;

import com.xiaohui.springcloud.entities.CommonResult;
import com.xiaohui.springcloud.service.ProductFeignClient;
import org.springframework.stereotype.Component;

@Component
public class ProductFeignClientFallBack implements ProductFeignClient {

    @Override
    public CommonResult getPayment(Long id) {
        System.out.println("Feign 降级处理逻辑..");
        return new CommonResult(404,"Feign 降级处理逻辑..",null);
    }

    @Override
    public CommonResult getPaymentTimeout() {
        System.out.println("Feign timeOut降级处理逻辑...");
        return new CommonResult(404,"Feign timeOut降级处理逻辑....",null);
    }
}

Controller类

package com.xiaohui.springcloud.controller;

import com.xiaohui.springcloud.entities.CommonResult;
import com.xiaohui.springcloud.entities.Payment;
import com.xiaohui.springcloud.service.ProductFeignClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class OrderController {

    @Autowired
    private ProductFeignClient productFeignClient;

    @GetMapping("/consumer/payment/get/{id}")
    public CommonResult<Payment> getPayment(@PathVariable("id") Long id){
        return productFeignClient.getPayment(id);
    }

    @GetMapping("/consumer/payment/get/timeout")
    public CommonResult getPaymentTimeout(){
        return productFeignClient.getPaymentTimeout();
    }
}

只启动Eureka和消费者工程调用测试:根据现象可以看到没有对应的生产者方法时会执行实现的降级方法。

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值