一、概述
重点:能让服务的调用方,够快的知道被调方挂了!不至于说让用户在等待。
Hystix 是 Netflix 开源的一个延迟和容错库,用于隔离访问远程服务、第三方库,防止出现级联失败(雪崩)。
雪崩:一个服务失败,导致整条链路的服务都失败的情形。
Hystix 主要功能
二、隔离
2.1 线程池隔离
没有hystrix,a重试100次,才知道c挂了!
使用了hystrix,更细分线程池,只需要重试40次,让a更快的知道c挂了
2.2 信号量隔离
没有hystrix,a一个带着认证信息的线程,重试100次,才知道c挂了!
使用了hystrix,更细分线程池,一个带着认证信息的线程,只需要重试40次,让a更快的知道c挂了
三、服务降级
3.1 服务提供方降级(异常,超时)
a、在服务提供方,引入 hystrix 依赖
<!-- hystrix -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
b、方法
/** 定义降级方法 返回特殊对象
* 1方法的返回值要和原方法一致
* 2方法参数和原方法一样
*/
public Goods findById_fallback(Integer id){
Goods goods=new Goods();
goods.setGoodId(-1);
goods.setTitle("provider提供方降级!");
goods.setPrice(-9.9);
goods.setStock(-10);
return goods;
}
c、使用 @HystrixCommand 注解配置降级方法
@GetMapping("/findById/{id}")
@HystrixCommand(fallbackMethod = "findById_fallback",commandProperties = {
//设置Hystrix的超时时间,默认1s
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "3000")
})
public Goods findById(@PathVariable("id") Integer id){
Goods goods = goodsService.findById(id);
goods.setTitle(goods.getTitle()+"|端口号:"+port);
//模拟出异常
// int a=1/0;
//模拟业务逻辑比较繁忙
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return goods;
}
d、在启动类上开启Hystrix功能:@EnableCircuitBreaker
测试:http://localhost:9000/order/add/10
1.出错,服务方降级了
2.3000超时,服务方降级了
3.2 消费方降级
a、feign 组件已经集成了 hystrix 组件
b、定义feign 调用接口实现类,复写方法,即 降级方法
GoodsFeignClientFallback
package com.liming.consumer.feign;
import com.liming.consumer.domain.Goods;
import org.springframework.stereotype.Component;
@Component
public class GoodsFeignCallback implements GoodsFeign{
@Override
public Goods findById(Integer id) {
Goods goods=new Goods();
goods.setGoodId(-2);
goods.setTitle("调用方降级了!");
goods.setPrice(-5.5);
goods.setStock(-5);
return goods;
}
}
c、在 @FeignClient 注解中使用 fallback 属性设置降级处理类
GoodsFeignClient
package com.liming.consumer.feign;
import com.liming.consumer.config.FeignLogConfig;
import com.liming.consumer.domain.Goods;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(value = "EUREKA-PROVIDER",configuration = FeignLogConfig.class,fallback = GoodsFeignCallback.class)
public interface GoodsFeign {
@GetMapping("/goods/findById/{id}")
public Goods findById(@PathVariable("id") Integer id);
}
d、配置开启
# 开启feign对hystrix的支持
feign:
hystrix:
enabled: true
测试:停掉provider
http://localhost:9000/order/add/10
四、熔断
provider
package com.liming.proviver.controller;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import com.liming.proviver.domain.Goods;
import com.liming.proviver.service.GoodsService;
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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/goods")
public class GoodsController {
@Autowired
GoodsService goodsService;
@Value("${server.port}")
int port;
@GetMapping("/findById/{id}")
@HystrixCommand(fallbackMethod = "findById_fallback",commandProperties = {
//设置Hystrix的超时时间,默认1s
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "3000")
})
public Goods findById(@PathVariable("id") Integer id){
Goods goods = goodsService.findById(id);
goods.setTitle(goods.getTitle()+"|端口号:"+port);
if(id==1){
//模拟出异常
int a=1/0;
}
//模拟出异常
// int a=1/0;
//模拟业务逻辑比较繁忙
// try {
// Thread.sleep(5000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
return goods;
}
/** 定义降级方法 返回特殊对象
* 1方法的返回值要和原方法一致
* 2方法参数和原方法一样
*/
public Goods findById_fallback(Integer id){
Goods goods=new Goods();
goods.setGoodId(-1);
goods.setTitle("provider提供方降级!");
goods.setPrice(-9.9);
goods.setStock(-10);
return goods;
}
}
访问两个接口
1、http://localhost:9000/order/add/10
2、多次访问 http://localhost:9000/order/add/1
3、导致10也不能访问了
4.再过一会儿,半开状态
http://localhost:9000/order/add/10
Hyst rix 熔断机制,用于监控微服务调用情况,当失败的情况达到预定的阈值(5秒失败20次),会打开断路器,拒绝所有请求,直到服务恢复正常为止。
circuitBreaker.sleepWindowInMilliseconds:监控时间
circuitBreaker.requestVolumeThreshold:失败次数
circuitBreaker.errorThresholdPercentage:失败率
提供者controller中
@HystrixCommand(fallbackMethod = "findOne_fallback",commandProperties = {
//设置Hystrix的超时时间,默认1s
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "3000"),
//监控时间 默认5000 毫秒
@HystrixProperty(name="circuitBreaker.sleepWindowInMilliseconds",value = "5000"),
//失败次数。默认20次
@HystrixProperty(name="circuitBreaker.requestVolumeThreshold",value = "20"),
//失败率 默认50%
@HystrixProperty(name="circuitBreaker.errorThresholdPercentage",value = "50")
})
五、熔断监控-运维
Hystrix 提供了 Hystrix-dashboard 功能,用于实时监控微服务运行状态。
但是Hystrix-dashboard只能监控一个微服务。
Netflix 还提供了 Turbine ,进行聚合监控。
5.1 Turbine聚合监控
a、 创建监控模块
创建hystrix-monitor模块,使用Turbine聚合监控多个Hystrix dashboard功能
b、引入Turbine聚合监控起步依赖
<?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>spring-cloud-parent</artifactId>
<groupId>com.liming</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>hystrix-monitor</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-turbine</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
c、修改application.yml
spring:
application:
name: hystrix-monitor
server:
port: 8769
turbine:
combine-host-port: true
# 配置需要监控的服务名称列表
app-config: EUREKA-PROVIDER,EUREKA-CONSUMER
cluster-name-expression: "'default'"
aggregator:
cluster-config: default
#instanceUrlSuffix: /actuator/hystrix.stream
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
hystrix:
dashboard:
proxy-stream-allow-list: "*"
d、创建启动类
package com.liming.monitor;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
import org.springframework.cloud.netflix.turbine.EnableTurbine;
@SpringBootApplication
@EnableEurekaClient
@EnableTurbine //开启Turbine 很聚合监控功能
@EnableHystrixDashboard //开启Hystrix仪表盘监控功能
public class HystrixMonitorApp {
public static void main(String[] args) {
SpringApplication.run(HystrixMonitorApp.class,args);
}
}
5.2 2、修改被监控模块
需要分别修改 hystrix-provider 和 hystrix-consumer 模块:
a、导入依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
b、配置Bean
此处为了方便,将其配置在启动类中
@Bean
public ServletRegistrationBean getServlet() {
HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
registrationBean.setLoadOnStartup(1);
registrationBean.addUrlMappings("/actuator/hystrix.stream");
registrationBean.setName("HystrixMetricsStreamServlet");
return registrationBean;
}
c、启动类上添加注解@EnableHystrixDashboard
@EnableDiscoveryClient
@EnableEurekaClient
@SpringBootApplication
@EnableFeignClients
@EnableHystrixDashboard // 开启Hystrix仪表盘监控功能
public class ConsumerApp {
public static void main(String[] args) {
SpringApplication.run(ConsumerApp.class,args);
}
@Bean
public ServletRegistrationBean getServlet() {
HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
registrationBean.setLoadOnStartup(1);
registrationBean.addUrlMappings("/actuator/hystrix.stream");
registrationBean.setName("HystrixMetricsStreamServlet");
return registrationBean;
}
}
5.3 启动测试
a、启动服务:
-
eureka-server
-
hystrix-provider
-
hystrix-consumer
-
hystrix-monitor
b、访问:
在浏览器访问http://localhost:8769/hystrix/
进入Hystrix Dashboard界面
界面中输入监控的Url地址 http://localhost:8769/turbine.stream
,监控时间间隔2000毫秒和title,如下图
- 实心圆:它有颜色和大小之分,分别代表实例的监控程度和流量大小。如上图所示,它的健康度从绿色、黄色、橙色、红色递减。通过该实心圆的展示,我们就可以在大量的实例中快速的发现故障实例和高压力实例。
- 曲线:用来记录 2 分钟内流量的相对变化,我们可以通过它来观察到流量的上升和下降趋势。