9.1 服务容错和Hystrix
1.雪崩效应:在微服务架构中,通常会有多个服务层调用,如果某个服务不可用,导致几连故障,造成整个系统不可用的情况。
如上所示:服务A调用服务B,服务B调用服务C。当服务C发生故障时候,服务B调用不通服务C,则B发生故障,由于服务A也调用服务B,服务A调用不通服务B时候,会采取多次重连,同步等待会造成资源耗尽,则服务A也故障。最后都不可用。2.SpringCloud家族中防雪崩的利器就是:SpringCloud Hystrix,它是基于Netflix的开源框架(Hystrix的中文意思是豪猪:defend you app);Hystrix目的就是给微服务提供一系列服务容错保护机制;还记得Eureka的意思吗?Eureka就是找到了,也就是服务注册中心
3.Spring Cloud Hystrix具有如下功能:
a.服务降级 b.依赖隔离 c.服务熔断 d.监控(Hystrix Dashboard)
9.1.1 服务降级
比如双十一时候,刷新网站时候会出现”哎呦喂,被挤爆了”,还有秒杀的时候,某些app提示网络开小差,请稍后再试,诸如此类问题,服务降级知道思想是要区分业务,具体是:
- 1.优先核心服务,非核心服务不可用或弱可用。
(比如在订单,商品微服务中:买家查询是核心服务,卖家查询是弱可用服务,我们需要优先保证买家查询服务) - 2.在应用层面,使用服务降级很简单,通过HystrixCommand注解制定。在fallbackMethod(回退函数)中具体实现降级逻辑。
9.2 触发降级
在order服务中有一个create接口调用商品服务代码块
我们将其拎出来
我们单独在order服务的controller包中创建一个:HystrixController类,然后在里面使用restTemplate
然后通过浏览器请求:
我们此时关掉product服务,然后再次请求:发现连接被拒绝:
9.2.1服务降级应用搭建
我们这个时候使用Hystrix用作服务降级,然后就是老套路了
- 1.引入依赖:(order-server的pom.xml文件中)
|
|
然后刷新一下:maven
- 2.在启动类中加入注解:@EnableCircuitBreaker
此时我们发现在启动类上:OrderApplication有很多注解,这个时候,我们再看一个注解:@SpringCloudApplication
|
|
其实SpringCloudApplication可以替换上面 3个注解
- 3.在请求的HystrixController类的方法中加入注解:
浏览器测试输入:
当被调用的server端不能正常提供服务时候,我们换一个思路,被请求的服务不是client端调用server端的代码,而是抛出一个异常:
以上情况说明:降级不一定用在这种场景:被调用的server端不能正常提供服务了,触发降级,我们也可以用在我们自己服务内部来触发降级(比如:自己服务内部抛出异常,内部服务并发数太高,或者数据库连接数太多时候,我们抛出一个异常)
9.2 超时设置
以上就调用了一个fallback方法,那么如果我们有很多业务逻辑都需要处理的话,是不是都需要降级呢?这样写会不会很麻烦,其实SpringCloud提供了一个在类型注解默认的fallback方法:
|
|
联系之前我们的介绍,比如我们上面getProductInfoList方法是我们核心业务的方法,比如就是买家查询商品时候,我们需要优先保证其正常使用,使用注解,自定义特殊的降级处理逻辑fallback,但是此时fallback中50%的概率是可以正常处理的,其他方法是非核心业务,统一的降级策略就是直接回到了一个静态页面之类。更多的场景其实要注意服务的时间,也就是超时的问题。比如我们在product服务中根据商品id查询商品时候,我们让其睡眠2秒。
我们在浏览器访问order服务获取商品接口:
其实我们可以在HystrixCommand里面设置超时时间。
我们进入源码发现其配置的默认超时时间是1秒
点击注解:@HystrixProperty 再点击:package com.netflix.hystrix.contrib.javanica.annotation;然后我们看到左边的源码:HystrixCommandProperties属性配置
默认1秒,所以控制台请求响应一般为1秒左右,那我们该如何配置呢?在类中搜索一下:default_executionTimeoutInMilliseconds
然后我们设置getProductInfoList个超时时间为4秒
然后我们在浏览器请求:
超时时间配置很重要,具体超时时间设置需要看调用方和具体业务,比如有些场景请求到第三方:开发、充值等需要将超时时间设置为长一些。
9.4 依赖隔离
1.线程池隔离(依赖隔离)
SpringCloud Hystrix的依赖隔离类似于docker的”舱壁模式”;docker通过”舱壁模式”实现进程隔离,使得容器之间互不影响,而Hystrix使用该模式实现:“线程池隔离”;会为每一个HystrixCommand创建一个独立线程池,这样就算某个在Hystrix包装下的依赖服务出现延迟过高情况,也只是对该依赖服务的调用产生影响,并不会拖慢其他服务,使用HystrixCommand来将某个函数包装成了Hystrix命令时候,Hystrix框架自动地为这个函数实现了依赖隔离。所以依赖隔离,服务降级在使用时候都是一体化实现的,这样就可以实现服务容错保护。在编程模型上就会非常方便。2.服务熔断:除了依赖隔离,服务降级之外,Hystrix还有另一一个重要元素:服务熔断。
9.4.1 服务熔断
- 1.服务熔断还是使用@HystrixCommand注解:
我们如何配置了,我们还是打开HystrixCommandProperties类:
我们将上面注解拷贝出来,使用在Order服务的getProductInfoList上
然后我们在浏览器测试:http://localhost:8082/getProductInfoList
发现其一直返回”默认提示:太拥挤了,请稍后再试~~~”
此时发现一直返回错误,我们该如何进行测试呢?我们加一个请求参数,如果number为偶数直接返回success,否则调用product服务;注意此时调用product服务肯定会进入服务降级回调,原因是因为上面execution.isolation.thread.timeoutInMilliseconds已经注释掉了并且product服务里面线程等待为2秒,并且execution.isolation.thread.timeoutInMilliseconds默认等待时间是1秒。
- 2.产生熔断:我们不停地访问:http://localhost:8082/getProductInfoList?number=1让其错误率达到60%
- 3.服务熔断:
circuitBreaker.requestVolumeThreshold
circuitBreaker.sleepWindowInMilliseconds
circuitBreaker.errorThresholdPercentage
这是我们上面用到的3个配置,3个配置前面都有一个共同的词:circuitBreaker
a.circuitBreaker:断路器(当某个服务发生故障,类似用电器发生短路,通过断路器的故障监控,就类似于熔断的保险丝,直接切断原来的主逻辑调用)
b.微服务和分布式里面容错必须是要考虑的,通常做法有两种:
1)重试机制:对于预期的短暂的故障问题,可以重试解决的
2)断路器模式:对于更长时间的故障问题,不断重试也是没有意义的,这个时候就可以使用断路器模式。
断路器模式是将受保护的服务封装在一个可监控的断路器对象里面,当故障到达一定的值,断路器将会跳闸,断路器对象返回错误。如下所示:
上图描述了断路器模式的3中状态积:
1)close:熔断器的关闭状态,调用失败次数累计到一定阈值/比例时候,就会启动熔断机制。
2)open:熔断器的打开状态,对服务直接返回错误,但是有一个时钟,到达这个时钟之后,会进入半熔断状态,也就是half open,允许定量的服务请求,如果调用成功到一定比例就认为恢复了,就会关闭熔断器。否则,认为还没有好,又回到熔断器打开状态。
3):half open:
- 4.参数含义:
circuitBreaker.sleepWindowInMilliseconds:这里面的Window很多地方会翻译成时间窗口,断路器确定是否需要断开统计一些请求和错误数据的时候,是有一个时间范围的,这个时间范围就被称为时间窗口;当断路器打开对主逻辑进行熔断之后,Hystrix会启动一个休眠时间窗,在这个时间窗内降级逻辑临时成为主逻辑,当休眠时间窗到期,断路器将进为半开状态,释放一些请求到原来的主逻辑上,如果此次请求正常返回,那么断路器将继续闭合,主逻辑恢复,如果此次请求依然有问题,断路器将继续进入打开状态,休眠时间窗重新计时。我们上面将此参数设置为10000ms。
circuitBreaker.requestVolumeThreshold :设置在滚动窗中,断路器的最小请求数
circuitBreaker.errorThresholdPercentage:设置断路器打开的错误百分比条件,上面设置的是60,表示在滚动时间窗口中,如果发生了10次调用,有7次异常超过60%,此时断路器设置为打开状态,否则设置为关闭状态。
9.5 使用配置项
我们先注释掉所有配置:
之前的关于断路器的配置都是在代码里面配置的,如下图所示,不利于后期的维护
我们能把上面的配置写到配置文件中去吗?我们先写到本地文件中的yml格式
现在要改成用配置文件的方式进行,我们针对超时时间来做一个配置,
Hystrix全局超时时间配置如下图所示,表示3秒
有时候我们发现我们配置不起作用,服务器不触发降级,原因是我们没有在方法上添加@HystrixCommand注解
加上之后就可以了。上面是配置的全局的default配置,如果我们想给某一个类单独配置:在方法上注解:@HystrixComman然后配置属性里面的comandKey,然后再配置文件中加上。
9.6 feign-hystrix的使用
feign如何搭配hystrix,我们先看一下feign依赖了哪些组件?
再按:Ctrl+F
说明feign已经依赖了hystrix,所以使用按照如下方式:
- 1.order服务添加依赖
- 2.product服务在client端改造:@FeignClient注解属性里面添加fallback
a.在fallback填写ProductClientFallback.class类。
b.书写内部静态类并且实现ProductClient接口。
c.内部静态类需要添加@Component注解。
d.将此包打出去:在Terminal中输入:mvn install
此时我们进入order服务里面OrderServiceImpl里面的productClient,然后点击进去:发现就有了。
启动order服务,我们发现报错了:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name ‘orderServiceImpl’: Unsatisfied dependency expressed through field ‘productClient’; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘com.yxm.product.client.ProductClient’: FactoryBean threw exception on object creation; nested exception is java.lang.IllegalStateException: No fallback instance of type class com.yxm.product.client.ProductClient$ProductClientFallback found for feign client product
以上说明orderServiceImpl里面引入的com.yxm.product.client.ProductClient$ProductClientFallbac没有实例化。
原因:以上order服务引入productClient时候,已经把其当做order服务代码的一部分引入,productClient已经是order服务里面的一块代码了,所以运行的时候是在order服务中运行的,为什么不起作用了,原因是我们的启动类中没有扫描到。
明显和com.yxm.product.client.ProductClient不一样了,所以我们需要把扫描扩大:
然后启动正常。
使用post下单(此时我们的product服务没有启动)
以上说明我们已经达到了我们的要求。
9.7 hystrix-dashboard使用
hystrix-dashboard是进行可视化的一个组件,使用老套路
- 1.引入依赖
|
|
```
但是其实我们这里不需要再次引入了:
有时候我们会遇到@EnableHystrixDashboard注解始终加不上问题,我们统一下SpringBoot和SpringCloud版本。
SpringBoot:2.1.8.RELEASE
SpringCloud:Greenwich.SR3
- 2.启动类加注解
- 3.浏览器访问:
http://localhost:8082/hystrix
a.最上面输入框:填写应用地址
b.填写应用的3种方式,我们这里是Single Hystrix App所以使用:https://hystrix-app:port/actuator/hystrix.stream
Cluster via Turbine (default cluster): https://turbine-hostname:port/turbine.stream
Cluster via Turbine (custom cluster): https://turbine-hostname:port/turbine.stream?cluster=[clusterName]
Single Hystrix App: https://hystrix-app:port/actuator/hystrix.stream
我们点击Monitor Stream进去后进入:
Unable to connect to Command Metric Stream.
查看控制台发现:java.lang.IllegalArgumentException: Invalid character found in method name. HTTP method names must be tokens
参考:
https://blog.csdn.net/HonsonNgai/article/details/89300789
如果一直loading,我无意中的测试,发现这个Loading…是一直在等待负载均衡的提供方要去消费服务,即访问负载均衡服务器,去调用客户端,如果有数据响应则监控界面就会有图形数据展示:
如果想让图中的数据发生变化,则需要循环多次的去访问负载均衡的提供方,让其消费服务,以至于达到监控的目的。
http://localhost:8082/getProductInfoList?number=1
a.上面颜色小圈对应的就是:Success | Short-Circuited | Bad Request | Timeout | Rejected | Failure | Error
b.Circuit Closed表明已经是熔断了
c.中间有一个圆;圆越大说明流量就越大;圆颜色偏向于红色,表示服务越不健康。线条表示流量的相对变化。
d.最上面百分比是错误率;下面两个百分比是请求的频率。
在HystrixController中打开之前设置的参数,然后请求:
有时候,我们如果把熔断百分比设置比较大的话,我们一次次请求是很耗费时间的,其实postman提供了一个多次发送的功能: