欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

SpringCloud中级篇之Hystrix

程序员文章站 2022-03-12 21:28:57
Hystrix简介借鉴博客:https://blog.csdn.net/qq_40603010/article/details/1091658571. 什么是Hystrix?作用?Hystrix,是一种保护机制,是Netflix开源的一个延迟和容错库。用于隔离访问远程服务、第三方库,防止出现级联失败。官网:https://github.com/Netflix/Hystrix/2. 服务雪崩微服务中,服务间调用关系错综复杂,一个请求可能需要调用多个微服务接口才能实现,会形成非常复杂的调...
Hystrix简介
1. 什么是Hystrix?作用?
2. 服务雪崩
  • 微服务中,服务间调用关系错综复杂,一个请求可能需要调用多个微服务接口才能实现,会形成非常复杂的调用链路。
  • 服务器支持的线程和并发数有限,请求一直阻塞,会导致服务器资源耗尽,从而导致所有其它服务都不可用,形成雪崩效应。
3. Hystrix中几个重要概念
  • 服务降级:

  • 服务器忙碌或者网络拥堵时,为了提高用户体验,在用户等待的同时,会返回一个友好提示,fallback(备选方案)

  • SpringCloud中级篇之Hystrix

  • 服务熔断:

  • 应对雪崩效应的一种微服务链路保护机制。

  • 当扇出链路的某个微服务出错不可用或者响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回错误的响应信息。

  • 当检测到该节点微服务调用响应正常后,恢复调用链路。
    SpringCloud中级篇之Hystrix
    SpringCloud中级篇之Hystrix

SpringCloud中级篇之Hystrix
SpringCloud中级篇之Hystrix
SpringCloud中级篇之Hystrix

  • 服务限流:
    SpringCloud中级篇之Hystrix
4. Hystrix案例
  • 创建服务提供者模块(cloud-provider-hystrix-layment8001)
  • pom.xml文件添加依赖
<dependencies>
    <!--eureka-client-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <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>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
    <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>
    <dependency>
        <!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
        <groupId>com.krisswen.cloud</groupId>
        <artifactId>cloud-api-commons</artifactId>
        <version>${project.version}</version>
    </dependency>
</dependencies>
  • 编写配置文件
server:
  port: 8001
spring:
  application:
    name: cloud-payment-service  #服务名称
eureka:
  client:
    # 注册进 Eureka 的服务中心
    register-with-eureka: true
    # 检索 服务中心 的其它服务
    fetch-registry: true
    service-url:
      # 设置与 Eureka Server 交互的地址
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
  • 编写启动类
@SpringBootApplication
@EnableDiscoveryClient
public class HystrixPaymentApplication {
    public static void main(String[] args) {
        SpringApplication.run(HystrixPaymentApplication.class, args);
    }
}
  • 编写service
@Service
public class PaymentService {

    /**
     * 可以正常访问的方法
     * @param id
     * @return
     */
    public String paymentInfo_Ok(Integer id){
        return "线程池:" + Thread.currentThread().getName() + "  ,paymentInfo_OK,id:" + id;
    }

    /**
     超时访问的方法
     */
    public String paymentInfo_Timeout(Integer id){
        int interTime = 3;
        try{
            TimeUnit.SECONDS.sleep(interTime);
        }catch (Exception e){
            e.printStackTrace();
        }
        return "线程池:" + Thread.currentThread().getName() + "  ,paymentInfo_Timeout,id:" + id + "耗时" + interTime + "秒钟";
    }
}
  • 编写controller
@RestController
@Slf4j
public class PaymentController {

    @Autowired
    PaymentService paymentService;

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

    @GetMapping("/payment/hystrix/{id}")
    public String paymentInfo_OK(@PathVariable("id")Integer id){
        log.info("paymentInfo_OKKKKOKKK");
        return paymentService.paymentInfo_Ok(id);
    }

    @GetMapping("/payment/hystrix/timeout/{id}")
    public String paymentInfo_Timeout(@PathVariable("id")Integer id){
        log.info("paymentInfo_timeout");
        return paymentService.paymentInfo_Timeout(id);
    }
}
  • 启动测试类,测试结果
    SpringCloud中级篇之Hystrix
    SpringCloud中级篇之Hystrix
4.1 模拟高并发
  • 定义cloud-customer-feign-hystrix-order80
  • pom.xml文件中添加依赖
<dependencies>
    <!-- OpenFeign -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    <!--eureka-client-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <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>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
    <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>
    <dependency><!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
        <groupId>com.krisswen.cloud</groupId>
        <artifactId>cloud-api-commons</artifactId>
        <version>${project.version}</version>
    </dependency>
</dependencies>
  • 编写配置文件
server:
  port: 80
spring:
  application:
    name: cloud-customer-feign-hystrix-service
eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
  • 编写启动类
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients // 开启Feign客户端
public class HystrixOrderApplication80 {
    public static void main(String[] args) {
        SpringApplication.run(HystrixOrderApplication80.class, args);
    }
}
  • 编写feign客户端
@Component
@FeignClient(value = "cloud-payment-service")
public interface OrderService {

    @GetMapping("/payment/hystrix/{id}")
    public String paymentInfo_OK(@PathVariable("id")Integer id);

    @GetMapping("/payment/hystrix/timeout/{id}")
    public String paymentInfo_Timeout(@PathVariable("id")Integer id);
}
  • 编写controller
@RestController
@Slf4j
public class OrderController {

    @Autowired
    OrderService orderService;

    @GetMapping("/consumer/payment/hystrix/{id}")
    public String paymentInfo_OK(@PathVariable("id")Integer id){
        log.info("paymentInfo_OKKKKOKKK");
        return orderService.paymentInfo_OK(id);
    }

    @GetMapping("/consumer/payment/hystrix/timeout/{id}")
    public String paymentInfo_Timeout(@PathVariable("id")Integer id){
        log.info("paymentInfo_timeout");
        return orderService.paymentInfo_Timeout(id);
    }
}
  • 测试结果。

SpringCloud中级篇之Hystrix

4.2 服务降级
4.2.1 局部服务降级( 服务提供方)
  • 服务提供方设置局部服务降级
  • 服务降级放在消费端,即消费者端,但是提供者端同样适用。
  • 提供者设置自身调用超时的峰值,峰值内正常运行,超出峰值需要有兜底的方法处理,作服务降级fallback。
  • 局部服务降级步骤:
    • 提供方引入Hystrix依赖:
<!-- hystrix -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
  • 提供方service进行设置(对超时方法进行设置)
@Service
public class PaymentService {

    /**
     * 可以正常访问的方法
     * @param id
     * @return
     */
    public String paymentInfo_Ok(Integer id){
        return "线程池:" + Thread.currentThread().getName() + "  ,paymentInfo_OK,id:" + id;
    }

    /**
     超时访问的方法
     */
    @HystrixCommand(fallbackMethod = "timeoutHandler",commandProperties = {
            //设置峰值,超过 3 秒,就会调用兜底方法,这个时间也可以由feign控制
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000")
    })
    public String paymentInfo_Timeout(Integer id){
        int interTime = 5;
        try{
            TimeUnit.SECONDS.sleep(interTime);
        }catch (Exception e){
            e.printStackTrace();
        }
        return "线程池:" + Thread.currentThread().getName() + "  ,paymentInfo_Timeout,id:" + id + "耗时" + interTime + "秒钟";
    }
   // 定义服务出现异常之后,兜底的方法
    public String timeoutHandler(Integer id){
        return "服务异常,请重试......";
    }
}
  • 启动类添加注解@EnableCircuitBreaker,开启服务熔断
@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker // 开启服务熔断
public class HystrixPaymentApplication {
    public static void main(String[] args) {
        SpringApplication.run(HystrixPaymentApplication.class, args);
    }
}
  • 启动服务测试
    SpringCloud中级篇之Hystrix

  • 修改服务方中代码(模拟服务出现异常,而不是服务调用超时)

/**
 * 超时访问的方法
 *
 * @param id
 * @return
 */
@HystrixCommand(fallbackMethod = "timeoutHandler", commandProperties = {
        // 设置峰值,超过3秒,调用兜底方法,这个时间可由feign控制
        @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
})
public String paymentInfo_Timeout(Integer id) {
  /*  int interTime = 5;
    try {
        TimeUnit.SECONDS.sleep(interTime);
    } catch (Exception e) {
        e.printStackTrace();
    }*/
    int i = 10 / 0; // 模拟服务出现故障
    // return "线程池:" + Thread.currentThread().getName() + ",paymentInfo_Timeout,id:" + id + "耗时:" + interTime + "秒";
    return "hello";
}

public String timeoutHandler(Integer id) {
    return "服务异常,请重试……";
}

SpringCloud中级篇之Hystrix

  • 小结:只要是服务不可用了(调用超时,内部错误),都可以用降级来处理。
4.2.2 局部服务降级(服务消费方设置)
  • 步骤:
  • 将服务提供方关于服务降级的色湖之全部去掉
  • 服务消费方引入hystrix依赖
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
  • 在启动类上添加注解@EnableEircuitBeaker开启服务熔断
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients // 开启Feign客户端
@EnableCircuitBreaker // 开启熔断
public class HystrixOrderApplication80 {
    public static void main(String[] args) {
        SpringApplication.run(HystrixOrderApplication80.class, args);
    }
}
  • 在controller编写降级逻辑
@RestController
@Slf4j
@SuppressWarnings("all")
public class OrderController {
    @Autowired
    OrderService orderService;
    @GetMapping("/consumer/payment/hystrix/{id}")
    public String paymentInfo_OK(@PathVariable("id")Integer id){
        log.info("paymentInfo_OKKKKOKKK");
        return orderService.paymentInfo_OK(id);
    }
    @HystrixCommand(fallbackMethod = "handeException", commandProperties = {
            //设置峰值,超过 1.5 秒,就会调用兜底方法
            @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds", value = "1500")
    })
    @GetMapping("/consumer/payment/hystrix/timeout/{id}")
    public String paymentInfo_Timeout(@PathVariable("id")Integer id){
        log.info("paymentInfo_timeout");
        return orderService.paymentInfo_Timeout(id);
    }

    public String handeException(Integer id){
        return "服务调用异常,请稍后再试.....";
    }
}
  • 启动类启动测试
    SpringCloud中级篇之Hystrix
  • 修改服务提供方代码
@HystrixCommand(fallbackMethod = "timeoutHandler", commandProperties = {
        // 设置峰值,超过3秒,调用兜底方法,这个时间可由feign控制
        @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
})
public String paymentInfo_Timeout(Integer id) {
    int i = 10 / 0; // 模拟服务出现故障
    return "hello";
}

SpringCloud中级篇之Hystrix

4.2.3 全局服务降级
  • 上面的降级策略,很明显造成了代码的杂乱,提升了耦合度,而且按照这样,每个方法都需要配置一个兜底方法,很繁琐。
  • 现在将降级处理方法(兜底方法)做一个全局的配置,设置共有的兜底方法和独享的兜底方法。
  • 步骤:
  • 服务消费方controller添加全局降级逻辑方法
// 全局服务降级处理方法
public String globalHandler() {
    return "这是全局服务降级逻辑的方法……";
}
  • 消费方controller上添加一个注解@DefaultProperties(defaultFallback="globalHandler")开启全局服务降级
  • 消费方controller中修改paymentInfo_Timeout方法上的注解@HystrixCommand
/* @HystrixCommand(fallbackMethod = "handlerException",commandProperties = {
        // 设置峰值,超过1.5秒,调用兜底方法
        @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="1500")
}) */// 不写自己的 fallbackMethod属性,使用全局默认的
@HystrixCommand // 不写自己的fallbackMethod 属性 使用全局默认
@GetMapping("/consumer/payment/hystrix/timeout/{id}")
public String paymentInfo_Timeout(@PathVariable("id") Integer id) {
    log.info("paymentInfo_timeout");
    return orderService.paymentInfo_Timeout(id);
}
  • 启动测试
    SpringCloud中级篇之Hystrix

小结
  • 编写代码中,发现一个有意思的问题:
    • @SpringCloudApplication注解是个组和注解,其中包含了@SpringBootApplication @EnableDiscoverCilent @EnableCircuitBreaker 这三个注解。
    • 也就是说,这个使用了这个注解,可以直接替代上述三个注解,简化代码。
    • 当然前提是,引入了hystrix依赖。
@SpringCloudApplication源码

SpringCloud中级篇之Hystrix

本文地址:https://blog.csdn.net/weixin_44796580/article/details/112850722