断路器
相当于一种 开关控制
,通过断路器的 故障监控
(保险丝), 向调用方返回一个服务于其的、可处理的备用响应方案,而不是长时间的等待或者抛出调用方法无法处理的异常,这样就保证了服务调用方的线程不会被长时间不必要的占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩,可以防止服务雪崩
。 服务降级、服务熔断、服务限流、接近实时的监控等
服务雪崩
的情况,那么应用程序整个就会一直等待导致瘫痪,有了 Hystrix服务熔灾
之后,当某一个服务挂了之后,服务会调用一个备用的服务,备用的服务返回一些提示错误的消息,不至于像以前直接整个应用程序产生 雪崩效应
,不会导致整个服务失败,避免出现服务故障, 熔断机制
是对 雪崩效应
的一种 微服务链路保护机制
熔断机制
,熔断机制的注解是 @HystrixCommand
<!--配置Hystrix依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix</artifactId> <version>1.4.3.RELEASE</version> </dependency> 复制代码
server: port: 8080 # mybatis 配置 mybatis: type-aliases-package: com.baoji.springcloud.pojo config-location: classpath:mybatis/mybatis-config.xml #config-location 为mybatis配置文件 mapper-locations: classpath:mybatis/mapper/*.xml #mapper-locations 为mapper配置 #spring配置 spring: application: name: springcloud-provider datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/xxx?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true username: xxx password: xxx #Eureka的配置 服务注册到哪里 和注册中心服务的路径一样 eureka: client: service-url: defaultZone: http://localhost:7001/eureka/ instance: instance-id: springcloud-provider-dept-hystrix8001 # 修改eureka上的默认描述信息 prefer-ip-address: true # true 可以显示服务的ip,而不是显示localhost #info信息 info: app.name: linchi-springcloud company.name: com.baoji 复制代码
service层
,调用方法即可 @HystrixCommand(fallbackMethod = "hystrixGet")
注解,这个注解是当服务出现故障时,会调用下面的备选方案处理,返回一个提示信息的对象,调用的本之还是这个请求。 package com.baoji.springcloud.controller; import com.baoji.springcloud.pojo.Dept; import com.baoji.springcloud.service.DeptService; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; //提高ResultFul服务 @RestController public class DeptController { //属性注入service层 @Autowired private DeptService deptService; @GetMapping("/dept/get/{id}") @HystrixCommand(fallbackMethod = "hystrixGet") //当服务出现故障时,会调用下面的备选方法处理,返回一个提示信息的对象,调用的本之还是这个请求 public Dept get(@PathVariable("id") Long id){ Dept dept = deptService.getDeptById(id); if(dept == null){ throw new RuntimeException("id=>"+id+",不存在该用户,或者用户信息不存在!"); } return dept; } //备选方案 public Dept hystrixGet(@PathVariable("id") Long id){ return new Dept().setDeptno(id) .setDeptname("id=>"+id+",没有对应的信息,null->@Hystrix") .setDb_source("no this database in mysql"); } } 复制代码
@EnableCircuitBreaker
注解, 添加对熔断器的支持。 启动类代码如下:
package com.baoji.springcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; @SpringBootApplication @EnableEurekaClient //把客户端服务启动之后,将服务自动注册到服务端 @EnableDiscoveryClient //服务发现,获取微服务的一些信息 @EnableCircuitBreaker //添加对熔断器的支持 public class DeptProvidre_hystrix_8001 { public static void main(String[] args) { SpringApplication.run(DeptProvidre_hystrix_8001.class,args); } } 复制代码
prefer-ip-address: true
,这样配置了之后,我们就可以看到不在一台电脑上操作的服务ip地址了。
prefer-ip-address: true # true 可以显示服务的ip,而不是显示localhost 复制代码
服务降级是指 当服务器压力剧增的情况下,根据实际业务情况及流量,对一些服务和页面有策略的不处理或换种简单的方式处理,从而释放服务器资源以保证核心业务正常运作或高效运作。说白了,就是尽可能的把系统资源让给优先级高的服务。 资源有限,而请求是无限的。如果在并发高峰期,不做服务降级处理,一方面肯定会影响整体服务的性能,严重的话可能会导致宕机某些重要的服务不可用。所以,一般在高峰期,为了保证核心功能服务的可用性,都要对某些服务降级处理。比如当双11活动时,把交易无关的服务统统降级,如查看蚂蚁深林,查看历史订单等等。
服务降级主要用于什么场景呢?当整个微服务架构整体的负载超出了预设的上限阈值或即将到来的流量预计将会超过预设的阈值时,为了保证重要或基本的服务能正常运行,可以将一些 不重要 或 不紧急 的服务或任务进行服务的 延迟使用 或 暂停使用。
package com.baoji.springcloud.service; import com.baoji.springcloud.pojo.Dept; import feign.hystrix.FallbackFactory; import org.springframework.stereotype.Component; import java.util.List; @Component public class DeptClientServiceFailBackFactory implements FallbackFactory { public DeptClientService create(Throwable throwable) { return new DeptClientService() { public Dept quaryById(Long id) { return new Dept().setDeptno(id) .setDeptname("id"+id+"没有对应的信息,客户端提供了降级的信息,这个服务已经被关闭!") .setDb_source("没有数据"); } public List<Dept> queryAll() { return null; } public boolean addDept(Dept dept) { return false; } }; } } 复制代码
@FeignClient
注解中使用 fallbackFactory=DeptClientServiceFailBackFactory.class
属性即可,说明该业务接口调用出现错误时服务降级操作的类。 package com.baoji.springcloud.service; import com.baoji.springcloud.pojo.Dept; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import java.util.List; @Component //此注解是将此接口注入到spring中 //可以被其他服务直接调用,通过客户端去找springcloud-provider服务名,进行负载均衡 @FeignClient(value = "springcloud-provider",fallbackFactory = DeptClientServiceFailBackFactory.class) //fallbackFactory 表示该业务服务失败时调用失败业务服务的服务降级操作 public interface DeptClientService { @GetMapping("/dept/get/{id}") public Dept quaryById(@PathVariable("id") Long id); @GetMapping("/dept/list") public List<Dept> queryAll(); @PostMapping("/dept/add") public boolean addDept(Dept dept); } 复制代码
# 开启降级 feign和hystrix设置此配置时,feign和hystrix才能同时使用 feign: hystrix: enabled: true 复制代码
1、编写一个监控页面
Hystrix
依赖和 hystrix-dashboard
监控页面依赖 <!--Hystrix服务熔断与降级--> <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>springcloud</artifactId> <groupId>com.baoji</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>springcloud-consume-hystrix-dashboard</artifactId> <!--消费者--> <dependencies> <!--Hystrix服务熔断与降级--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix</artifactId> <version>1.4.6.RELEASE</version> </dependency> <!--Hystrix监控页面--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId> <version>1.4.6.RELEASE</version> </dependency> <!--Feign--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-feign</artifactId> <version>1.4.6.RELEASE</version> </dependency> <!--给消费者引入Ribbon依赖。让消费者从注册中心获取到服务列表的地址--> <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-ribbon --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-ribbon</artifactId> <version>1.4.6.RELEASE</version> </dependency> <!--给消费者加入Eureka客户端,方便消费者在注册中心发现更多服务--> <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> <version>1.4.3.RELEASE</version> </dependency> <!--实体类+web--> <dependency> <groupId>com.baoji</groupId> <artifactId>springcloud-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> </project> 复制代码
server: port: 9001 复制代码
@EnableHystrixDashboard
注解开启监控页面功能 package com.baoji.springcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard; @SpringBootApplication @EnableHystrixDashboard //开启监控页面功能 public class DeptConsumeDashboard_9001 { public static void main(String[] args) { SpringApplication.run(DeptConsumeDashboard_9001.class,args); } } 复制代码
spring-boot-starter-actuator
完善监控依赖,再添加 spring-cloud-starter-hystri
熔断机制依赖 <!--actuator完善监控的依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!--配置Hystrix依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix</artifactId> <version>1.4.3.RELEASE</version> </dependency> 复制代码
/actuator/hystrix.stream
,访问此url,该服务就可以被监控了。 package com.baoji.springcloud; 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.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.context.annotation.Bean; @SpringBootApplication @EnableEurekaClient //把客户端服务启动之后,将服务自动注册到服务端 @EnableDiscoveryClient //服务发现,获取微服务的一些信息 @EnableCircuitBreaker //添加对熔断器的支持 public class DeptProvidre_hystrix_8001 { public static void main(String[] args) { SpringApplication.run(DeptProvidre_hystrix_8001.class,args); } //注入一个可以被监控的servlet @Bean public ServletRegistrationBean hystrixMetricsStreamServlet(){ ServletRegistrationBean registrationBean = new ServletRegistrationBean(new HystrixMetricsStreamServlet()); registrationBean.addUrlMappings("/actuator/hystrix.stream"); //添加访问的路径,访问/actuator/hystrix.stream监控的页面就可以被监控了 return registrationBean; }} 复制代码
依次打开服务注册中心(7001),监控页面(9001),服务提供者(Hystrix_8001),访问localhost/7001,可以看到服务已经注册进来了
访问localhost:9001/hystrix,可以看到默认的监控主界面(:pig2:界面)
打开http://localhost:8001/dept/get/1
服务提供方,测试数据是否拿到
打开http://localhost/hystrix.stream
,查看是否ping数据
填写将要监控的页面url: http://localhost:8001/actuator/hystrix.stream
,时间和标题默认即可,即可进入监控界面
http://localhost:8001/dept/get/2
不断发送请求,可以发现监控页面出现圆圈变大,心跳波动明显等,它可以监控我们的请求信息。
故障实例和高压力实例
场景中使用 成功数
熔断数
错误请求数
超时数
线程池拒绝数
失败/异常数
最近10s内错误百分比
服务请求频率
断路状态
触发原因不太一样,服务熔断一般是某个服务(下游服务)故障引起,而服务降级一般是从整体负荷考虑;
管理目标的层次不太一样,熔断其实是一个框架级的处理,每个微服务都需要(无层级之分),而降级一般需要对业务有层级之分(比如降级一般是从最外围服务开始)
实现方式不太一样,服务降级具有代码侵入性(由控制器完成/或自动降级),熔断一般称为自我熔断。