首先,介绍下问题:

一个plat-gateway工程,配置了Hystrix。按照通用的配置,如下验证:

@RestController
public class SelfHystrixController {
    @RequestMapping("/defaultfallback")
    public Map<String,String> defaultfallback(){
    	log.info(LogMessage.getMessage("", "请求被熔断了"));
        Map<String,String> 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等。

不急,时间会说明一切。(未完,待续)

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐