SpringCloud_05 Hystrix
分布式系统面临的问题
-
复杂分布式体系结构中的应用程序有数十个依赖关系,每个依赖关系在某些时候将不可避免的失败!
-
服务雪崩
- 多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C又调用其他的微服务,这就是所谓的**“扇出”,如果扇出的链路上某个微服务的调用响应时间过长或者不可用,对微服务A的调用就会占用越来越多的系统资源,进而引起系统的崩溃,这就是所谓的“雪崩效应”**。
- 对于高流量的应用来说,单一的后端依赖可能会导致所有服务器上的所有资源都在几秒钟内饱和。比失败更糟糕的是这些应用程序还可能导致服务之间的延迟增加,备份队列,线程和其他系统资源紧张,导致整个系统发生更多的级联故障,这些都表示需要对故障和延迟进行隔离和管理,以便单个依赖关系的失败,不能取消整个应用程序或系统。
Hystrix简介
- Hystrix是一个用于处理分布式系统的延迟和容错的开源库。在分布式系统里,许多依赖不可以避免的会调用失败,比如超时、异常等。Hystrix能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。
- “断路器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个服务预期的,可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方法无法处理的异常,这样就可以保证服务调用方的线程不会被长时间,不必要的占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。
- Hystrix的功能:
- 服务降级。
- 服务熔断。
- 服务限流。
- 接近实时的监控。
- …
服务熔断
- 熔断机制是对应雪崩效应的一种微服务链路保护机制。
- 当扇出链路的某个微服务不可用或者响应时间太长时,会进行服务降级,进而熔断该节点微服务的调用,快速返回错误的响应信息。当检测到该节点微服务调用响应正常后恢复调用链路。
- 在SpringCloud框架里熔断机制通过Hystrix实现,Hystrix会监控微服务间调用的状况,当失败调用到一定阈值,缺省是5秒内20次调用失败就会启动熔断机制。
- 熔断机制的注解是@HystrixCommand。
Hystrix服务熔断实现
- 新建模块spring-cloud-provider-dept-hystrix-8001。
- 导入hystrix依赖。
<!-- hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
- 修改controller上的方法。
package com.jiu.controller;
import com.jiu.pojo.Dept;
import com.jiu.service.DeptService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/dept")
public class DeptController {
private DeptService deptService;
@Autowired
public void setDeptService(DeptService deptService) {
this.deptService = deptService;
}
@HystrixCommand(fallbackMethod = "hystrixQueryDeptByNo") //服务熔断
@GetMapping("/queryDeptByNo/{deptno}")
public Dept queryDeptByNo(@PathVariable("deptno") Long deptno){
Dept dept = deptService.queryDeptByNo(deptno);
if (dept == null){
throw new RuntimeException("deptno不存在");
}
return dept;
}
public Dept hystrixQueryDeptByNo(Long deptno){
return new Dept().setDeptno(deptno).setDname(deptno+"deptno不存在").setDb_source("no this database in mysql.");
}
}
- 在主启动类添加熔断支持。
package com.jiu;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient //在服务启动后自动注册到Eureka中
@EnableCircuitBreaker //添加熔断支持
public class SpringCloudProviderDeptHystrix8001 {
public static void main(String[] args) {
SpringApplication.run(SpringCloudProviderDeptHystrix8001.class, args);
}
}
- 启动7001、hystrix-8001、80项目测试。
-
访问http://localhost/dept/queryDeptByNo/5,数据正常时:
-
访问http://localhost/dept/queryDeptByNo/10,此时从数据库获取的数据是null:
服务降级
-
服务降级,当服务器压力剧增的情况下,根据当前业务情况及流量对一些服务和页面有策略的降级,以此释放服务器资源以保证核心任务的正常运行。比如电商平台,在针对618、双11等高峰情形下采用部分服务不出现或者延时出现的情形。
-
SpringCloud实现
- 在spring-cloud-api模块的service下编写DeptServiceFallBack类实现FallBack接口,并重写方法。内容提供者无法提供服务时,会调用降级操作,返回服务不可用等信息。
package com.jiu.service;
import com.jiu.pojo.Dept;
import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
/**
* @CLassName : DeptServiceFallBack
* @Description : TODO 服务降级
* @Author : 九九
* @Date : 2021/7/29,17:03
**/
@Component
public class DeptServiceFallBack implements FallbackFactory<DeptService> {
@Override
public DeptService create(Throwable throwable) {
return new DeptService() {
@Override
public List<Dept> queryAllDept() {
List<Dept> depts = new ArrayList<>();
depts.add(new Dept().setDeptno(500L).setDname("服务降级").setDb_source("no data."));
return depts;
}
@Override
public Dept queryDeptByNo(Long deptno) {
return new Dept().setDeptno(deptno).setDname("服务降级~").setDb_source("no data.");
}
};
}
}
- 在DeptService接口的@FeignClient注解添加fallbackFactory属性。
@FeignClient(value = "SPRING-CLOUD-PROVIDER-DEPT",fallbackFactory = DeptServiceFallBack.class)
public interface DeptService {
@GetMapping("/dept/queryAllDept")
public List<Dept> queryAllDept();
@GetMapping("/dept/queryDeptByNo/{deptno}")
public Dept queryDeptByNo(@PathVariable("deptno") Long deptno);
}
- 在消费者段spring-cloud-consumer-dept-feign-80模块的application.yml配置文件开启服务降级功能。
feign:
hystrix:
enabled: true
- 启动spring-cloud-eureka-7001,spring-cloud-provider-dept-8001,spring-cloud-consumer-dept-feign-80测试。
-
正常访问如下:
-
关闭spring-cloud-provider-dept-8001(比如淘宝“双十一期间关闭退款等服务”),重新访问测试。
-
此时访问该服务不是直接报错,而是显示服务降级:
Dashboard流监控
- 新建流监控模块spring-cloud-consumer-dept-hystrix-dashboard-9001,导入依赖。
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<dependency>
<groupId>com.jiu</groupId>
<artifactId>spring-cloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</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.6.RELEASE</version>
</dependency>
</dependencies>
- 编写配置文件application.yml
server:
port: 9001
hystrix:
dashboard:
proxy-stream-allow-list: "*"
- 编写主启动类,使用注解@EnableHystrixDashboard开启功能。
package com.jiu;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
@SpringBootApplication
@EnableHystrixDashboard //开启Dashboard
public class SpringCloudConsumerDeptDashboard9001 {
public static void main(String[] args) {
SpringApplication.run(SpringCloudConsumerDeptDashboard9001.class,args);
}
}
- 启动项目spring-cloud-consumer-dept-hystrix-dashboard-9001。
- 访问http://localhost:9001/hystrix
- 可以看到如下页面:
- 接着在需要监控的服务提供者增加配置类DashboardConfig。
package com.jiu.config;
import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class DashboardConfig {
@Bean
public ServletRegistrationBean hystrixMetricsStreamServlet(){
ServletRegistrationBean registrationBean = new ServletRegistrationBean(new HystrixMetricsStreamServlet());
registrationBean.addUrlMappings("/actuator/hystrix.stream");
return registrationBean;
}
}
- 启动注册中心7001,提供者spring-cloud-provider-dept-hystrix-8001以及消费者spring-cloud-consumer-dept-hystrix-dashboard-9001。
- 访问http://localhost:8001/actuator/hystrix.stream
- 可以看到有很多的ping:
- 输入监控信息:
- 显示如下页面:
- 绿色的数字表示访问成功数。
- 蓝色的表示熔断数。
- 靛青色的表示错误请求数。
- 黄色的表示超时数。
- 紫色的表示线程池拒绝数。
- 红色的表示失败/异常数。
- 百分数是最近10秒错误请求所占百分比。
- 左边的绿色圆圈表示实例健康程度,会在绿色<黄色<橙色<红色变化,健康程度依次递减。