Hystrix

133 阅读4分钟

Hystrix几个概念

Hystrix 是什么:它是用于处理分布式系统的延时和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,例如超时、异常。Hystrix能够在保证一个依赖出现问题的情况下,不会导致整体服务失败,避免级联故障,以此来提高分布式系统的弹性。

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

服务降级(fallback)

服务器忙,请稍后再试,不让客户等待并立刻返回一个友好的提示

触发降级的情况:程序运行异常、超时、服务熔断触发降级、线程池/信号量打满也会导致服务降级。

务熔断(break) 类比保险丝达到最大服务访问以后,直接拒绝访问,然后调用服务降级的方法并返回友好提示

限流(flowlimit)

限制请求的流量,严禁一窝蜂的请求打过来。

创建模块服务提供者 cloud-provider-hystrix-payment8001

pom

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

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

    <dependency>
        <groupId>com.nyc.cloud</groupId>
        <artifactId>cloud-api-commons</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-actuator</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
</dependencies>

yml

server:
  port: 8001
spring:
  application:
    name: cloud-provider-hystrix-payment
eureka:
  client:
    #是否要将自己入驻到EurekaServer 默认为 true
    register-with-eureka: true
    #是否从EurekaServer抓取已有的注册信息,默认为true,单节点无所谓,集群必须设置ture才能配合ribbon使用负载均衡
    fetch-registry: true
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka
  instance:
    instance-id: CloudProviderHystrixPayment8001
    prefer-ip-address: true   #显示ip

service

@Service
public class PaymentServiceImpl implements PaymentService {
    @Override
    public String paymentinfo_ok(Integer id) {
        return "线程池 : " + Thread.currentThread().getName() + " paymentInfo_OK,id " + id;
    }

    @Override
    @HystrixCommand(fallbackMethod = "paymentTimeOutFallBackMethod",commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000")
    })
    public String paymentInfo_TimeOut(Integer id) {
        int timeNumber = 1;
        try {
            TimeUnit.SECONDS.sleep(timeNumber);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        return "线程池 : " + Thread.currentThread().getName() + " paymentInfo_OK,id " + id + " 耗时 " + timeNumber;
    }

    public String paymentTimeOutFallBackMethod(Integer id){
        return "线程池 : " + Thread.currentThread().getName() + " paymentInfo_TimeOut,id " + id + " 耗时 " + "/(ㄒoㄒ)/~~  超时了......";
    }
}

controller


@RestController
public class PaymentHystirxController {

    @Autowired
    private PaymentService paymentService;

    @GetMapping("/payment/hystrix/ok/{id}")
    public String paymentInfo_Ok(@PathVariable("id")Integer id){
        return paymentService.paymentinfo_ok(id);
    }

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

启动类

@EnableEurekaClient 注册进入Eureka

@EnableCircuitBreaker 开启降级注解。

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

降级

图片.png

开启降级注解

图片.png

创建服务消费方 cloud-consumer-feign-hystrix-order80

pom

<dependencies>
    <!--hystrix-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        <version>2.2.1.RELEASE</version>
    </dependency>
    <!--OpenFeign-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
        <version>2.2.1.RELEASE</version>
    </dependency>
    <!--Eureka 客户端-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        <version>2.2.1.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-actuator</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
</dependencies>

yml

server:
  port: 80
spring:
  application:
    name: consumer-feign-hystrix-order
eureka:
  client:
    register-with-eureka: true
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka
feign:
  hystrix:
    enabled: true

Service 远程调用

@Component
@FeignClient(value = "cloud-provider-hystrix-payment")
public interface PaymentHystrixService {

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

     @GetMapping(value = "/payment/hystrix/timeout/{id}")
     String paymentInfo_TimeOut(@PathVariable("id")Integer id);
}

Controller

@RestController
@Slf4j
public class OrderHystrixController {

    @Autowired
    private PaymentHystrixService paymentHystrixService;

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

    @GetMapping(value = "/consumer/payment/hystrix/timeout/{id}")
    @HystrixCommand(fallbackMethod = "paymentTimeOutFallBackMethod",commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "1500")
    })
    public String  paymentInfo_TimeOut(@PathVariable("id")Integer id){
        //TimeUnit.SECONDS.sleep(3);
        String result = paymentHystrixService.paymentInfo_TimeOut(id);
        return result;
    }

    public String paymentTimeOutFallBackMethod(@PathVariable("id")Integer id){
        return "我是消费者80,对方支付系统繁忙请10秒钟以后在重试,呜呜呜";
    }
}

启动类

@SpringBootApplication
@EnableEurekaClient     //Eureka客户端
@EnableFeignClients     //激活OpenFeign
@EnableHystrix
public class OrderConsumerMain80 {
    public static void main(String[] args) {
        SpringApplication.run(OrderConsumerMain80.class);
    }
}

全局服务降级@DefaultProperties

图片.png

测试

图片.png

Hystrix统配服务降级

图片.png

图片.png

服务熔断

服务达到最大访问以后,直接拒绝访问,然后调用服务降级方法返回友好提示。服务降级->服务熔断->恢复调用链路。

熔断机制

熔断机制是应对雪崩效应的一种微服务链路保护机制,当扇出链路的某个微服务出错不可用或者响应时间太长,会进行服务的降级,进而熔断该节点微服务的调用,快速返回错误信息。当检测到该节点微服务调用响应正常后,回复调用链路

在spring cloud中,熔断机制通过Hystrix实现,Hystrix会监控微服务间的调用状况,当失败的调用到一定的阈值,缺省是5秒内20次调用失败,就会启动熔断机制,熔断机制的注解是 @HystrixCommand

服务熔断演示

@HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback",commandProperties = {
        @HystrixProperty(name = "circuitBreaker.enabled",value = "true"),           //是否开启断路器
        @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"),//请求次数
        @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "10000"),//时间窗口
        @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "60") //失败率达到多少以后跳闸
})
public String paymentCircuitBreaker(@PathVariable("id")Integer id){
    if (id<0){
        throw new RuntimeException("*********id,不能负数");
    }
    String serialNumber = IdUtil.simpleUUID();
    return Thread.currentThread().getName() + "\t" + "调用成功,流水号:" + serialNumber;
}
public String paymentCircuitBreaker_fallback(@PathVariable("id")Integer id){
    return "id 不能为负数,请稍后重试,┭┮﹏┭┮,id:" + id;
}

图片.png

@GetMapping(value = "/payment/circuit/{id}")
public String paymentCircuitBreaker(@PathVariable("id")Integer id){
    String result = paymentService.paymentCircuitBreaker(id);
    log.info("********result:"+result);
    return result;
}

图片.png

Hystrix图形化

搭建图形化界面

pom

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
        <version>2.2.1.RELEASE</version>
    </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-starter</artifactId>
    </dependency>

    <dependency>
        <groupId>com.nyc.cloud</groupId>
        <artifactId>cloud-api-commons</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
</dependencies>

yml

server:
  port: 9001

启动类

@SpringBootApplication
@EnableHystrixDashboard   //开启面板
public class HystrixDashBordMain9001 {
    public static void main(String[] args) {
        SpringApplication.run(HystrixDashBordMain9001.class);
    }
}

图片.png