0.学习目标
1.学会配置Hystrix熔断
2.学会使用Feign进行远程调用
3.能独立搭建Zuul网关
4.能编写Zuul的拦截器
1.Hystrix
1.1 简介
Hystrix,即熔断器,(英文翻译为豪猪,全身带刺就是起保护作用)。
主页:https://github.com/Netflix/Hystrix/
Hystrix是Netflix开源的一个延迟和容错库,用于隔离访问远程服务、第三方库,防止出现级联失败。
1.2 雪崩问题
微服务中,服务之间的调用关系错综复杂,一个请求可能需要调用多个微服务接口才能实现,形成复杂的调用链路
如图,一个业务请求,需要调用A、H、I、P四个服务,而这四个服务又可能调用其他服务
如果此时有一个服务出现异常(例如I服务)
I发生异常,则会导致请求阻塞,用户得不到响应,则tomcat这个线程不会释放,于是用户就继续发请求(因为没响应),越来越多请求来(因为I服务还是异常,后面来的请求也无法处理继续跟着阻塞),那么越来越多线程阻塞,那么tomcat里的可用连接都被占满了(连接数满了,无法接收其他请求)
服务器支持的线程和并发数有限,请求一直阻塞,会导致资源耗尽,从而不再接收其他请求,也就使得其他服务也不可用,形成雪崩效应,服务器崩溃
Hystrix解决雪崩问题的两种手段
1.线程隔离
2.服务熔断
1.3 线程隔离
1.3.1 原理
线程隔离
解读:
从图中看到,服务A-T里面都有有一定的线程数。
实际上Hystrix为每个依赖服务调用分配了一个小的线程池(数量较少的线程数),如果线程池满了(线程隔离:用线程池把各个服务的资源隔离开,就算一个服务异常了,耗尽的也是该服务的线程资源,不会影响其他服务),或者请求超时了,调用就会立即被拒绝,而不是阻塞等待响应了,这也叫做服务降级(优先保证核心服务,而非核心服务不可用或者弱可用 )。通常拒绝后,会返回给浏览器一个友好的提示信息。
服务降级:优先保证核心服务,而非核心服务不可用或者弱可用
触发Hystrix服务降级的原因:
1.线程池已满
2.请求超时
作用:用户出现故障的时候,不会无休止的等待或看到系统奔溃,而是看到一个执行结果(友好的提示)
1.3.2 线程隔离、服务降级案例
是通过改进consumer,使其有线程隔离和服务降级功能,实现它去调用其他服务时,如果对方服务异常导致线程阻塞或者请求超时,自己就马上返回一个友好的提示结果
1.在consumer的配置文件中引入Hystrix依赖
2.在consumer的配置文件加注解
这有两个注解一个是@EnableHystrix肯定是可以的,但后面会将熔断,所以直接用了熔断的注解@CircuitBreaker也是可以的,等会会解释
3.配置文件的配置
一般可以配置的属性有服务等待超时时长(当然会有默认)
4.注意事项:注解
在一般标准的Eureka客户端的服务中,(配置类里)我们之前加起来配置的注解有@EnableCircuitBreaker(熔断的),@EnableDiscoveryClient(负载均衡),@SpringBootApplication(SpringBoot)所以Spring也给这些注解进行了整合
5.编写Controller层
首先要先把服务降级打开(通过 @HystrixCommand注解,里面配置了降级处理的方法名,方法名可以随意),编写降级处理方法
其中需要注意:
1.返回类型需要和原事务方法返回类型一致
这里降级处理返回类型是String类型(提示一句话),而原来事务方法返回类型是User类型,那么既然原方法返回时为了展示数据,也就是也要把User转换成String,不如在接收到服务端返回回来的json类型数据拆分时就转成String,直接返回,这样就可以保证两个方法的返回类型一样。
2.参数列表也要一致
6.模拟服务端(被调用的user-service)超时(设置线程休眠2s)
7.运行程序(实际在1s时就被视为降级处理)
8.注意事项
1.在controller层中,我们为原事务方法(controller方法)设置了服务降级方法,但如果我们有很多事务方法岂不是也要配置很多降级方法,事实上降级方法是可以通用的,我们只要在类上配置一个默认的降级方法的注释@DefautProperties(参数也是方法名),然后再对应的事务方法上开启@HystrixCommand服务降级即可
其中降级方法要想要通用就不能说和某个方法的参数一致了,因为可能每个事务方法的参数都不同,所以就要用空参
2.除了通用降级方法外,还有一个就是每个服务用时不同,那么理应服务超时也不同,有些耗时长的服务,服务超时也要设置长一点
那么如何来设置呢,这个技能和之前学的一样,就是先通过相关配置注解里面一般可以找到他们对应的默认属性(默认的服务超时时长,然后再改掉)
比如我们既然是不同方法的不同服务超时,那么相关的注释就是这个@HystrixCommand,我们看看它里面的参数列表Ctrl+Alt+B
像之前配置的fallbackMethod也是这里可以大概猜出来就是服务降级,而我们这次的修改服务超时时长是一个属性,那么大概就是这个commandProperties(通用属性)了,而它是个数组,说明可以配置多个属性,我们用@HystrixProperty来拿到超时属性,可是我们不知道key和value是什么,我们就去找原jar包
找到对应jar包,点进去发现里面定义了很多默认的属性,由于我们之前运行发现1s就超时了,而且通过变量名大概就能推断出default_executeTimeoutInMilliseconds就是服务超时属性,那么这个是value,我们还要找到它的key
我们可以通过Ctrl+F搜索到属性名,找到对应的key值
回去就可以修改了
然后运行一下发现由于我们休眠了两秒所以延时到两秒,也是超时了,当我们延时设置长一点就会发现可以运行了
运行了2.03s,实际上休眠2s,运行只需要0.03s,所以延时2s无法运行,而3s就可以了
如果要配置全局延时就没有源码提示了,但也能大概猜一点
红框里的是之前的key,把 . 都换成了 :
前面的hystrix:command:default因为是hystrix的属性,打hyestrix可以弹出提示
也可以在配置文件这里指定哪个方法 / 服务的超时属性
1.4 服务熔断
1.4.1 熔断原理
熔断器,也称断路器
类似空气开关,负载过高会跳闸起保护作用,所以熔断器就是保护服务,如果请求延迟过高,超时后就直接返回失败提示,但实际上超时等待的3s也远比成功运行的3ms长的久,这样就会降低很大的效率,所以我们统计这个服务超时次数,如果发现是多次超时(比如占比总次数50%),那么就说明这个服务本身就不好,所以选择关闭它,即熔断,这样连3s都不用等直接返回错误提示,那么赚来的3s可以提供给其他服务(不能丢了西瓜换芝麻,类似跳闸后也要找到对应导致跳闸的电器并关闭它)。但熔断有个特性是会恢复(不想跳闸后不会自动恢复)
Hystrix熔断状态机模型
熔断器有三种状态
closed:关闭状态(断路器关闭),所有请求都正常访问。
open:打开状态(断路器打开),所有请求都会被降级。hystrix会对请求情况计数,当一定时间内失败请求百分比达到阈值,则触发熔断,断路器会完全关闭。默认失败比例的阈值是50%,请求次数最少不低于20次。
half open:半开状态,closed状态不是永久的,关闭后会进行休眠时间(默认是5s),随后断路器会自动进入半开状态。此时会释放部分请求通过,若这些请求都是健康的,则会完全打开断路器,否则继续保持关闭,再次进入休眠计时。
服务熔断测试
通过抛出异常来参数熔断
因为不好设置超时时间,比如临界是2s,如果大于2s则全成功,小于2s全失败,那么根本无法达到控制有些成功有些失败,所以我们用异常来模拟,手动让线程发生异常触发熔断,然后再不发生,看熔断器状态转换
修改熔断阈值
当服务运行时间超过这个阈值就算失败,次数百分比达到一定时默认50%,就熔断,进入打开状态
其中这个参数就和我们上面找的那个服务超时属性一样,要进入源码找key
主要就是三个参数
1熔断请求次数(服务失败次数至少达到20次,就可以熔断了)
2休眠时间(5s以后就算失败)
3失败百分比(次数达到50%就可熔断)
再通过这个参数名通过Ctrl+F,搜索出它的key即可
设置熔断器阈值数量、休眠时间、失败百分比
首先访问id=1 ,没有问题
访问多次2,触发熔断机制
再访问1,说明该服务方法被触发了熔断(那么这个服务就暂时不能被访问,腾出休眠的那几秒给其他服务使用,可提高整个项目的效率)
过一会访问id=1就又没问题了,恢复了关闭状态