首先,介绍下问题:
一个plat-gateway工程,配置了Hystrix。按照通用的配置,如下验证:
@RestController
public class SelfHystrixController {
@RequestMapping("/defaultfallback")
public Map defaultfallback(){
log.info(LogMessage.getMessage("", "请求被熔断了"));
Map map = new HashMap<>();
map.put("msg","网络繁忙服务降级请稍后再访问");
map.put("code","GW0001");
return map;
}
/**
* 发起Get 请求 :localhost:8000/gateway/timeout
* 会进行熔断
* @return
*/
@RequestMapping("/timeout")
public String timeout(){
try {
Thread.sleep(15000);
} catch (Exception e) {
e.printStackTrace();
}
return "Hello, I am timeout return. If normal, you can not find me.";
}
}
Yml配置如下:
cloud:
# Gateway routes config
gateway:
default-filters:
- name: Hystrix
args:
name: fallbackcmd
fallbackUri: forward:/defaultfallback
routes:
# 走 fsp 的路由
- id: wish.plat-gateway.fsp
uri: http://127.0.0.1:80
order: 2
#网关断言匹配
predicates:
- Path=/gateway/**
filters:
# - StripPrefix=4
- FspAdapt
如上,在controller中验证是没有问题的。但是发现,在 FspAdaptGatewayFilterFactory 的过滤器中,是无法熔断。
配置 10s熔断, 在过滤器中休眠 15s,执行post请求。期望是:到10s后,主动熔断,返回前端信息。but,现实情况是,到达10秒后,继续执行,执行完后,才返回前端。此时信息是:
{
"timestamp": "2019-10-31T00:54:57.352+0000",
"path": "/gateway/04320/07/B70001/arrange/newBusiness/1233333",
"status": 504,
"error": "Gateway Timeout",
"message": "Response took longer than configured timeout"
}
本人想过很多方案,第一:修改spring-cloud-gateway-core中的TimeoutException,为RuntimeException,这样就可以终止继续执行了。第二:自定义一个 HystrixGatewayFilterFactory 来实现该功能。但是思来想去,spring cloud hystrix不应该这样。因为根本未达到熔断的目的,猜想是对使用不够深入了解。
在这样一篇文章中,Spring Cloud Hystrix设计原理。请认真阅览,发现如下是跟我相关的描述:
如果run() 或者construct()方法 的真实执行时间超过了Command设置的超时时间阈值, 则当前则执行线程(或者是独立的定时器线程)将会抛出TimeoutException。抛出超时异常TimeoutException,后,将执行步骤8的Fallback降级处理。即使run()或者construct()执行没有被取消或中断,最终能够处理返回结果,但在降级处理逻辑中,将会抛弃run()或construct()方法的返回结果,而返回Fallback降级处理结果。
需要注意的是,Hystrix无法强制 将正在运行的线程停止掉--Hystrix能够做的最好的方式就是在JVM中抛出一个InterruptedException。如果Hystrix包装的工作不抛出中断异常InterruptedException, 则在Hystrix线程池中的线程将会继续执行,尽管调用的客户端已经接收到了TimeoutException。这种方式会使Hystrix 的线程池处于饱和状态。大部分的Java Http Client 开源库并不会解析 InterruptedException。所以确认HTTP client 相关的连接和读/写相关的超时时间设置。
3.1 断路器相关配置:
circuitBreaker.forceOpen 是否强制将断路器设置成开启状态 false
心想,这不就是说的我这种情况吗?于是觉得可以查阅http的超时或者circuitBreaker.forceOpen来试一下。
美好的事情,总会发生。增加如下配置,生效了:
#熔断相关配置
hystrix:
command:
default:
circuitBreaker:
# 强制将断路器设置成开启状态
forceOpen: true
此刻,整个世界都好了。等等,本以为到此结束,万万没想到。
接下来,配置 timeoutInMilliseconds: 10000 ,去掉过滤器中的休眠,打算正常测试下。结果:熔断,熔断,熔断。是的,连正常功能都不好使了,吓得我赶紧去掉了这个参数。仔细一想,这个参数是,强制熔断。so,不能随便乱用。
http请求的超时,未找到相关设置。
结论:可能与设计原理,不是很一致,因此通过配置可能无法实现。暂时搁置/自定义过滤器实现/考虑下其他方案,如Sentinel等。
不急,时间会说明一切。(未完,待续)