做网站南昌,两学一做 专题网站,网站建设业务饱和了吗,制作图片软件免费版1. 雪崩效应
复杂的分布式体系结构中的应用程序很多都有依赖调用关系, 每个依赖关系有些时候会出现不可避免的失败(异常,超时,网络故障等). 这种多个服务层调用#xff0c;基础服务的故障可能会导致级联故障#xff0c;进而造成整个系统不可用的情况#xff0c;这种现象被称…1. 雪崩效应
复杂的分布式体系结构中的应用程序很多都有依赖调用关系, 每个依赖关系有些时候会出现不可避免的失败(异常,超时,网络故障等). 这种多个服务层调用基础服务的故障可能会导致级联故障进而造成整个系统不可用的情况这种现象被称为服务雪崩效应。 服务雪崩效应是一种因“服务提供者”的不可用导致“服务消费者”的不可用,并将不可用逐渐放大的过程。 如果下图所示A作为服务提供者B为A的服务消费者C和D是B的服务消费者。A不可用引起了B的不可用并将不可用像滚雪球一样放大到C和D时雪崩效应就形成了。
2. 服务熔断
针对雪崩效应, Netflix公司提供了解决方案: Hystrix. →GitHub开源 Hystrix是一个用于处理分布式系统的延迟和容错的开源库在分布式系统里许多依赖不可避免的会调用失败比如超时、异常等Hystrix能够保证在一个依赖出问题的情况下不会导致整体服务失败避免级联故障以提高分布式系统的弹性。
2.1 熔断原理
“断路器”本身是一种开关装置当某个服务单元发生故障之后通过断路器的故障监控类似熔断保险丝向调用方返回一个符合预期的、可处理的备选响应FallBack而不是长时间的等待或者抛出调用方无法处理的异常这样就保证了服务调用方的线程不会被长时间、不必要地占用从而避免了故障在分布式系统中的蔓延乃至雪崩。
比如家里的电路熔断器, 如果电路发生短路能立刻熔断电路, 避免发生灾难. 在分布式系统中应用这种模式后, 服务调用方可以自己进行判断某些服务反应慢或者存在大量超时的情况时, 能够主动熔断, 防止整个系统被拖垮.
不同于电路熔断的是,Hystrix可以实现弹性容错, 当情况发生好转之后, 可以自动重连. 通过断路的方式, 可以将后续请求直接拒绝掉, 一段时间之后允许部分请求通过(半开), 如果调用成功则回到电路闭合状态, 否则继续断开(全开).
2.2 熔断器的使用
2.2.1 导入依赖
因为服务熔断发生在服务调用方, 所以需要在服务消费者应用添加Hystrix依赖.
dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-netflix-hystrix/artifactId
/dependency2.2.2 启动类开启Hystrix配置
需要在服务消费者应用的启动类上添加EnableHystrix注解开启熔断器配置.
SpringBootApplication
EnableEurekaClient // 开启Eureka客户端配置
EnableDiscoveryClient // 开启服务发现
// RibbonClient 在启动微服务时加载自定义的Ribbon配置类
// 这个自定义配置类不能放在ComponentScan所扫描的当前包下及子包下面,否则自定义配置类会被所有的Ribbon客户端共享, 达不到定制化目的.
// 下面配置解释: 对microservicecloud-provider微服务使用自定义Ribbon策略MyRule
RibbonClient(name microservicecloud-provider, configuration {MyRuleConfig.class})
EnableFeignClients // 开启Feign声明式调用的配置
EnableHystrix // 开启Hystrix熔断器配置
public class ConsumerApplication {public static void main(String[] args) {SpringApplication.run(ConsumerApplication.class, args);}}低版本SpringCloud使用的是EnableCircuitBreaker注解, 高版本SpringCloud使用的EnableHystrix注解, EnableHystrix注解包含了EnableCircuitBreaker.
Target({ElementType.TYPE})
Retention(RetentionPolicy.RUNTIME)
Documented
Inherited
EnableCircuitBreaker // 兼容低版本的注解
public interface EnableHystrix {
}2.2.3 声明服务熔断方法
在controller层的服务调用api方法上添加HystrixCommand注解, 使用其fallbackMethod属性声明服务熔断方法. com.atguigu.springcloud.controller.ConsumerController#findById3
/*** 使用Eureka的服务发现api调用远程服务提供方(负载均衡Ribbon-简化版)* RestTemplate配置bean需要添加LoadBalanced注解, RestTemplate才能自动负载均衡* Ribbon底层使用了{link DiscoveryClient}服务发现组件* param id* return*/
GetMapping(value /findById3/{id})
// 熔断器方法: 一旦调用服务提供方失败并抛出异常后,就会自动跳转执行fallbackMethod指定的方法
HystrixCommand(fallbackMethod fallbackHandle)
public Dept findById3(PathVariable(value id) Integer id) {Dept dept restTemplate.getForObject(http://microservicecloud-provider /dept/ id, Dept.class);if (null dept) throw new RuntimeException(查询失败);return dept;
}提示 (1) HystrixCommand注解如果没有指定服务熔断后的降级方法, 还可以在类上使用注解DefaultProperties指定全局服务降级 处理. DefaultProperties(defaultFallback default_gloab_fallback) (2) HystrixCommand注解的commandProperties属性可以设置超时时间. HystrixCommand(fallbackMethod “fallbackHandle”, // 超时5s发生服务降级 commandProperties {HystrixProperty(name “execution.isolation.thread.timeoutInMilliseconds”, value “5000”)}) 2.2.4 编写服务熔断方法
在当前服务调用api的controller类中添加声明的服务熔断方法. com.atguigu.springcloud.controller.ConsumerController#fallbackHandle
/*** Hystrix熔断器的熔断方法* 返回值类型要和上面保持一致, 否则访问会报错.* return*/
private Dept fallbackHandle(PathVariable(value id) Integer id) {log.info(没有查到id为{}的dept信息,发生了熔断..);Dept dept Dept.builder().deptno(id).dname(没有查到id为 id 的dept信息,发生了熔断).build();return dept;
}注意: 服务熔断方法的返回值类型要和服务调用api方法的返回值类型保持一致, 否则访问会抛出异常. 比如下面这样:
private String fallbackHandle(PathVariable(value id) Integer id) {log.info(没有查到id为{}的dept信息,发生了熔断..);return 发生熔断了;
}因为服务熔断方法的返回值类型(String)和服务调用api方法的返回值类型(Dept)不一致, 导致访问报错. 下图所示:
2.2.5 服务熔断测试
场景一: 关闭服务提供方 将服务提供方关闭后,访问服务调用api, 应用并没有一直等待服务提供者的响应, 而是执行了我们声明的服务熔断方法, 给客户合适的反馈, 实际应用场景中应该返回提示界面给客户. 现在将服务提供方应用启动, 再次访问上面的api, 调用成功. 场景二: 服务提供方正常, 访问不存在的dept信息 如果访问系统库表中不存在的dept信息时, 也就是服务提供方没有查询到信息, 返回null, 然后在服务调用方通过非空判断抛出异常, 是否也会走到服务熔断方法中去呢? 下面我们看测试将结果. 也一样的进行了熔断处理. 存在的问题 HystrixCommand(fallbackMethod “fallbackHandle”)服务熔断处理方式存在调用逻辑和熔断逻辑高度耦合的缺陷, 而且当调用的api方法很多时, 每个方法都要配置一个服务熔断的fallback方法, 会造成方法臃肿. 如何解决呢? 下面的Feign提供了面向接口编程的解决方案: 服务降级 3. 服务降级
3.1 导入依赖
Feign默认就有对Hystix的集成.
dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-openfeign/artifactId
/dependency3.2 开启Feign对Hystrix的支持
默认情况下Hystix是关闭的。我们需要通过下面的配置参数来开启
#OpenFeign内置有Hystrix, 需要开启Hystrix(熔断器)
feign:hystrix:enabled: true3.3 启动类开启Feign配置
启动类上不要忘记了EnableFeignClients注解, 开启Feign功能的配置.
SpringBootApplication
EnableEurekaClient // 开启Eureka客户端配置
EnableDiscoveryClient // 开启服务发现
// RibbonClient 在启动微服务时加载自定义的Ribbon配置类
// 这个自定义配置类不能放在ComponentScan所扫描的当前包下及子包下面,否则自定义配置类会被所有的Ribbon客户端共享, 达不到定制化目的.
// 下面配置解释: 对microservicecloud-provider微服务使用自定义Ribbon策略MyRule
RibbonClient(name microservicecloud-provider, configuration {MyRuleConfig.class})
EnableFeignClients // 开启Feign声明式调用的配置
EnableHystrix // 开启Hystrix熔断器配置
public class ConsumerApplication {public static void main(String[] args) {SpringApplication.run(ConsumerApplication.class, args);}}3.4 编写FeignClient接口
面向接口编程, 类似mybatis中的mapper接口, 使用的时候底层会自动生成动态代理对象. 接口类上添加FeignClient注解, 使用value属性指定要调用的服务提供方的服务ID, 使用fallbackFactory属性指定服务降级的处理类.
/*** 类描述Feign声明式调用的接口* fallback 或 fallbackFactory属性指定服务降级处理逻辑* Author wang_qz* Date 2021/10/27 20:44* Version 1.0*/
FeignClient(value microservicecloud-provider, fallbackFactory DeptFeignClientFallbackFactory.class)
public interface DeptFeignClientService {PostMapping(value /dept/add)boolean add(Dept dept);GetMapping(value /dept/{id})Dept get(PathVariable(value id) Integer id);GetMapping(value /dept)ListDept findAll();
}3.5 编写服务降级类
编写服务降级逻辑处理的类, 需要继承FallbackFactoryT , 然后重写feign.hystrix.FallbackFactory.Default#create方法.
package com.atguigu.springcloud.service.impl;import com.atguigu.springcloud.entities.Dept;
import com.atguigu.springcloud.service.DeptFeignClientService;
import feign.hystrix.FallbackFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;import java.util.List;/*** 类描述fallbackFactory指定的服务降级类* Author wang_qz* Date 2021/10/30 21:18* Version 1.0*/
Component
Slf4j
public class DeptFeignClientFallbackFactory implements FallbackFactoryDeptFeignClientService {Overridepublic DeptFeignClientService create(Throwable throwable) {return new DeptFeignClientService() {Overridepublic boolean add(Dept dept) {log.info(添加失败, 发生了服务降级...);return false;}Overridepublic Dept get(Integer id) {Dept dept Dept.builder().deptno(id).dname(没有查询到id为 id 的dept信息, 发生了服务降级...).build();return dept;}Overridepublic ListDept findAll() {log.info(查询失败, 发生了服务降级...);return null;}};}
}3.6 补充
FeignClient还提供了属性fallback配置服务降级的逻辑处理类. 但服务降级类的实现方式稍微有所不同.
/*** 类描述Feign声明式调用的接口* fallback 或 fallbackFactory属性指定服务降级处理逻辑* Author wang_qz* Date 2021/10/27 20:44* Version 1.0*/
FeignClient(value microservicecloud-provider, fallback DeptFeignClientServiceImpl.class)
public interface DeptFeignClientService {PostMapping(value /dept/add)boolean add(Dept dept);GetMapping(value /dept/{id})Dept get(PathVariable(value id) Integer id);GetMapping(value /dept)ListDept findAll();
}fallback声明的服务降级类, 需要继承FeignClient接口类.
package com.atguigu.springcloud.service.impl;import com.atguigu.springcloud.entities.Dept;
import com.atguigu.springcloud.service.DeptFeignClientService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;import java.util.List;/*** 类描述fallback指定的服务降级类* Author wang_qz* Date 2021/10/31 11:34* Version 1.0*/
Component
Slf4j
public class DeptFeignClientServiceImpl implements DeptFeignClientService {Overridepublic boolean add(Dept dept) {log.info(添加失败, 发生了服务降级...);return false;}Overridepublic Dept get(Integer id) {Dept dept Dept.builder().deptno(id).dname(没有查询到id为 id 的dept信息, 发生了服务降级...).build();return dept;}Overridepublic ListDept findAll() {log.info(查询失败, 发生了服务降级...);return null;}
}3.7 Feign的使用
在服务调用api中使用feign接口.
/*** Feign声明式调用*/
Autowired
private DeptFeignClientService feignClientService;
/*** 使用Eureka的服务发现api调用远程服务提供方(Feign声明式调用)* Feign内置了Ribbon负载均衡, 默认轮询策略* param id* return*/
GetMapping(value /findById4/{id})
public Dept findById4(PathVariable(value id) Integer id) {Dept dept feignClientService.get(id);return dept;
}3.8 服务降级测试
场景一: 服务提供方正常. 访问不存在dept信息. 发现没有发生服务降级, 而是返回空处理. 场景二: 服务提供方正常, 在服务调用api中进行非空判断, 抛出异常, 访问不存在dept信息.
/*** 使用Eureka的服务发现api调用远程服务提供方(Feign声明式调用)* Feign内置了Ribbon负载均衡, 默认轮询策略* param id* return*/
GetMapping(value /findById4/{id})
public Dept findById4(PathVariable(value id) Integer id) {Dept dept feignClientService.get(id);// 非空判断, 抛出异常if (null dept) throw new RuntimeException(查询失败);return dept;
}结果也没有发生服务降级, 而是返回系统默认的异常信息界面. 场景三: 服务提供方正常, 访问存在的dept信息. 正常返回. 场景四: 关闭 服务提供方, 随意访问. 发生了服务降级. 也就是整体资源不够的时候, 将某些服务先关闭, 待资源ok的时候,再开启回来.
4. 服务熔断高级
上面的服务熔断只是简单的使用, 从熔断到降级处理, 再到链路恢复的弹性容错过程没有完整的体现出来. 这个过程就像家里的保险丝一样. 下面通过更多的配置项来详细介绍这个使用过程.
4.1 熔断机制概述
熔断机制是应对雪崩效应的一种微服务链路保护机制。当扇出链路的某个微服务出错不可用或者响应时间太长时会进行服务的降级进而熔断该节点微服务的调用快速返回错误的响应信息。而当检测到该节点微服务调用响应正常后恢复调用链路。
在Spring Cloud框架里熔断机制通过Hystrix实现。熔断机制的注解是HystrixCommand。Hystrix会监控微服务间调用的状况当失败的调用到一定阈值缺省是5秒内20次调用失败就会启动熔断机制。
Martin Fowler的断路器论文→
4.2 最佳实践
修改服务提供方[cloud-provider-payment-8001]
4.2.1 修改service层
service层添加服务熔断的测试方法, 当id传入负数时抛出异常, 进而触发熔断器. com.atguigu.springcloud.service.PaymentService#paymentCircuitBreaker com.atguigu.springcloud.service.impl.PaymentServiceImpl#paymentCircuitBreaker
//服务熔断// // HystrixCommandProperties
// 参数解读: 10s窗口期内, 请求次数达到阈值10,失败率达到60%, 触发断路器发生熔断, 进而服务降级处理.
HystrixCommand(fallbackMethod paymentCircuitBreaker_fallback, commandProperties {HystrixProperty(name circuitBreaker.enabled, value true), // 是否开启断路器HystrixProperty(name circuitBreaker.requestVolumeThreshold, value 10), // 请求次数(阈值)HystrixProperty(name circuitBreaker.sleepWindowInMilliseconds, value 10000), // 时间窗口期HystrixProperty(name circuitBreaker.errorThresholdPercentage, value 60), // 失败率达到多少后跳闸
})
public String paymentCircuitBreaker(Integer id) {if (id 0) {throw new RuntimeException(******id 不能负数);}String serialNumber IdUtil.simpleUUID();return Thread.currentThread().getName() \t 调用成功流水号: serialNumber;
}// 服务降级方法
public String paymentCircuitBreaker_fallback(Integer id) {return id 不能负数请稍后再试/(ㄒoㄒ)/~~ id: id;
}4.2.2 修改controller层
controller层添加服务熔断的测试入口方法. com.atguigu.springcloud.controller.PaymentController#paymentCircuitBreaker
//服务熔断
GetMapping(/circuit/{id}) // /payment/circuit/{id}
public String paymentCircuitBreaker(PathVariable(id) Integer id) {String result paymentService.paymentCircuitBreaker(id);log.info(****result: result);return result;
}4.2.3 自测服务提供方
id传入正数, http://localhost:8001/payment/circuit/1 , 返回结果正常. id传入负数, http://localhost:8001/payment/circuit/-11, 因为抛出异常触发熔断器, 进而服务降级返回友好提示. 一次负数, 一次正数的来回交叉访问, 或者使用Jmeter高压测试, 通过下面的测试结果, 发现原来传入正数的访问请求也没有正常返回了, 被服务降级处理. 待一定的时间窗口期过后, 传入正数的访问请求又恢复了正常. 这就不难看出上面的参数配置的想要达到的效果. 10s窗口期内, 请求次数达到阈值10,失败率达到60%, 触发断路器发生熔断, 进而服务降级处理. 一段时间后, 断路器尝试半开, 如果部分请求能够正常返回, 再进行全开; 否则回到断路状态.
4.3 原理分析
上面的测试过程完整展现了断路器的弹性熔断过程.
4.3.1 原理及流程分析 根据上面原理图, 进行解读. 熔断器打开 : 请求不再进行调用当前服务内部设置时钟一般为MTTR平均故障处理时间)当打开时长达到所设时钟则进入半熔断状态. 熔断器关闭 : 熔断关闭不会对服务进行熔断, 请求正常返回. 熔断器半开 : 部分请求根据规则调用当前服务如果请求成功且符合规则则认为当前服务恢复正常关闭熔断
官网的断路器流程图: 熔断器的工作过程:
4.3.2 断路器参数解读 涉及到断路器的三个重要参数快照时间窗、请求总数阀值、错误百分比阀值。 1快照时间窗断路器确定是否打开需要统计一些请求和错误数据而统计的时间范围就是快照时间窗默认为最近的10秒。
2请求总数阀值在快照时间窗内必须满足请求总数阀值才有资格熔断。默认为20意味着在10秒内如果该hystrix命令的调用次数不足20次即使所有的请求都超时或其他原因失败断路器都不会打开。
3错误百分比阀值当请求总数在快照时间窗内超过了阀值比如发生了30次调用如果在这30次调用中有15次发生了超时异常也就是超过50%的错误百分比在默认设定50%阀值情况下这时候就会将断路器打开。
4.3.3 断路器开启或者关闭的条件
1: 当满足一定的阀值的时候默认10秒内超过20个请求次数 2: 当失败率达到一定的时候默认10秒内超过50%的请求失败 3: 到达以上阀值断路器将会开启 4: 当开启的时候所有请求都不会进行转发 5: 一段时间之后默认是5秒这个时候断路器是半开状态会让其中一个请求进行转发。如果成功断路器会关闭; 若失败断路器继续开启。→重复4和5.
4.3.4 断路器打开后的处理
1再有请求调用的时候将不会调用主逻辑而是直接调用降级 fallback。通过断路器实现了自动地发现错误并将降级逻辑切换为主逻辑减少响应延迟的效果。
2原来的主逻辑要如何恢复呢 对于这一问题hystrix也为我们实现了自动恢复功能。 当断路器打开对主逻辑进行熔断之后hystrix会启动一个休眠时间窗在这个时间窗内降级逻辑是临时的成为主逻辑当休眠 时间窗到期断路器将进入半开状态释放一次请求到原来的主逻辑上如果此次请求正常返回那么断路器将继续闭合 主逻辑恢复如果这次请求依然有问题断路器继续进入打开状态休眠时间窗重新计时。
4.4 HystrixCommand注解完整参数
在com.netflix.hystrix.HystrixCommandProperties类中提供了完整的参数项, 可以在commandProperties属性中配置, 或读取默认值.
//All
HystrixCommand(fallbackMethod str_fallbackMethod,groupKey strGroupCommand,commandKey strCommand,threadPoolKey strThreadPool,commandProperties {// 设置隔离策略THREAD 表示线程池 SEMAPHORE信号池隔离HystrixProperty(name execution.isolation.strategy, value THREAD),// 当隔离策略选择信号池隔离的时候用来设置信号池的大小最大并发数HystrixProperty(name execution.isolation.semaphore.maxConcurrentRequests, value 10),// 配置命令执行的超时时间HystrixProperty(name execution.isolation.thread.timeoutinMilliseconds, value 10),// 是否启用超时时间HystrixProperty(name execution.timeout.enabled, value true),// 执行超时的时候是否中断HystrixProperty(name execution.isolation.thread.interruptOnTimeout, value true),// 执行被取消的时候是否中断HystrixProperty(name execution.isolation.thread.interruptOnCancel, value true),// 允许回调方法执行的最大并发数HystrixProperty(name fallback.isolation.semaphore.maxConcurrentRequests, value 10),// 服务降级是否启用是否执行回调函数HystrixProperty(name fallback.enabled, value true),// 是否启用断路器HystrixProperty(name circuitBreaker.enabled, value true),// 该属性用来设置在滚动时间窗中断路器熔断的最小请求数。例如默认该值为 20 的时候// 如果滚动时间窗默认10秒内仅收到了19个请求 即使这19个请求都失败了断路器也不会打开。HystrixProperty(name circuitBreaker.requestVolumeThreshold, value 20),// 该属性用来设置在滚动时间窗中表示在滚动时间窗中在请求数量超过// circuitBreaker.requestVolumeThreshold 的情况下如果错误请求数的百分比超过50,// 就把断路器设置为 打开 状态否则就设置为 关闭 状态。HystrixProperty(name circuitBreaker.errorThresholdPercentage, value 50),// 该属性用来设置当断路器打开之后的休眠时间窗。 休眠时间窗结束之后// 会将断路器置为 半开 状态尝试熔断的请求命令如果依然失败就将断路器继续设置为 打开 状态// 如果成功就设置为 关闭 状态。HystrixProperty(name circuitBreaker.sleepWindowinMilliseconds, value 5000),// 断路器强制打开HystrixProperty(name circuitBreaker.forceOpen, value false),// 断路器强制关闭HystrixProperty(name circuitBreaker.forceClosed, value false),// 滚动时间窗设置该时间用于断路器判断健康度时需要收集信息的持续时间HystrixProperty(name metrics.rollingStats.timeinMilliseconds, value 10000),// 该属性用来设置滚动时间窗统计指标信息时划分桶的数量断路器在收集指标信息的时候会根据// 设置的时间窗长度拆分成多个 桶 来累计各度量值每个桶记录了一段时间内的采集指标。// 比如 10 秒内拆分成 10 个桶收集这样所以 timeinMilliseconds 必须能被 numBuckets 整除。否则会抛异常HystrixProperty(name metrics.rollingStats.numBuckets, value 10),// 该属性用来设置对命令执行的延迟是否使用百分位数来跟踪和计算。如果设置为 false, 那么所有的概要统计都将返回 -1。HystrixProperty(name metrics.rollingPercentile.enabled, value false),// 该属性用来设置百分位统计的滚动窗口的持续时间单位为毫秒。HystrixProperty(name metrics.rollingPercentile.timeInMilliseconds, value 60000),// 该属性用来设置百分位统计滚动窗口中使用 “ 桶 ”的数量。HystrixProperty(name metrics.rollingPercentile.numBuckets, value 60000),// 该属性用来设置在执行过程中每个 “桶” 中保留的最大执行次数。如果在滚动时间窗内发生超过该设定值的执行次数// 就从最初的位置开始重写。例如将该值设置为100, 滚动窗口为10秒若在10秒内一个 “桶 ”中发生了500次执行// 那么该 “桶” 中只保留 最后的100次执行的统计。另外增加该值的大小将会增加内存量的消耗并增加排序百分位数所需的计算时间。HystrixProperty(name metrics.rollingPercentile.bucketSize, value 100),// 该属性用来设置采集影响断路器状态的健康快照请求的成功、 错误百分比的间隔等待时间。HystrixProperty(name metrics.healthSnapshot.intervalinMilliseconds, value 500),// 是否开启请求缓存HystrixProperty(name requestCache.enabled, value true),// HystrixCommand的执行和事件是否打印日志到 HystrixRequestLog 中HystrixProperty(name requestLog.enabled, value true),},threadPoolProperties {// 该参数用来设置执行命令线程池的核心线程数该值也就是命令执行的最大并发量HystrixProperty(name coreSize, value 10),// 该参数用来设置线程池的最大队列大小。当设置为 -1 时线程池将使用 SynchronousQueue 实现的队列// 否则将使用 LinkedBlockingQueue 实现的队列。HystrixProperty(name maxQueueSize, value -1),// 该参数用来为队列设置拒绝阈值。 通过该参数 即使队列没有达到最大值也能拒绝请求。// 该参数主要是对 LinkedBlockingQueue 队列的补充,因为 LinkedBlockingQueue// 队列不能动态修改它的对象大小而通过该属性就可以调整拒绝请求的队列大小了。HystrixProperty(name queueSizeRejectionThreshold, value 5),}
)
public String strConsumer() {return hello 2020;
}
public String str_fallbackMethod()
{return *****fall back str_fallbackMethod;
}4.5 Hystrix工作流程
Hystrix的GitHub开源, How-it-Works→ 下面是官方资料, 看得懂的就看看吧.
4.5.1 官方图例 4.5.2 步骤说明
序号说明1创建 HystrixCommand用在依赖的服务返回单个操作结果的时候 或 HystrixObserableCommand用在依赖的服务返回多个操作结果的时候 对象。2命令执行。其中 HystrixComand 实现了下面前两种执行方式而 HystrixObservableCommand 实现了后两种执行方式execute()同步执行从依赖的服务返回一个单一的结果对象 或是在发生错误的时候抛出异常。queue()异步执行 直接返回 一个Future对象 其中包含了服务执行结束时要返回的单一结果对象。observe()返回 Observable 对象它代表了操作的多个结果它是一个 Hot Obserable不论 “事件源” 是否有 “订阅者”都会在创建后对事件进行发布所以对于 Hot Observable 的每一个 “订阅者” 都有可能是从 “事件源” 的中途开始的并可能只是看到了整个操作的局部过程。toObservable() 同样会返回 Observable 对象也代表了操作的多个结果但它返回的是一个Cold Observable没有 “订阅者” 的时候并不会发布事件而是进行等待直到有 “订阅者” 之后才发布事件所以对于 Cold Observable 的订阅者它可以保证从一开始看到整个操作的全部过程。3若当前命令的请求缓存功能是被启用的 并且该命令缓存命中 那么缓存的结果会立即以 Observable 对象的形式 返回。4检查断路器是否为打开状态。如果断路器是打开的那么Hystrix不会执行命令而是转接到 fallback 处理逻辑第 8 步如果断路器是关闭的检查是否有可用资源来执行命令第 5 步。5线程池/请求队列/信号量是否占满。如果命令依赖服务的专有线程池和请求队列或者信号量不使用线程池的时候已经被占满 那么 Hystrix 也不会执行命令 而是转接到 fallback 处理逻辑第8步。6Hystrix 会根据我们编写的方法来决定采取什么样的方式去请求依赖服务。HystrixCommand.run() 返回一个单一的结果或者抛出异常。HystrixObservableCommand.construct() 返回一个Observable 对象来发射多个结果或通过 onError 发送错误通知。7Hystrix会将 “成功”、“失败”、“拒绝”、“超时” 等信息报告给断路器 而断路器会维护一组计数器来统计这些数据。断路器会使用这些统计数据来决定是否要将断路器打开来对某个依赖服务的请求进行 “熔断/短路”。8当命令执行失败的时候 Hystrix 会进入 fallback 尝试回退处理 我们通常也称该操作为 “服务降级”。而能够引起服务降级处理的情况有下面几种第4步 当前命令处于熔断/短路状态断路器是打开的时候。第5步 当前命令的线程池、 请求队列或 者信号量被占满的时候。第6步HystrixObservableCommand.construct() 或 HystrixCommand.run() 抛出异常的时候。9当Hystrix命令执行成功之后 它会将处理结果直接返回或是以Observable 的形式返回。 tips如果我们没有为命令实现降级逻辑或者在降级处理逻辑中抛出了异常 Hystrix 依然会返回一个 Observable 对象 但是它 不会发射任何结果数据 而是通过 onError 方法通知命令立即中断请求并通过onError()方法将引起命令失败的异常发送给调用 者。 5. 服务实时监控(Hystrix Dashboard)
5.1 简介
除了隔离依赖服务的调用以外Hystrix还提供了准实时的调用监控Hystrix DashboardHystrix会持续地记录所有通过Hystrix发起的请求的执行信息并以统计报表和图形的形式展示给用户包括每秒执行多少请求多少成功多少失败等。Netflix 通过hystrix-metrics-event-stream项目实现了对以上指标的监控。Spring Cloud也提供了Hystrix Dashboard的整合对监控内容转化成可视化界面。
5.2 创建监控仪表盘
新增微服务模块[cloud-hystrix-dashboard-9001]
5.2.1 依赖
?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdparentartifactIdatguigu-cloud-2020/artifactIdgroupIdcom.atguigu.springcloud/groupIdversion1.0-SNAPSHOT/version/parentmodelVersion4.0.0/modelVersionartifactIdcloud-hystrix-dashboard-9001/artifactIddependenciesdependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-netflix-hystrix-dashboard/artifactId/dependency!--监控依赖配置--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-actuator/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-devtools/artifactIdscoperuntime/scopeoptionaltrue/optional/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdoptionaltrue/optional/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependency/dependencies
/project5.2.2 编写配置
server:port: 9001
spring:application:name: cloud-hystrix-dashboard5.2.3 编写启动类
启动类上添加注解EnableHystrixDashboard开启hystrix-dashboard功能.
package com.atguigu.springcloud;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;/*** 类描述hystrix监控面板启动类* Author wang_qz* Date 2021/11/15 6:22* Version 1.0*/
SpringBootApplication
EnableHystrixDashboard
public class HystrixDashboardApplication {public static void main(String[] args) {SpringApplication.run(HystrixDashboardApplication.class);}
}5.2.4 dashboard控制面板
启动9001应用, 访问 http://localhost:9001/hystrix进入控制面板. 在监控栏位输入要监控的应用地址http://localhost:8002/hystrix.stream , 进入监控界面发现报错. Unable to connect to Command Metric Stream. 这是springcloud升级后的坑, 下面给出解决方案.
5.3 监控服务提供方
在服务提供方8001微服务的启动类或配置类中添加监控路径.
/***此配置是为了服务监控而配置与服务容错本身无关springcloud升级后的坑*ServletRegistrationBean因为springboot的默认路径不是/hystrix.stream*只要在自己的项目里配置上下面的servlet就可以了*/
Bean
public ServletRegistrationBean getServlet() {HystrixMetricsStreamServlet streamServlet new HystrixMetricsStreamServlet();ServletRegistrationBean registrationBean new ServletRegistrationBean(streamServlet);registrationBean.setLoadOnStartup(1);registrationBean.addUrlMappings(/hystrix.stream);registrationBean.setName(HystrixMetricsStreamServlet);return registrationBean;
}检查端点暴露可以被监控的依赖配置, 必须要有.
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-actuator/artifactId
/dependency再次在hystrix-dashboard监控面板输入8001的监控地址. http://localhost:8001/hystrix.stream 访问几次正常和失败的请求, 刷新监控面板. http://localhost:8001/payment/circuit/1 http://localhost:8001/payment/circuit/-11, 失败次数上去后, 断路器打开了.
5.4 监控服务消费方
与上面服务提供方8001一样的配置步骤. 访问正常的请求. http://localhost/consumer/payment/hystrix/ok/1 访问多次失败的请求. http://localhost/consumer/payment/hystrix/timeout/1, 断路器也一样被打开了.
5.5 监控窗口指标解读
从上面的监控面板中可以看到很多监控的曲线和圈圈, 它们分别都有各自的监控指标含义. 简单总结为: 7色1圈1线.
7色
7种不同的颜色表示了不同健康程度的请求状态.
1圈
实心圆共有两种含义。它通过颜色的变化代表了实例的健康程度它的健康度从绿色黄色橙色红色递减。 该实心圆除了颜色的变化之外它的大小也会根据实例的请求流量发生变化流量越大该实心圆就越大。 所以通过该实心圆的展示就可以在大量的实例中快速的发现故障实例和高压力实例。
1线
曲线用来记录2分钟内流量的相对变化可以通过它来观察到流量的上升和下降趋势。
整体说明 看懂一个简单的监控曲线图, 才能看懂下面这种复杂的监控曲线图.
6. 总结
注意, 我们需要弄清楚服务熔断和服务降级的区别. 服务熔断 一般是服务端的某个服务故障或者异常引起, 类似现实生活中的保险丝, 当某个异常条件被触发, 直接熔断整个服务(拉闸限电), 而不是一直等到此服务响应超时. 然后调用服务降级的方法返回友好提示. 且是弹性熔断, 支持恢复. (服务的降级-进而熔断- 恢复调用链路) 服务降级 所谓服务降级, 一般是从整体负荷考虑, , 就是当某个服务端熔断或关闭之后, 服务器将不再被调用. 此时客户端可以自己准备一 个本地的fallback回调, 返回一个缺省值. (不让客户端等待并立刻返回一个友好提示) 这样做, 虽然服务水平下降了, 但是不会造成雪崩效应, 拉跨整个调用链, 比直接瘫痪好很多. 服务降级场景: 程序运行异常 超时 服务熔断触发服务降级 线程池/信号量打满也会导致服务降级 服务限流 秒杀高并发等操作严禁一窝蜂的过来拥挤大家排队一秒钟N个有序进行. ( JMeter高压测试 ). tomcat的默认的工作线程数被打满 了没有多余的线程来分解压力和处理。此时需要限流控制. 个人博客
欢迎访问个人博客: https://www.crystalblog.xyz/
备用地址: https://wang-qz.gitee.io/crystal-blog/