“ 微服务熔断,是当微服务中某个子服务,发生异常不可用,其他服务在进行远程调用时不能正常访问而一直占用资源,导致正常的服务也发生资源不能释放而崩溃,这时为了不造成整个微服务群瘫痪,进行的保护机制”
01 关于微服务熔断,意想不到的实验结果
我们基于 SpringCloud,搭了一个简单的微服务场景,应用 A 调 B,在 A 的测试接口上设置了 Hystrix 熔断器,熔断超时时间是 1s,如下图:
你是否知道:
-
这个熔断超时时间指的是 A 接口的执行时间,还是仅 A 调用 B 的调用时间?
-
A、B 执行逻辑计算的时间都设置了 500ms,熔断超时时间是 1s,熔断器未开启时,A 是否能拿到 B 的返回结果?
-
A 接口超时、抛 Exception 这两种场景都能触发它的降级熔断,底层触发逻辑有什么不一样?看似同步的请求竟然是通过异步线程来实现的?
-
当 A 触发熔断器开启后,它是否还能成功调用到 B 接口?难道就这样让用户一直失败
实验结果究竟如何,我们一起往下看。(心急的小伙伴可以直接滑到文末,查看答案~)
02 可视化熔断实验的 demo 介绍
本次实验,基于 SpringCloud,Eureka 作为注册中心,单机部署,采用 OpenFeign 实现 RPC 调用,Hystrix 实现熔断机制,下面是应用 A(即 consumer)的测试接口代码:
我们借助 Kindling 程序摄像头,它能够查看分析一次请求调用下的所有线程的工作情况记录的能力,来看下实验结果。
03 实验 1: 当 A 未接入断路器,A 调用 B 的线程分析
当 A 未接入断路器,请求是通过执行线程 exec 来执行,请求开始,打了 A 开始 Sleep 的日志,A sleep 500ms 之后,又打了开始调用 B(即 producter)的日志,最后拿到 B 的执行结果,请求结束。(关于 kindling 摄像头程序操作手册:http://www.kindling.space:33215/project-3/doc-94/)
04 实验 2: 当 A 接入断路器,A 调用 B 的线程分析
当 A 接入断路器后,执行线程 exec 上没有打执行日志了,反而是多了一个 hystrix-ConsumerController 线程,打了 A 开始 sleep 的日志。
接着又由这个线程 sleep500ms,再调用 B,但是我们在这个线程上找不到 net B 的请求事件,我们可以看到,是由另外一个线程 hystrix-producter 来和 B 建立网络连接。
但是我们点击这个线程,查看它从 B 读到的执行结果,它能拿到正常的返回结果:
但是,我们发现最后 A 返回给用户的报文却是:
其实这就是 A 接口上的熔断超时时间在起作用,如下图,Asleep 了 500ms,B 也执行了 500ms,再加上系统调用等时间开销,A 接口的执行时间肯定会超过我们设置的熔断超时时间是 1s,所以,Hystrix 上的 Timer 线程,监测到时间超时,进入了降级服务。
05 实验 3: 当 A 接入断路器,B 直接返回 Exception,线程分析
这个实验,我们让 B 不再执行 500ms,而是直接返回 Exception,也就是说,A 不会再因为超时而进入降级服务。同样的,它也是由多个 Hystrix 线程执行业务,但是和上一个实验中,Timer 线程监测到超时而触发降级的情况不同,这里是由 hystrix-consumerController 直接触发降级。
虽然最后这两个实验都是进入了降级服务,但是通过 Kindling 程序摄像头我们就能清楚的看到,它是怎么被触发降级的。
06 Hystrix 配置讲解
再回到配置这里,刚才实验中提到的熔断超时时间就是通过上图中,红框里的配置实验的,另外,第 1 条配置是 Hystrix 的开关。第 2、3、4 条配置是一起的,我这里配置的意思是:当 10s 内,接口的请求次数达到 10 次,且失败率在 60%以上,就会触发熔断。
07 实验 4: 当 A 接入断路器,且触发熔断后,请求调用情况
当 A 熔断器开启,所有请求直接返回降级结果,如下图:
但是等过了熔断时间窗口期,我们发现,Hystrix 有让一少部分请求正常执行:
这就是熔断器的自我恢复机制,熔断器一共有三种状态,断开后,过了时间窗口期,它就会允许一部分请求进行尝试,如果成功次数达到阈值,熔断器就会关闭,服务恢复。
最后总结一下开篇疑问:
-
熔断超时时间指的是接口的执行时间
-
接口超时是有 HystrixTimer 线程定时监测到时间超时,触发的降级,而接口异常是通过 Hystrix 执行线程触发降级
-
熔断器触发之后,过了窗口时间,熔断器会允许少部分请求正常执行,尝试自我恢复
-
Hystrix 的底层用的也是线程池,一个线程执行业务,一个线程做网络调用,还有个线程做超时检测