Hystrix断路器

Hystrix简介

Hystrix是由Netflix开源的一个延迟和容错库,用于隔离访问远程系统、服务或者第三方库,防止级联失败,从而提升系统的可用性与容错性。

断路器本身是一种开关装置,当某个服务单元发生故障后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个符合预期·可处理的备选响应(Fallback),而不是长时间的的等待或者抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间,不必要的占用,从而避免了故障在分布式系统中蔓延,乃至雪崩

Hystrix主要通过以下几点实现延迟和容错。

包裹请求:使用HystrixCommand (或HystrixObservableCommand )包裹对依赖的调用逻辑,每个命令在独立线程中执行。这使用到了设计模式中的“命令模式”。
跳闸机制:当某服务的错误率超过一定阈值时,Hystrix可以自动或者手动跳闸,停 止请求该服务一段时间。
资源隔离:Hystrix为每个依赖都维护了一个小型的线程池(或者信号量)。如果该线 程池已满,发往该依赖的请求就被立即拒绝,而不是排队等候,从而加速失败判定。
监控:Hystrix可以近乎实时地监控运行指标和配置的变化,例如成功、失败、超时、 以及被拒绝的请求等。
回退机制:当请求失败、超时、被拒绝,或当断路器打开时,执行回退逻辑。回退逻辑可由开发人员自行提供,例如返回一个缺省值。
自我修复:断路器打开一段时间后,会自动进入“半开”状态。断路器打开、关闭、 半开的逻辑转换。

Hystrix能干嘛

服务降级 fallback

导致服务降级的原因,比如程序运行异常、超时、服务熔断触发服务降级、线程池信号量打满也会导致服务降级
服务熔断 break

类比保险丝达到最大服务访问后,直接拒绝访问,熔断服务,然后调用服务降级的方法来返回友好提示
服务的降级 -> 进而熔断 -> 恢复调用链路
服务限流 flowlimit

出现服务降级的情况:

①程序运行异常;
②超时;
③服务熔断触发服务降级;
④线程池/信号量打满也会导致服务降级。

解决方案:
对方服务超时了或宕机,调用者不能一直卡死等待,必须有服务降级;
对方服务可能OK,调用者自己出故障或有自我要求(自己的等待时间小于服务提供者),自己服务降级。

Hystrix案例

Hystrix服务提供者

1.新建cloud-provider-hystrix-payment8001

在这里插入图片描述

2.添加hystrix依赖:

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

3.配置yml:

server:
  port: 8001

spring:
  application:
    name: cloud-provider-hystrix-payment

eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      #defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
      defaultZone: http://eureka7001.com:7001/eureka

这里为了等下方便演示,所以只配置了eureka单机

4.主启动类


import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;

/**
 * 启动上添加注解@EnableCircuitBreaker或@EnableHystrix,启用断路器支持
 */
@SpringBootApplication
@EnableEurekaClient
//@EnableCircuitBreaker
public class PaymentHystrixApp8001 {

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

5. service


import cn.hutool.core.util.IdUtil;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.PathVariable;

import java.util.concurrent.TimeUnit;

@Service
public class PaymentService {

    public String paymentInfo_OK(Integer id) {
        return "线程池:  " + Thread.currentThread().getName() + "  paymentInfo_OK,id:  " + id + "\t" + "**************";
    }

    public String paymentInfo_TimeOut(Integer id) {
        //int age = 10/0;
        try {
            TimeUnit.MILLISECONDS.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "线程池:  " + Thread.currentThread().getName() + " id:  " + id + "\t" + "**************" + "  耗时(秒): ";
    }

    

6.controller


@RestController
@Slf4j
public class PaymentController {

    @Resource
    private PaymrntService paymrntService;
    @GetMapping("/payment/hystrix/ok/{id}")
    public String paymentInfo_OK(@PathVariable("id") Integer id){
        String result = paymrntService.paymentInfo_OK(id);
        return result;
    }
    @GetMapping("/payment/hystrix/timeout/{id}")
    public String paymentInfo_TimeOut(Integer id){
        String result = paymrntService.paymentInfo_TimeOut(id);
        return result;
    }
}

6.高并发测试

单独发送一个请求是没有问题,程序可以正常运行
使用JMeter做高并发压力测试,发送两万个请求到paymentInfo_TimeOut

当大批量访问paymentInfo_TimeOut,微服务将所有资源集中处理这些大批量的请求,paymentInfo_OK也会被拖慢

在这里插入图片描述访问 http://localhost:8001/payment/hystrix/timeout/1

发现访问很慢,一直在转圈, tomcat默认线程数被打满了,没有多余的的线程来处理
在这里插入图片描述如果此时外部的消费者80也来访问,最终导致服务端8001直接卡死

hystrix服务消费者

1.新建cloud-consumer-feign-hystrix-order80项目

2.添加hystrix 依赖


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

3.配置yml

server:
  port: 80

eureka:
  client:
    register-with-eureka: false
    service-url:
      http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/

4.主启动类

package com.my.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.cloud.openfeign.EnableFeignClients;

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

5.service


@Component
@FeignClient(value="CLOUD-PROVIDER-HYSTRIX-PAYMENT")
public interface PaymentHystrixService {
    @GetMapping("/payment/hystrix/ok/{id}")
    public String paymentInfo_OK(@PathVariable("id") Integer id);
    @GetMapping("/payment/hystrix/timeout/{id}")
    public String paymentInfo_TimeOut(Integer id);
}

6.controller


@RestController
@Slf4j
public class OrderHystrixController {
    @Resource
    private PaymentHystrixService paymentHystrixService;

    @GetMapping("/consumer/payment/hystrix/ok/{id}")
    public String paymentInfo_OK(@PathVariable("id") Integer id){
        return paymentHystrixService.paymentInfo_OK(id);
    }
    @GetMapping("/consumer/payment/hystrix/timeout/{id}")
    public String paymentInfo_TimeOut(Integer id){
        return paymentHystrixService.paymentInfo_TimeOut(id);
    }
}

使用JMeter向8001发送20000条请求,这时8001同一层次的其他接口服务被困死,因为tomcat线程池里面的工作线程已经被挤占完毕,80此时调用8001,客户端访问响应缓慢,转圈圈

应对这种超时、卡死、宕机,服务提供者和消费者都需要有应对方式

服务降级

对服务提供者进行降级
设置自身调用超时时间的峰值,峰值内正常运行
超过了需要又兜底的方法处理,做服务降级fallback

服务提供者fallback

service,添加注解@HystrixCommand

服务提供者fallback

1.service接口方法上添加注解@HystrixCommand


@Service
public class PaymrntService {
    public String paymentInfo_OK(Integer id){
        return "Thread Pool: "+Thread.currentThread().getName()
                + " paymentInfo_OK";
    }

    // 设置一个兜底方法(服务降级)
    // name:表示哪个线程
    // value:表示超时时间设置
    @HystrixCommand(fallbackMethod="paymentInfo_TimeOutHandler",
            commandProperties={
                @HystrixProperties(name="execution.isolation.thread.timeoutInMilliseconds",value="3000")
            })
    public String paymentInfo_TimeOut(Integer id){
        try {
            TimeUnit.SECONDS.sleep(5);
        }catch(Exception e){
            e.printStackTrace();
        }
        return "Thread Pool: "+Thread.currentThread().getName()
                + " paymentInfo_TimeOut";
    }

    public String paymentInfo_TimeOutHandler(Integer id){
        return "服务器较忙,请稍后重试";
    }
}

2.主启动类添加注解@EnableCircuitBreaker


@RestController
@Slf4j
public class OrderHystrixController {
    @Resource
    private PaymentHystrixService paymentHystrixService;

    @GetMapping("/consumer/payment/hystrix/ok/{id}")
    public String paymentInfo_OK(@PathVariable("id") Integer id){
        return paymentHystrixService.paymentInfo_OK(id);
    }
    @GetMapping("/consumer/payment/hystrix/timeout/{id}")
    @HystrixCommand(FallbackMenthod="paymentTimeOutFallbackMethod",commandProperties={
            @HystrixProperties(name="execution.isolation.thread.timeoutInMilliseconds",value="1500")
    })
    public String paymentInfo_TimeOut(Integer id){
        return paymentHystrixService.paymentInfo_TimeOut(id);
    }
    // 添加一个兜底方法
    public String paymentTimeOutFallbackMethod(@PathVariable("id")Integer id){
        return "80 服务繁忙,稍后重试";
    }
}

服务消费者fallback

1.controller方法上添加注解@HystrixCommand,实现服务降级功能


@RestController
@Slf4j
public class OrderHystrixController {
    @Resource
    private PaymentHystrixService paymentHystrixService;

    @GetMapping("/consumer/payment/hystrix/ok/{id}")
    public String paymentInfo_OK(@PathVariable("id") Integer id){
        return paymentHystrixService.paymentInfo_OK(id);
    }
    @GetMapping("/consumer/payment/hystrix/timeout/{id}")
    @HystrixCommand(FallbackMenthod="paymentTimeOutFallbackMethod",commandProperties={
            @HystrixProperties(name="execution.isolation.thread.timeoutInMilliseconds",value="1500")
    })
    public String paymentInfo_TimeOut(Integer id){
        return paymentHystrixService.paymentInfo_TimeOut(id);
    }
    // 添加一个兜底方法
    public String paymentTimeOutFallbackMethod(@PathVariable("id")Integer id){
        return "80 服务繁忙,稍后重试";
    }
}

2.启动类添加@EnableCircuitBreaker注解,启用服务降级


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

全局服务降级 DefaultProperties

@DefaultProperties(defaultFallback=“”)
每个方法配置一个服务降级方法,技术上可以,实际上代码很冗余
除了个别重要核心业务又专属,其他普通的可以通过@DefaultProperties(defaultFallback=“”)统一跳转到统一处理结果页面


@RestController
@Slf4j
@DefaultProperties(defaultFallback="payment_Global_FallbackMethod")
public class OrderHystrixController {
    @Resource
    private PaymentHystrixService paymentHystrixService;

  
    @GetMapping("/consumer/payment/hystrix/timeout/{id}")
    @HystrixCommand //没有特别指明,就用类上标注的统一的
    public String paymentInfo_TimeOut(Integer id){
        return paymentHystrixService.paymentInfo_TimeOut(id);
    }
    // 全局fallback方法
    public String payment_Global_FallbackMethod() {
        return "Global异常处理信息,请稍后再试,/(ㄒoㄒ)/~~";
    }
}


测试

访问 http://localhost/consumer/payment/hystrix/timeout/1

在这里插入图片描述

通用的和独享的各自分开,避免了代码膨胀,合理减少了代码量

通配服务降级FeignFallback

1.新建全局异常处理类

修改cloud-consumer-feign-hystrix-order80

根据cloud-consumer-feign-hystrix-order80项目已经有的PaymentHystrixService接口,重新新建一个类(PaymentFallbackService)实现该接口,统一为接口里面的方法进行异常处理


@Component
public class PaymentFallbackService implements PaymentHystrixService{
    @Override
    public String paymentInfo_OK(Integer id) {
        return "PaymentFallbackService paymentInfo_OK";
    }

    @Override
    public String paymentInfo_TimeOut(Integer id) {
        return "PaymentFallbackService paymentInfo_TimeOut";
    }
}

2.接口上指定fallback方法


@Component
@FeignClient(value="CLOUD-PROVIDER-HYSTRIX-PAYMENT",fallback=PaymentFallbackService.class)
public interface PaymentHystrixService {
    @GetMapping("/payment/hystrix/ok/{id}")
    public String paymentInfo_OK(@PathVariable("id") Integer id);
    @GetMapping("/payment/hystrix/timeout/{id}")
    public String paymentInfo_TimeOut(Integer id);
}

3.yml文件修改


# 用于服务降级,在注解@FeignClient中添加fallbackFactory属性值
feign:
	hystrix:
		enable: true #在Feign中开启Hystrix

  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值