Hystrix断路器

概述:

分布式系统面临的问题?

复杂分式式体系中的应用程序有数十个依赖关系,每个依赖关系在某些时候将不可避免地失败。
服务雪崩的概念:
在这里插入图片描述

多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C又调用其他微服务,这就是所谓的**“扇出” ** 。如果扇出的链路上某个微服务的调用响应时间过长或者不可用,对微服务的调用就会占用越来越多的系统资源,进而引起系统崩溃,所谓的**“雪崩效应”**
对高流量的应用来说,单一的后端依赖可能会导致所有的服务器上所有的资源都在几秒中内饱和,比失败更槽糕的是,这些应用程序还可能导致服务之间的延迟增加,备份队列,线程和其他系统资源紧张,导致整个系统发生更多的级联故障,这些都表示需要对故障和延迟进行隔离和管理,以便单个依赖关系的失败,不能取消整个应用程序或系统。

是什么?

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

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

能干嘛?

服务降级
服务熔断
接近实时的监控

官网资料

https://github.com/Netflix/Hystrix/wiki/How-To-Use

Hystrix官宣,停更进维

http://github.com/Netflix/Hystrix
在这里插入图片描述

Hystrix重要概念:

服务降级 Fallback

服务器忙,请稍后再试,不让客户端等待并立刻返回一个友好提示,fallback
哪些情况会触发降级
程序运行异常
超时
服务熔断触发服务降级
线程池/信号量打满也会导致服务降级

服务熔断 break

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

服务限流 flowlimit

秒杀高并发等操作,严禁一窝蜂过来拥挤,大家排队,一秒钟N个,有序进行。

Hystrix案例:

1.构建Hystrix支付工程

a.建工程 cloud-hystrix-payment
b. pom.xml

<dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</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.example</groupId>
            <artifactId>cloud-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

c.yml配置

server:
  port: 8001

spring:
  application:
    name: cloud-payment-hystrix-service
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource #当前数据源操作类型
    driver-class-name: org.gjt.mm.mysql.Driver   # mysql驱动包
    url: jdbc:mysql://127.0.0.1:3306/db2019?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false
    username: root
    password: root

mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.atguigu.springcloud.entites  #所有Entity别名类所在包

eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
    register-with-eureka: true # 表示是否将自己注册进EurekaServer 默认为TRUE

    fetchRegistry: true     #  是否从EurekServer抓取已有的注册信息,默认为true.集群必须设置为true,才能配合Ribbon负载均衡使用
  instance:
    instance-id: payment8001 # 增加主机名
    prefer-ip-address: true  # 访问路径可以显示ip地址

d.启动类

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

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

e.业务
这里写了两个接口测试业务,一个是正常访问业务,一个是模拟业务处理时间长暂停3s返回。
正常业务

import com.atguigu.springcloud.entities.CommonResult;
import com.atguigu.springcloud.entities.Payment;
import com.atguigu.springcloud.service.HsystrixService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
@Slf4j
public class HsystrixController {

    @Autowired
    private HsystrixService hsystrixService;

    @Value("${server.port}")
    private String serverPort;  // 获取服务端口号


    @GetMapping(value = "/payment/hsystrix/get/{id}")
    public CommonResult getPaymentById(@PathVariable("id") long id){
        long start = System.currentTimeMillis();
        Payment payment = hsystrixService.getPaymentById(id);
        if (payment != null){


            long end = System.currentTimeMillis();
            return new CommonResult<Payment>(200,"查询成功成功serverPort:"+serverPort+" 访问耗时:"+(end-start)/1000 +"秒",payment);
        }else {
            long end2 = System.currentTimeMillis();
            return new CommonResult<Payment>(404,"查询失败serverPort:"+serverPort+" 访问耗时:"+(end2-start)/1000 +"秒");
        }
    }

耗时业务:

@GetMapping(value = "/payment/hsystrix/timeout/get/{id}")
    public CommonResult getPaymentTimeout(@PathVariable("id") long id){
        long start = System.currentTimeMillis();

        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        Payment payment = hsystrixService.getPaymentById(id);


        if (payment != null){
            long end = System.currentTimeMillis();
            return new CommonResult<Payment>(200,"查询成功成功serverPort:"+serverPort+" 访问耗时:"+(end-start)/1000 +"秒",payment);
        }else {
            long end2 = System.currentTimeMillis();
            return new CommonResult<Payment>(404,"查询失败serverPort:"+serverPort+" 访问耗时:"+(end2-start)/1000 +"秒");
        }
    }

f.测试
两个接口都测试正常
在这里插入图片描述
卡顿3m正常。
在这里插入图片描述

2.压力测试

在这里插入图片描述
在这里插入图片描述
测试结果:
正常服务和耗时业务都会出现卡顿。消费延迟的情况下,容易导致调用者只能干等,最终导致调用者不满意,服务端被拖死。
原因:
tomcat的默认工作线程数被打满了,没有多余的线程来分解压力和处理。

3. 新建调用者工程

a.建工程
b. pom.xml
c.yml
d.主启动类
e.业务
f.调用测试
h.高压测试

4.问题解决思路
1.超时导致服务器变慢(转圈)----------超时不再等待
2.出错(宕机或程序运行出错)----------出错要有兜底
解决:
对方服务(8001)超时了,调用者(80)不能一直卡死等待,必须要有服务降级
对方服务(8001)宕机了,调用者(80)不能一直卡死等待,必须有服务降级
对方服务(8001)ok.调用者(80)自己出故障或有自我要求(自己的等待时间不能小于服务响应时间)

5.服务降级
a.降级配置 @HystrixCommand
官网上案例是要继承一个类,这里用一个注解配置
在这里插入图片描述
b.8001先从自身找问题
设置自身调用超时时间的峰值,峰值内可以正常运行,超过了需要有兜底的方法处理,作服务降级Fallback。
c.8001fallback
消费者降级
d.80fallback
调用者降级
e.目前问题
每个业务方法对应一个兜底的方法,代码膨胀
统一和自定义的分开
f.解决问题
每个方法配置一个???膨胀
feign接口系列
@DefaultProperties(defaultFallback="")
1对1 每个方法配置一个服务降级方法,技术上可以的,但是代码冗余
1对N 除了个别重要核心业务有专属,其他普通的可以通过@DefaultProperties(defaultFallback ="") 统一跳转到统一处理结果页面
通用和独享的各自分开,避免了代码膨胀,合理减少了代码量。
controller配置
在这里插入图片描述
和业务逻辑混在一起???混乱
服务降级,客户端去调用服务端,碰上服务端宕机或关闭
本次案例服务降级处理是在客户端80实现完成的,与服务端8001没有关系,只需为Feign客户端定义的接口添加一个服务降级处理的实现类即可实现解耦,

熔断机制概述:
熔断机制是应对雪崩效应的一种微服务链路保护机制,当煽出链路的某微服务出错不可用或者响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回错误的响应信息
当检测到该节点微服务调用响应正常后,恢复调用链路
在spring clouod框架里,熔断机制通过Hystrix实现,Hystrix会监控微服务调用的状况,当失效的调用到一定阀值,缺省是5秒内调用20次失败,就会启动熔断机制,熔断机制的注解是@HystrixCommand。

在这里插入图片描述
案例:
服务熔断方法: 在HsystrixServiceImpl 类里面写一个熔断方法

//=====  服务熔断
    @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 simpleUUID = IdUtil.simpleUUID();
        return Thread.currentThread().getName()+" \t" +" 调用成功,调用流水号"+simpleUUID;
    }
    public String paymentCircuitBreaker_fallback(@PathVariable("id") Integer id){ // 兜底方法
        return "id 不能负数, 请稍后再试 --- id: " + id;
    }

接口: HsystrixService

 String paymentCircuitBreaker(Integer id);

controller调用HsystrixController

 // === 服务熔断
    @GetMapping("/payment/circuit/{id}")
    public String paymentCircuitBreaker(@PathVariable("id") Integer id){
      String result =  hsystrixService.paymentCircuitBreaker(id);
        return result;
    }

测试;
返回正常时状态:
在这里插入图片描述
返回异常时状态:
在这里插入图片描述
多次异常后,访问正常时,也是出于熔断状态
在这里插入图片描述

Hystrix工作流程

在这里插入图片描述

服务监控HystrixDashboard

概述:
除了隔离依赖服务的调用以外,Hystrix还提供了准确的调用监控(Hystrix Dashboard),Hystrix会持续地记录所有通过Hystrix发起的请求的执行信息,并以统计报表和图形的形式展示给用户,包括每秒执行多少请求多少成功,多少失败等,Netfix通过Hystrix-metrics-event-stream项目实现了对以上指标的监控,Spring Cloud也提供了Hystrix Dashboard的整合,对监控内容转化成可视化界面.

1.监控工程搭建
a.建工程 cloud-consumer-hsystrix-order9001
b. pom.xml

<dependencies>
        <!--仪表盘图形化的依赖-->
        <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>
        </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>
    </dependencies>

c.yml

server:
  port: 9001

d.主启动类

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;

@SpringBootApplication
@EnableHystrixDashboard  // 启动监控图形化配置
public class HystrixDashboardAppcation {
    public static void main(String[] args) {
        SpringApplication.run(HystrixDashboardAppcation.class,args);
    }
}

e.启动测试
浏览器输入: http://localhost:9001/hystrix
在这里插入图片描述
2. 配置
a. 需要在监控的微服务里面加入依赖

<!--actuator监控信息坐标依赖-->
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-actuator</artifactId>
      </dependency>

b.在监控的微服务主启动类上开启配置

@EnableCircuitBreaker 

c. 填坑,在启动类加bean配置

/*
* 此配置是为了服务监控而配置,与服务容错本身无关,SpringCloud升级的坑
* ServletRegistrationBean因为springboot的默认路径不是"/hystrix.stream",
* 只要在自己的项目里配置上下面的servlet就可以了
*/
  @Bean
  public ServletRegistrationBean getServlet(){
      HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
      ServletRegistrationBean registrationBean = new ServletRegistrationBean();
      registrationBean.setLoadOnStartup(1);
      registrationBean.addUrlMappings("/hystrix.stream");
      registrationBean.setName("HystrixMetricsStreamServlet");
      return registrationBean;
  }

e. 被监控的服务重启
f. 监控配置
在这里插入图片描述
h.监控示例
在这里插入图片描述
i.参数说明:
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值