6 Hystrix
6.1 是什么
官方介绍:https://github.com/Netflix/Hystrix/wiki
-
在现代的分布式系统中,通常一个服务会依赖多个其他的服务
- 如图所示是正常情况下的服务
- 当发生了某些错误时
- 当只有一个发生错误的时候,我们的服务器完全可以负载其他的正常服务
- 但是在高并发的情况下,仅一个错误就可以其很快的榨干服务器
-
这就是Hystrix的目的所在,通过某些手段,提高系统的容灾性能
服务雪崩与服务熔断
- 服务雪崩
- 在服务依赖链中,某些中间节点由于出现问题而无法及时响应调用,从而导致服务崩溃
- 服务熔断
- 在服务链路中,某些节点出现问题的时候,将该节点降级,熔断这次调用,使得调用者可以快速得到相应信息
区分服务熔断和服务降级
- 服务降级
- 通过限制部分低优先级别的服务来保证高优先级的服务正常运行
- 服务熔断
- 应对雪崩效应的链路自我保护机制,简单来说就是在发生某些错误的时候也能正常返回消息
- 未进行服务熔断时,程序在发生错误或异常的时候返回的数据可能是一个关于异常的消息之类的,这类消息常常无法被处理,从而导致整个服务链路的暂停。在实现了服务熔断之后,我们可以通过设置来使得返回的消息仍能继续在服务链路中流转下去,从而达到不堵塞服务链路的目的。
6.2 集成Hystrix
1)pom.xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
2)application.yaml
server:
port: 8001
spring:
application:
name: provider-eureka
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/cloud-db01?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
username: root
password: 123456
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.pbx.springcloud.pojo
eureka:
client:
service-url:
defaultZone: http://eureka7000:7000/eureka/, http://eureka7001:7001/eureka/, http://eureka7002:7002/eureka/, http://eureka7003:7003/eureka/, http://eureka7004:7004/eureka/
fetch-registry: true # 作为服务提供商,需要到Eureka中注册一下
register-with-eureka: true
instance:
instance-id: BruceXu:Eureka Provider:8001
3)启动类
@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker
public class HystrixApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixApplication.class, args);
}
}
4)改造controller
@RestController
@RequestMapping("/provider")
public class DepartmentController {
@Autowired
private DepartmentService service;
@Value("${eureka.instance.instance-id}")
private String source;
@GetMapping("/get/{id}")
@HystrixCommand(fallbackMethod = "fallbackGet")
public Message getDepartmentById(@PathVariable("id") Long id) {
Department res = service.getDepartmentById(id);
if (res == null) {
throw new RuntimeException("找不到");
}
return new Message(200, "hystrix", "查找成功", res);
}
// 回调方法的参数要和原方法的参数保持一致
public Message fallbackGet(@PathVariable Long id) {
return new Message(303, "hystrix", "查找失败,这是Hystrix的失败回调",
new Department().setId(id).setName("hystrix fallback"));
}
@GetMapping("/get/all")
public Message getAllDepartment(HttpServletRequest request) {
log.info(request.getRemoteAddr() + " try to get department list");
List<Department> list = service.getDepartmentList();
if (list.size() > 0) {
log.info("search success, + department nums = " + list.size());
return new Message(200, source, "查找成功", list);
} else {
log.info("search failed");
return new Message(400, source, "查找失败");
}
}
}
5)启动测试
- 正常调用
- 正常失败的回调
- 使用熔断之后的回调
6.3 服务降级
相比于服务熔断,是在服务端做手脚。服务降级则是在客户端做手脚
1)pom.xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
2)application.yaml
# 开启hystrix
feign:
hystrix:
enabled: true
3)启动类
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients("com.pbx.springcloud")
public class FeignConsumer {
public static void main(String[] args) {
SpringApplication.run(FeignConsumer.class, args);
}
}
4)服务降级配置
- 通过实现FallbackFactory接口来实现服务降级时的通知
@Component
public class FallbackService implements FallbackFactory<FeignService> {
@Override
public FeignService create(Throwable throwable) {
return new FeignService() {
@Override
public Message add(Department department) {
return null;
}
@Override
public Message getDepartmentById(Long id) {
return new Message(304, "client", "服务暂时不可用");
}
@Override
public Message getDepartmentList() {
return null;
}
};
}
}
5)测试
- 正常访问
- 服务降级之后
6.4 DashBoard监控
1)搭建监控端
-
pom.xml
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId> </dependency>
-
启动类
@EnableHystrixDashboard @SpringBootApplication public class DashboardApplication { public static void main(String[] args) { SpringApplication.run(DashboardApplication.class, args); } }
2)修改提供者
-
增加依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
-
增加对外提供监控信息的servlet bean
@Bean public ServletRegistrationBean hystrixDashboard() { ServletRegistrationBean bean = new ServletRegistrationBean(new HystrixMetricsStreamServlet()); bean.addUrlMappings("/actuator/hystrix.stream"); return bean; }
-
增加配置
management: endpoints: web: exposure: include: hystrix.stream
3)测试
4)数据解读
- 圆圈大小表示当前的并发量
- 绿色表示正常
- 蓝色是触发熔断
- 黄色是超时数
- 紫色是线程池拒绝数
- 红色则是失败或异常