<>概述
<>分布式问题
分布式系统:将项目不同的服务单独部署到不同的服务器中,服务加在一起构成完整的项目。
分布式系统面临的问题:复杂分布式体系结构中的应用程序有数十个依赖关系,每个依赖关系在某些时候将不可避免地失败。
服务雪崩:多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C又调用其它的微服务,这就是所谓的“扇出”。如果扇出的链路上某个微服务的调用响应时间过长或者不可用,对微服务A的调用就会占用越来越多的系统资源,进而引起系统崩溃,所谓的“雪崩效应”。
对于高流量的应用来说,单一的后端依赖可能会导致所有服务器上的所有资源都在几秒钟内饱和。比失败更糟糕的是,这些应用程序还可能导致服务之间的延迟增加,备份队列,线程和其他系统资源紧张,导致整个系统发生更多的级联故障。这些都表示需要对故障和延迟进行隔离和管理,以便单个依赖关系的失败,不能取消整个应用程序或系统。
Hystrix
Hystrix是一个供分布式系统使用,提供延迟和容错功能,保证复杂的分布系统在面临不可避免的失败是时,仍具有弹性。
当服务器A调用服务器B时,如果服务器B宕机,则服务器A不去调用。当服务器B在时间范围内未响应,服务器A延迟时间等待服务器B的响应。
<>Hystrix的作用
* 服务降级
* 服务熔断
* 服务限流
* 接近实时的监控
如果微服务中一台服务器宕机,导致大量访问得不到结果,或者如果某个接口出现异常,则需要处理,比如熔断、限流、降级。例如秒杀抢购会出现从正常访问降为无法访问
<>服务降级
<>概述
因为整体负荷超出整体负载承受能力,为了保证重要或基本服务正常运行,延迟使用或暂停使用非重要服务。
服务降级是从整个系统的负荷情况出发和考虑的,对某些负荷会比较高的情况,为了预防某些功能(业务场景)出现负荷过载或者响应慢的情况,在其内部暂时舍弃对一些非核心的接口和数据的请求,而直接返回一个提前准备好的fallback(退路)错误处理信息。这样,虽然提供的是一个有损的服务,但却保证了整个系统的稳定性和可用性。
<>使用Hystrix实现降级
在项目中创建一个Spring Initializr的module
添加依赖
在application.properties文件中配置Naocs的应用名称和地址
spring.application.name=logicwithhystrix spring.cloud.nacos.server-addr=
localhost:8848
项目中有两个module,目录分别如下:
AuthController代码:
@RestController @RequestMapping("/auth") public class AuthController {
@RequestMapping(value = "auth.do",method = RequestMethod.POST) public String
test(@RequestBody String args){ int i = 1/0; return "hello"; }
AuthClient代码:
@FeignClient("authconfigtest")//Client 要去访问的地址接口对应的项目的Nacos应用名称 public
interface AuthClient { @RequestMapping(value = "/auth/auth.do",method =
RequestMethod.POST) public String feignAuth(); }
TestController代码:
@RestController @RequestMapping("test") public class TestController {
@Autowired AuthClient client; @RequestMapping("/test.do") public String test(){
return client.feignAuth(); }
TestController中导入Client会报错,需要在当前项目的启动类上添加注解@EnableFeignClients
在浏览器访问/test/test.do会报错/ by zero
解决方案:使用hystrix的fallback机制降级
在配置文件中添加配置,开启熔断机制
feign.hystrix.enabled=true
1
创建熔断器的实现类
@Component//作用是实现bean的注入,为该类创建对象 public class AuthClientFallBack implements
AuthClient { @Override public String feignAuth() { return "当前接口出现问题,请稍后访问"; }
修改调用接口的代码
@RestController @RequestMapping("test") public class TestController {
@Autowired @Qualifier("authclient")//指定自动注入的id名称 AuthClient client;
@RequestMapping("/test.do") public String test(){ return client.feignAuth(); }
修改AuthClient接口的注解
@FeignClient(qualifier = "authclient",value = "authconfigtest",fallback =
AuthClientFallBack.class) public interface AuthClient { @RequestMapping(value =
"/auth/auth.do",method = RequestMethod.POST) public String feignAuth(); }
AuthClient的feignAuth()调用RequestMapping对应接口,当返回错误时,会使用fallback去调用AuthClientFallBack类中重写的feignAuth()方法,实现服务降级。
<>服务熔断
<>概述
服务熔断的作用类似于我们家用的保险丝,当某服务出现不可用或响应超时的情况时,为了防止整个系统出现雪崩,暂时停止对该服务的调用。
熔断机制是应对雪崩效应的一种微服务链路保护机制。
当扇出链路的某个微服务不可用或者响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回"错误"的响应信息。当检测到该节点微服务调用响应正常后恢复调用链路。在SpringCloud框架里熔断机制通过Hystrix实现。Hystrix会监控微服务间调用的状况,当失败的调用到一定阈值,缺省是5秒内20次调用失败就会启动熔断机制。熔断机制的注解是@HystrixCommand。
<>服务熔断的状态
熔断有三种状态:
1.Closed:关闭状态,所有请求都正常访问。
2.Open:打开状态,所有请求都会被降级。Hystix会对请求情况计数,当一定时间内失败请求百分比达到阈值,则触发熔断,断路器会完全打开。默认失败比例的阈值是50%,请求次数最少不低于20次。
3.Half
Open:半开状态,open状态不是永久的,打开后会进入休眠时间(默认是5S)。随后断路器会自动进入半开状态。此时会释放部分请求通过,若这些请求都是健康的,则会完全关闭断路器,否则继续保持打开,再次进行休眠计时
<>服务熔断的原理
统计用户在指定的时间范围之内的请求总数达到指定的数量之后,如果不健康的请求(超时、异常)占总请求数量的百分比达到了指定的阈值之后,就会触发熔断。触发熔断,断路器就会打开(open),此时所有请求都不能通过。在指定时间之后,断路器会恢复到半开状态(half
open),会允许少量请求通过,如果这些请求都是健康的,那么断路器会回到关闭状态(close).如果这些请求还是失败的请求,断路器还是恢复到打开的状态(open).
1
在指定时间窗口内,达到出异常的请求数,触发熔断。
HystrixCommand配置
@HystrixCommand(fallbackMethod =
“paymentCircuitBreaker_fallback”,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的时候,如果滚动时间窗(默认10s)内仅收到了19个请求,即使这19个请求都失败了,断路器也不会打开。 @HystrixProperty(
name= "circuitBreaker.requestVolumeThreshold",value = "20"), //
该属性用来设置在滚动时间窗中,表示在滚动时间窗中,在请求数量超过circuitBreaker.RequestVolumeThreshold的情况下, //
如果错误请求数的百分比超过50,就把断路器设置为“打开”状态,否则就设置为“关闭”状态。 @HystrixProperty(name =
"circuitBreaker.sleepWindowInMilliseconds",value = "10000"),//时间窗口期 // 断路器强制打开
@HystrixProperty(name = "circuitBreaker.forceOpen",value = "false"), // 断路器强制关闭
@HystrixProperty(name = "circuitBreaker.forceClosed",value = "false"), //
滚动时间窗设置,该时间用于断路器判断健康度时需要收集信息的持续时间 @HystrixProperty(name =
"metrics.rollingStats.timeInMilliseconds",value = "10000"), //
该属性用来设置滚动时间窗统计指标信息时划分“桶”的数量, //
断路器在收集指标信息的时候会根据设置的时间窗长度拆分成多个“桶”来累计个度量值,每个“桶”记录了一段时间内的采集指标。 //
比如10s内拆分成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,滚动窗口为10s,若在10s内一个“桶”中发生了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"), @HystrixProperty(name =
"circuitBreaker.errorThresholdPercentage",value = "60"),//失败率达到多少后跳闸 },
threadPoolProperties= { // 该参数用来设置执行命令线程池的核心线程数,该值也就是命令执行的最大并发量 @HystrixProperty
(name = "coreSize",value = "10"), //
该参数用来设置线程池的最大队列大小。当设置为-1时,线程池将使用SynchronousQueue实现的队列, //
否则将使用LinkedBlockingQueue实现的队列 @HystrixProperty(name = "maxQueueSize",value =
"-1"), // 该参数用来为队列设置拒绝阈值。通过该参数,即使队列没有达到最大值也能拒绝请求。 //
该参数主要是对LinkedBlockingQueue队列的补充, //
因为LinkedBlockingQueue队列不能动态修改它的对象大小,而通过该属性就可以调整拒绝请求的队列大小了。 @HystrixProperty(name
= "queueSizeRejectionThreshold",value = "5"), })
commandProperties:HystrixCommand的执行策略
HystrixProperty:设置隔离策略。针对当前方法设置线程池,当该线程熔断时,会熔断整个线程池
性能好的时候可以适当放大点
真正部署的时候,参数的具体大小可以由测试人员测出来。
值的具体大小应参考项目业务被访问的频率或者是电脑配置
出异常是bug,应去解决
使用Hystrix实现熔断
在启动类上添加注解@EnableCircuitBreaker开启熔断器
在controller层添加熔断方法,并添加注解
一旦调用服务方法失败并抛出了错误信息后,会自动调用@HystrixCommand标注好的fallbackMethod调用类中的指定方法
服务监控hystrixDashboard
概述
除了隔离依赖服务的调用以外,Hystrix还提供了准实时的调用监控(Hystrix
Dashboard),Hystrix会持续地记录所有通过Hystrix发起的请求的执行信息,并以统计报表和图形的形式展示给用户,包括每秒执行多少请求多少成功,多少失败等。Netflix通过hystrix-metrics-event-stream项目实现了对以上指标的监控。Spring
Cloud也提供了Hystrix Dashboard的整合,对监控内容转化成可视化界面。
<>使用演示
在项目中创建一个Spring Initializr的module
添加依赖
在pom文件中,手动添加依赖
com.alibaba.cloud spring-cloud-starter-alibaba-nacos-discovery
在启动类上添加注解
@EnableDiscoveryClient:可以获取服务信息,用于向注册中心提供注册服务
@EnableHystrixDashboard:开启当前应用为仪表盘应用
启动项目
熔断和降级的区别
共同点
为了系统的稳定性,防止因为个别微服务的不可用而拖死整个系统服务
提高用户的可用性,保证用户在访问过程中一定能得到有效结果
粒度上,都是服务级别的粒度,某些情况下,也有更细的粒度,如数据的持久层,只允许查询,不允许增删改。
不同点
管理目标层次不一样,服务熔断是一个框架层次的处理,服务降级是业务层次的处理
实现方式不一样,服务熔断一般是自我熔断恢复,服务降级相当于人工控制
触发原因不同 服务熔断一般是某个服务(下游服务)故障引起,而服务降级一般是从整体负荷考虑,主动降级;
一句话:
服务熔断是应对系统服务雪崩的一种保险措施,给出的一种特殊降级措施。而服务降级则是对系统整体资源的合理分配以应对压力。