学习笔记【SpringCloud-第七节:Hystrix断路器】

Hystrix断路器

已停更进维

多个微服务之间调用的时候,假设A调用BC,B、C有调用其他,越来越多,这就是所谓的“扇出”。如果扇出中某个微服务响应时间过长或不可用,对A的调用会占用越来越多的系统资源,进而引起系统崩溃。所谓的雪崩效应。

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

断路器本身是一种看管装置,当某个服务单元发生故障之后,通过断路器的故障键控,向调用方返回一个符合预期的、可处理的本宣响应(FallBack),而不是长时间的等待或者抛出调用方法无法处理的异常。

作用:

  • 服务降级fallback
  • 服务熔断break
  • 接近实时的监控flowlimit
  • 。。。

服务降级
大白话:对方系统不可用了,需要给一个兜底的解决方法。如服务忙,请稍后等待,不让客户端等待并立刻返回一个友好提示fallback
情况:

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

服务熔断
大白话:类似保险苏达到最大访问量后,直接拒绝访问,拉闸限电,然后调用服务降级的方法并返回友好提示

服务限流
秒杀高并发等操作,进制一窝蜂的过来拥挤,大家排队,一秒钟N个,有序进行


Hystrix案例

7001改为单机

新建cloud-provider-hystrix-payment8001

写pom

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

写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    
  instance:
    instance-id: payment8001
    prefer-ip-address: true

主启动

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

service

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

    public String paymentInfo_TimeOut(Integer id){
        int timeNum=3000;
        try {
            Thread.sleep(timeNum);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "线程池:"+Thread.currentThread().getName()+"    paymentInfo_TimeOut,id: "+id+"  ;耗时"+(timeNum/1000)+"秒";
    }
}

controller

@RestController
@Slf4j
public class PaymentController {    
    @Resource
    private PaymentService paymentService;
    
    @Value("${server.port}")
    private String serverPort;
    
    @GetMapping("/payment/hystrix/ok/{id}")
    public String paymentInfo_OK(@PathVariable("id") Integer id){
        String result = paymentService.paymentInfo_OK(id);
        log.info("*****result:"+result);
        return result;
    }

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

若有两万个去访问timeout,访问ok也会变慢

新建一个80消费者cloud-consumer-feign-hystrix-order80

写pom

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

写yml

server:
  port: 80


eureka:
  client:
    register-with-eureka: false
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka

主启动:

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

service(feign)

@Component
@FeignClient(name = "CLOUD-PROVIDER-HYSTRIX-PAYMENT" )
public interface PaymentHystrixService {
    @GetMapping("/payment/hystrix/ok/{id}")

    String paymentInfo_OK(@PathVariable("id") Integer id);

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

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(@PathVariable("id") Integer id){
        return paymentHystrixService.paymentInfo_TimeOut(id);
    }
}

和之前一样,20000个timeout会使ok也变慢

超时、down机,都需有服务降级

降级配置

@HystrixCommand

8001从自身找问题:
设置自身调用超时时间的峰值,峰值内可以正常运行,超过了需要有兜底的方法处理,做服务降级fallback

8001service上配置,改了睡5s,但峰值为3s

@HystrixCommand(fallbackMethod = "paymentInfo_TimeOutHandler",commandProperties = {
            @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "3000")
    })
    public String paymentInfo_TimeOut(Integer id){
        int timeNum=5000;
        try {
            Thread.sleep(timeNum);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "线程池:"+Thread.currentThread().getName()+"    paymentInfo_TimeOut,id: "+id+"  ;耗时"+(timeNum/1000)+"秒";
    }

    public String paymentInfo_TimeOutHandler(Integer id){
        return "线程池:"+Thread.currentThread().getName()+"    paymentInfo_TimeOutHandler,id: "+id+"  ;不好意思,已超时!";
    }

8001主启动类上,@EnableCircuitBreaker:

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

在这里插入图片描述
若报错如10/0也会直接到这个页面

不过降级一般更多在客户端

80订单微服务,也可以更好地保护自己,自己也依样画葫芦进行客户端降级保护
题外话:对@HystrixCommand内属性的修改建议重启微服务

yml中:

feign:
  hystrix:
    enabled: true

在主启动类上加:@EnableCircuitBreaker

业务类改controller

@GetMapping("/consumer/payment/hystrix/timeout/{id}")
@HystrixCommand(fallbackMethod = "paymentInfo_TimeOutHandler",commandProperties = {
         @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "1500")
 })
 public String paymentInfo_TimeOut(@PathVariable("id") Integer id){
     return paymentHystrixService.paymentInfo_TimeOut(id);
 }
 public String paymentInfo_TimeOutHandler(@PathVariable("id") Integer id){
     return "我是消费者80,对方支付系统繁忙,请稍后再试!!";
 }

目前的问题
每个业务方法对应一个兜底的方法,代码膨胀,需要统一和自定义的分开
拿80举例:
在类上加:

@DefaultProperties(defaultFallback = "payment_Global_FallbackMethod")

写一个全局方法

//下面是全局fallback
public String payment_Global_FallbackMethod(){
    return "Global异常处理信息,请稍后再试!";
}

在需要降级的方法上加:@HystrixCommand

新问题:如果8001宕机,则会调用不到8001的方法
只需要为Feign客户端定义的接口添加一个服务降级处理的实现类即可实现解耦

写一个类继承用了feign的service接口

@Component
public class PaymentFallbackService implements PaymentHystrixService{
    @Override
    public String paymentInfo_OK(Integer id) {
        return "-------PaymentFallbackService fall back,ok,o(╥﹏╥)o";
    }

    @Override
    public String paymentInfo_TimeOut(Integer id) {
        return "-------PaymentFallbackService fall back,timeout,o(╥﹏╥)o";
    }
}

用了feign的service接口的注解上加上:fallback = PaymentFallbackService.class指向上面的类

@FeignClient(name = "CLOUD-PROVIDER-HYSTRIX-PAYMENT" ,fallback = PaymentFallbackService.class)

关闭了8001在访问:
在这里插入图片描述


服务熔断

服务熔断,一开始降级操作,但当检测到该节点微服务调用响应正常后,恢复调用链路。缺省是5秒内20次调用失败,就会启动熔断机制。熔断机制的注解是@HystrixCommand

修改8001,service加上

@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()+"调用成功,流水号:"+serialNumber;
}
public String paymentCircuitBreaker_fallback(@PathVariable("id") Integer id){
    return "ID 不能为负数,请稍后再试,o(╥﹏╥)o  id:"+id;
}

controller

@GetMapping("/payment/circuit/{id}")
public String paymentCircuitBreaker(@PathVariable("id") Integer id){
    String result = paymentService.paymentCircuitBreaker(id);
    log.info("****result:"+result);
    return result;
}
服务限流,后面到alibaba的Sentinel说明

服务监控hystrixDashboard

创建一个新的类:
cloud-consumer-hystrix-dashboard9001

写pom

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

写yml

server:
  port: 9001

主启动

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

所有Provider微服务提供类(8001、8002等)都需要监控依赖配置,pom中加

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

这样即配置成功
在这里插入图片描述
另外,因为版本原因,想监控8001,我们还需在
9001的yml中加入:

hystrix:
  dashboard:
    proxy-stream-allow-list: "*"

8001的主启动类上加入:

@Bean
public ServletRegistrationBean getServlet(){
    HystrixMetricsStreamServlet streamServlet=new HystrixMetricsStreamServlet();
    ServletRegistrationBean registrationBean=new ServletRegistrationBean(streamServlet);
    registrationBean.setLoadOnStartup(1);
    registrationBean.addUrlMappings("/hystrix.stream");
    registrationBean.setName("HystrixMetricsStreamServlet");
    return registrationBean;
}

最终
在这里插入图片描述
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值