在微服务架构中,一个请求需要调用多个服务是非常常见的。
如客户端访问A服务,而A服务需要调用B服务,B服务需要调用C服务,由于网络原因或者自身的原因,如果B服务或者C服务不能及时响应,A服务将处于阻塞状态,直到B服务C服务响应。
此时若有大量的请求涌入,容器的线程资源会被消耗完毕,导致服务瘫痪。
服务与服务之间的依赖性,故障会传播,造成连锁反应,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的“雪崩”效应。
雪崩是系统中的蝴蝶效应导致其发生的原因多种多样,有不合理的容量设计,或者是高并发下某一个方法响应变慢,亦或是某台机器的资源耗尽。
从源头上我们无法完全杜绝雪崩源头的发生,但是雪崩的根本原因来源于服务之间的强依赖,所以我们可以提前评估,做好熔断,隔离,限流。
顾名思义,它是指将系统按照一定的原则划分为若干个服务模块,各个模块之间相对独立,无强依赖。
当有故障发生时,能将问题和影响隔离在某个模块内部,而不扩散风险,不波及其它模块,不影响整体的系统服务。
熔断这一概念来源于电子工程中的断路器(Circuit Breaker)。
在互联网系统中,当下游服务因访问压力过大而响应变慢或失败,上游服务为了保护系统整体的可用性,可以暂时切断对下游服务的调用。
这种牺牲局部,保全整体的措施就叫做熔断。
所谓降级,就是当某个服务熔断之后,服务器将不再被调用,此时客户端可以自己准备一个本地的fallback回调,返回一个缺省值。 也可以理解为兜底。切断以后资源被释放,其他的服务性能提升
限流可以认为服务降级的一种,限流就是限制系统的输入和输出流量已达到保护系统的目的。
一般来说系统的吞吐量是可以被测算的,为了保证系统的稳固运行,一旦达到的需要限制的阈值,就需要限制流量并采取少量措施以完成限制流量的目的。
比方:推迟解决,拒绝解决,或者者部分拒绝解决等等。
Hystrix是由Netflix开源的一个延迟和容错库,用于隔离访问远程系统、服务或者第三方库,防止级联失败,从而提升系统的可用性与容错性。Hystrix主要通过以下几点实现延迟和容错。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
在RestOrderApplication当中添加 @EnableCircuitBreaker
注解开启对熔断器的支持。
可以看到,我们类上的注解越来越多,在微服务中,经常会引入上面的三个注解,于是Spring就提供了
一个组合注解:@SpringCloudApplication
package cn.itbluebox.order;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
//@SpringBootApplication
//激活Hystrix
//@EnableCircuitBreaker
@EntityScan("cn.itbluebox.order.entity")
@SpringCloudApplication
public class RestOrderApplication {
@LoadBalanced
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(RestOrderApplication.class,args);
}
}
@RestController
@RequestMapping("/order")
/** * @DefaultProperties : 指定此接口中公共的熔断设置 * 如果过在@DefaultProperties指定了公共的降级方法 * 在@HystrixCommand不需要单独指定了 */
//@DefaultProperties(defaultFallback = "defaultFallBack")
public class OrderController {
@Autowired
private RestTemplate restTemplate;
/** * 使用注解配置熔断保护 * fallbackmethod : 配置熔断之后的降级方法 */
@HystrixCommand(fallbackMethod = "orderFallBack")
@RequestMapping(value = "/buy/{id}",method = RequestMethod.GET)
public Product findById(@PathVariable Long id) {
if(id != 1) {
throw new RuntimeException("服务器异常");
}
return restTemplate.getForObject("http://service-product/product/1",Product.class);
}
/** * 降级方法 * 和需要收到保护的方法的返回值一致 * 方法参数一致 */
public Product orderFallBack(Long id) {
Product product = new Product();
product.setProductName("触发降级方法");
return product;
}
}
有代码可知,为 findById
方法编写一个回退方法orderFallBack,
该方法与 findById方法具有相同的参数与返回值类型,该方法返回一个默认的错误信息。
在 findById
方法上,使用注解@HystrixCommand
的fallbackMethod
属性,指定熔断触发的降级方法是 orderFallBack
。
因为熔断的降级逻辑方法必须跟正常逻辑方法保证:
相同的参数列表和返回值声明。在 findById方法上 HystrixCommand(fallbackMethod = "orderFallBack")
用来声明一个降级逻辑的方法
访问:http://localhost:9004/order/buy/1
在之前的案例中,请求在超过1秒后都会返回错误信息,这是因为Hystix的默认超时时长为1,我们可以通过配置修改这个值:
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 3000 #默认的连接的超时时间是1秒,若1秒没有返回数据,会自动触发降级逻辑
启动测试
http://localhost:9004/order/buy/1
这时我们将product_service停止
再次访问:http://localhost:9004/order/buy/1
运行成功:触发降级方法
在OrderController当中指定统一的降级方法
package cn.itbluebox.order.controller;
import cn.itbluebox.order.entity.Product;
import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
@RequestMapping("/order")
/** * @DefaultProperties : 指定此接口中公共的熔断设置 * 如果过在@DefaultProperties指定了公共的降级方法 * 在@HystrixCommand不需要单独指定了 */
@DefaultProperties(defaultFallback = "defaultFallBack")
public class OrderController {
@Autowired
private RestTemplate restTemplate;
/** * 使用注解配置熔断保护 * fallbackmethod : 配置熔断之后的降级方法 */
@HystrixCommand
@RequestMapping(value = "/buy/{id}",method = RequestMethod.GET)
public Product findById(@PathVariable Long id) {
if(id != 1) {
throw new RuntimeException("服务器异常");
}
return restTemplate.getForObject("http://service-product/product/1",Product.class);
}
/* 指定统一的降级方法 参数:没有参数 */
public Product defaultFallBack(){
Product product = new Product();
product.setProductName("触发统一的降级方法");
return product;
}
/** * 降级方法 * 和需要收到保护的方法的返回值一致 * 方法参数一致 */
public Product orderFallBack(Long id) {
Product product = new Product();
product.setProductName("触发降级方法");
return product;
}
}
启动运行测试
访问http://localhost:9004/order/buy/1
SpringCloud Fegin默认已为Feign整合了hystrix,所以添加Feign依赖后就不用在添加hystrix,那么怎么才能让Feign的熔断机制生效呢,只要按以下步骤开发:
在Feign中已经内置了hystrix,但是默认是关闭的需要在工程的 application.yml 中开启对hystrix的支持
hystrix: #在feign中开启hystrix熔断
enabled: true
基于Feign实现熔断降级,那么降级方法需要配置到FeignClient接口的实现类中
在order_service_feign当中创建ProductFeignClientCallBack
package cn.itbluebox.order.feign;
import cn.itbluebox.order.entity.Product;
import org.springframework.stereotype.Component;
@Component
public class ProductFeignClientCallBack implements ProductFeignClient {
/** * 熔断降级的方法 */
public Product findById(Long id) {
Product product = new Product();
product.setProductName("feign调用触发熔断降级方法");
return product;
}
}
访问:http://localhost:9003/order/buy/1
#默认的连接的超时时间是1秒,若1秒没有返回数据,会自动触发降级逻辑
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 3000 #默认的连接的超时时间是1秒,若1秒没有返回数据,会自动触发降级逻辑,这里设置的是3秒
我们知道,当请求失败,被拒绝,超时的时候,都会进入到降级方法中。但进入降级方法并不意味着断路器已经被打开。那么如何才能了解断路器中的状态呢?
除了实现容错功能,Hystrix还提供了近乎实时的监控HystrixCommandHystrixObservableCommand在执行时,会生成执行结果和运行指标。
比如每秒的请求数量,成功数量等。
这些状态会暴露在Actuator提供的/health端点中。
只需为项目添加 spring-boot-actuator 依赖,重启项目,
即可看到实时的监控数据。
<!--引入Hystrix的监控信息 -->
<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>
package cn.itbluebox.order;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EntityScan("cn.itbluebox.order.entity")
//激活Feign
@EnableFeignClients
//激活Hystrix
@EnableCircuitBreaker
public class FeignOrderApplication {
public static void main(String[] args) {
SpringApplication.run(FeignOrderApplication.class,args);
}
}
management:
endpoints:
web:
exposure:
include: '*'
访问:http://localhost:9003/actuator/hystrix.stream
访问http://localhost:9003/order/buy/1
再次访问:http://localhost:9003/actuator/hystrix.stream
刚刚讨论了Hystrix的监控,但访问/hystrix.stream接口获取的都是已文字形式展示的信息。很难通过文字直观的展示系统的运行状态,所以Hystrix官方还提供了基于图形化的DashBoard(仪表板)监控平台。
Hystrix仪表板可以显示每个断路器(被@HystrixCommand注解的方法)的状态。
在启动类使用@EnableHystrixDashboard
注解激活仪表盘项目
package cn.itbluebox.order;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EntityScan("cn.itbluebox.order.entity")
//激活Feign
@EnableFeignClients
//激活Hystrix
@EnableCircuitBreaker
//激活仪表盘项目
@EnableHystrixDashboard
public class FeignOrderApplication {
public static void main(String[] args) {
SpringApplication.run(FeignOrderApplication.class,args);
}
}
访问:http://localhost:9003/hystrix
在下列输入框当中输入:http://localhost:9003/actuator/hystrix.stream
点击:Monitor Stream
参数解释
在微服务架构体系中,每个服务都需要配置Hystrix DashBoard监控。
如果每次只能查看单个实例的监控数据,就需要不断切换监控地址,这显然很不方便。要想看这个系统的Hystrix Dashboard数据就需要用到Hystrix Turbine。
Turbine是一个聚合所有Hystrix 监控数据的工具,他可以将所有相关微服务的Hystrix 监控数据聚合到一起,方便使用。引入Turbine后,整个监控系统架构如下:
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-turbine</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>
</dependencies>
在application.yml的配置文件中开启turbine并进行相关配置
server:
port: 8031
spring:
application:
name: hystrix-turbine
eureka:
client:
service-url:
defaultZone: http://localhost:9000/eureka/
instance:
prefer-ip-address: true
turbine:
# 要监控的微服务列表,多个用,分隔
appConfig: service-order
clusterNameExpression: "'default'"
turbine会自动的从注册中心中获取需要监控的微服务,并聚合所有微服务中的/hystrix.stream
数据
package cn.itbluebox;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
import org.springframework.cloud.netflix.turbine.EnableTurbine;
@SpringBootApplication
@EnableTurbine //激活Turbine
@EnableHystrixDashboard //激活Hystrix页面监控平台
public class TurbineApplication {
public static void main(String[] args) {
SpringApplication.run(TurbineApplication.class, args);
}
}
作为一个独立的监控项目,需要配置启动类,开启HystrixDashboard监控平台,并激活Turbine
测试
访问其他微服务:http://localhost:9003/order/buy/1
浏览器访问 http://localhost:8031/hystrix 展示HystrixDashboard。
并在url位置输入 http://localhost:8031/turbine.stream,动态根据turbine.stream数据展示多个微服务的监控数据
hystrix可以对请求失败的请求,以及被拒绝,或者超时的请求进行统一的降级处理。
CLOSED 、
OPEN 、
HALF_OPEN
熔断器默认关闭状态,当触发熔断后状态变更为OPEN ,
在等待到指定的时间,Hystrix会放请求检测服务是否开启,
这期间熔断器会变为 HALF_OPEN 半开启状态,
熔断探测服务可用则继续变更为 CLOSED 关闭熔断器。
断路器:Closed(关闭)
断路器:Closed(关闭),Open(开启),Half Open(半开)
product_service
:将之前的延时屏蔽掉修改order_service_rest当中的OrderController
package cn.itbluebox.order.controller;
import cn.itbluebox.order.entity.Product;
import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
@RequestMapping("/order")
/** * @DefaultProperties : 指定此接口中公共的熔断设置 * 如果过在@DefaultProperties指定了公共的降级方法 * 在@HystrixCommand不需要单独指定了 */
//@DefaultProperties(defaultFallback = "defaultFallBack")
public class OrderController {
@Autowired
private RestTemplate restTemplate;
/** * 使用注解配置熔断保护 * fallbackmethod : 配置熔断之后的降级方法 */
@HystrixCommand(defaultFallback = "orderFallBack")
@RequestMapping(value = "/buy/{id}", method = RequestMethod.GET)
public Product findById(@PathVariable Long id) {
if (id != 1) {
throw new RuntimeException("服务器异常");
}
return restTemplate.getForObject("http://service-product/product/1", Product.class);
}
/* 指定统一的降级方法 参数:没有参数 */
public Product defaultFallBack() {
Product product = new Product();
product.setProductName("触发统一的降级方法");
return product;
}
/** * 降级方法 * 和需要收到保护的方法的返回值一致 * 方法参数一致 */
public Product orderFallBack(Long id) {
Product product = new Product();
product.setProductName("触发降级方法");
return product;
}
}
management:
endpoints:
web:
exposure:
include: '*'
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 3000 #默认的连接的超时时间是1秒,若1秒没有返回数据,会自动触发降级逻辑
circuitBreaker:
requestVolumeThreshold: 20 #触发熔断的最小请求次数,默认20 每10秒
sleepWindowInMilliseconds: 10000 #熔断多少秒后去尝试请求 默认 5 打开状态时间
errorThresholdPercentage: 50 #触发熔断的失败请求最小占比,默认50%
访问测试:http://localhost:9004/order/buy/1
多次访问:http://localhost:9004/order/buy/2
访问:http://localhost:8031/hystrix/monitor?stream=http%3A%2F%2Flocalhost%3A8031%2Fturbine.stream
服务熔断开启
访问:http://localhost:9004/order/buy/1
等待5秒访问熔断关闭
再次访问:http://localhost:9004/order/buy/1
微服务使用Hystrix熔断器实现了服务的自动降级,让微服务具备自我保护的能力,提升了系统的稳定性,也较好的解决雪崩效应。其使用方式目前支持两种策略:
线程池和型号量两种策略功能支持对比如下:
hystrix.command.default.execution.isolation.strategy
: 配置隔离策略
ExecutionIsolationStrategy.SEMAPHORE
信号量隔离
ExecutionIsolationStrategy.THREAD
线程池隔离
hystrix.command.default.execution.isolation.maxConcurrentRequests
: 最大信号量上限
配置隔离
isolation:
strategy: ExecutionIsolationStrategy.SEMAPHORE #信号量隔离
# ExecutionIsolationStrategy.THREAD 线程池隔离
Hystrix 底层基于 RxJava,RxJava 是响应式编程开发库,因此Hystrix的整个实现策略简单说即:把一个HystrixCommand封装成一个Observable(待观察者),针对自身要实现的核心功能,对Observable进行各种装饰,并在订阅各步装饰的Observable,以便在指定事件到达时,添加自己的业务。
Hystrix主要有4种调用方式:
主要的执行逻辑:
每次调用创建一个新的HystrixCommand,把依赖调用封装在run()方法中.
执行execute()/queue做同步或异步调用.
判断熔断器(circuit-breaker)是否打开,如果打开跳到步骤8,进行降级策略,如果关闭进入步骤.
判断线程池/队列/信号量是否跑满,如果跑满进入降级步骤8,否则继续后续步骤.
调用HystrixCommand的run方法.运行依赖逻辑,依赖逻辑调用超时,进入步骤8.
判断逻辑是否调用成功。返回成功调用结果;调用出错,进入步骤8.
计算熔断器状态,所有的运行状态(成功, 失败, 拒绝,超时)上报给熔断器,用于统计从而判断熔断器
状态.
getFallback()降级逻辑。以下四种情况将触发getFallback调用:
run()方法抛出非HystrixBadRequestException异常。
run()方法调用超时
熔断器开启拦截调用
线程池/队列/信号量是否跑满
没有实现getFallback的Command将直接抛出异常,fallback降级逻辑调用成功直接返回,降级逻辑调用失败抛出异常.
返回执行成功结果
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/qq_44757034/article/details/121496570
内容来源于网络,如有侵权,请联系作者删除!