文档章节

关于feign client触发熔断的异常

go4it
 go4it
发布于 2017/02/11 23:47
字数 692
阅读 597
收藏 1

##序 使用feign client进行restful服务间的调用,除了要注意超时时间、retry的设置外,还有一个关于自定义异常的部分,需要注意一下,不然容易出错。

##nginx对于upstream的health check Nginx 默认判断失败节点状态以connect refuse和time out状态为准,不以HTTP错误状态进行判断失败,因为HTTP只要能返回状态说明该节点还可以正常连接,所以nginx判断其还是存活状态;除非添加了proxy_next_upstream指令设置对404、502、503、504、500和time out等错误进行转到备机处理。

##feign及hystrix对于服务提供方的health check ###HystrixBadRequestException 这个异常主要是用来适配IllegalArgumentException这类异常。HystrixBadRequestException与其他HystrixCommand抛出的异常不同,该异常不会纳入circuit breaker的统计里头,即不会触发熔断。 ###feign client对restful调用的异常处理 /Users/xixicat/.m2/repository/io/github/openfeign/feign-core/9.3.1/feign-core-9.3.1-sources.jar!/feign/SynchronousMethodHandler.java

Object executeAndDecode(RequestTemplate template) throws Throwable {
    Request request = targetRequest(template);

    if (logLevel != Logger.Level.NONE) {
      logger.logRequest(metadata.configKey(), logLevel, request);
    }

    Response response;
    long start = System.nanoTime();
    try {
      response = client.execute(request, options);
      // ensure the request is set. TODO: remove in Feign 10
      response.toBuilder().request(request).build();
    } catch (IOException e) {
      if (logLevel != Logger.Level.NONE) {
        logger.logIOException(metadata.configKey(), logLevel, e, elapsedTime(start));
      }
      throw errorExecuting(request, e);
    }
    long elapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);

    boolean shouldClose = true;
    try {
      if (logLevel != Logger.Level.NONE) {
        response =
            logger.logAndRebufferResponse(metadata.configKey(), logLevel, response, elapsedTime);
        // ensure the request is set. TODO: remove in Feign 10
        response.toBuilder().request(request).build();
      }
      if (Response.class == metadata.returnType()) {
        if (response.body() == null) {
          return response;
        }
        if (response.body().length() == null ||
                response.body().length() > MAX_RESPONSE_BUFFER_SIZE) {
          shouldClose = false;
          return response;
        }
        // Ensure the response body is disconnected
        byte[] bodyData = Util.toByteArray(response.body().asInputStream());
        return response.toBuilder().body(bodyData).build();
      }
      if (response.status() >= 200 && response.status() < 300) {
        if (void.class == metadata.returnType()) {
          return null;
        } else {
          return decode(response);
        }
      } else if (decode404 && response.status() == 404) {
        return decoder.decode(response, metadata.returnType());
      } else {
        throw errorDecoder.decode(metadata.configKey(), response);
      }
    } catch (IOException e) {
      if (logLevel != Logger.Level.NONE) {
        logger.logIOException(metadata.configKey(), logLevel, e, elapsedTime);
      }
      throw errorReading(request, response, e);
    } finally {
      if (shouldClose) {
        ensureClosed(response.body());
      }
    }
  }

其中对status code的处理见这段

      if (response.status() >= 200 && response.status() < 300) {
        if (void.class == metadata.returnType()) {
          return null;
        } else {
          return decode(response);
        }
      } else if (decode404 && response.status() == 404) {
        return decoder.decode(response, metadata.returnType());
      } else {
        throw errorDecoder.decode(metadata.configKey(), response);
      }

也就是feign client的处理跟nginx的是不一样的,feign client把非200的以及404(可以配置是否纳入异常)都算成error,都转给errorDecoder去处理了。

##小结 要特别注意,对于restful抛出的4xx的错误,也许大部分是业务异常,并不是服务提供方的异常,因此在进行feign client调用的时候,需要进行errorDecoder去处理,适配为HystrixBadRequestException,好避开circuit breaker的统计,否则就容易误判,传几个错误的参数,立马就熔断整个服务了,后果不堪设想。

  • 附errorDecoder实例
@Configuration
public class BizExceptionFeignErrorDecoder implements feign.codec.ErrorDecoder{

    private static final Logger logger = LoggerFactory.getLogger(BizExceptionFeignErrorDecoder.class);

    @Override
    public Exception decode(String methodKey, Response response) {
        if(response.status() >= 400 && response.status() <= 499){
            return new HystrixBadRequestException("xxxxxx");
        }
        return feign.FeignException.errorStatus(methodKey, response);
    }
}

##doc

© 著作权归作者所有

共有 人打赏支持
go4it
粉丝 53
博文 705
码字总数 506188
作品 0
深圳
hehui/ SpringCloudTutorial

SpringCloud 教程 一、简介 二、各微服务占用端口列表 章 微服务模块名称 端口 功能描述 001 springms-simple-provider-user 8000 简单用户微服务 002 springms-simple-consumer-movie 8005 ...

hehui
05/02
0
0
SpringCloud学习6-如何创建一个服务消费者consumer

上一节如何创建一个服务提供者provider已经启动了一个provider的server,提供用户信息查询接口。接下来,我们启动另一个provider,由于是同一台机器本地测试,我们换一个端口 通过启动传参数...

ryan-miao
07/05
0
0
Hystrix介绍以及服务的降级限流熔断

介绍 首先在这里给粉丝道个歉,由于这一段时间比较忙,没有更新大数据,因为项目上用到了Spring cloud,所以在以后的日子里,会将Spring cloud纳入更新的范畴,好了,言归正传。 据我了解,现...

ROCK_杰哥
07/07
0
0
Spring Cloud中如何优雅的使用Feign调用接口

JAVA 项目中接口调用怎么做 ? Httpclient Okhttp Httpurlconnection RestTemplate 上面是最常见的几种用法,我们今天要介绍的用法比上面的更简单,方便,它就是 Feign Feign是一个声明式的R...

尹吉欢
2017/11/23
0
0
Spring Cloud学习:03断路器(Hystrix)

1 Hystrix介绍 Spring Cloud Hystrix是分布式系统处理超时和错误的机制,如下图所示,分布式系统中某个用户请求依赖A、H、I、P服务。 当此请求并发超过50的时候,服务I处理速度变慢,但是服务...

寒武没有纪
2017/10/22
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

获取多个集合列表的笛卡尔积

获取多个集合笛卡尔积 电商中典型业务场景:商品搜索 单属性属性值之间为并查询 不同属性的属性值之间查询为与查询 import java.util.ArrayList;import java.util.List;/** * Created w...

键走偏锋
10分钟前
0
0
echarts 迁移地图 控制鼠标缩放大小比例

在网上找了好久没有找到解决方式,还是重新看了一下文档,终于找到的解决方案, zoom:1, //默认显示级别 scaleLimit:{min:1,max:3}, // 缩放级别 echarts 文档-配置项链接 http://echarts.b...

心驰
13分钟前
0
0
Boot2Docker ISO is out-of-date,

Boot2Docker ISO is out-of-date, downloading the latest release. 使用docker-machine时无法更新Boot2Docker ISO导致创建vm machine失败 解决方法:关闭网络,创建好之后再开启...

writeademo
22分钟前
0
0
在 Tomcat 中设置 Tapestry 框架的 html 热加载

如果开发中使用到了 Tapestry 这个框架,如果事先没有设置过的话,开发的时候 html 是不会热加载的,也就是说修改了 html 文件,不能刷新浏览器后立马看到修改完的效果,必须先重新启动应用服...

LeoXu
43分钟前
0
0
【微服务】开启巨石应用到微服务的探索

背景 在过去的一年时间里,我一直在从事一件事情,将现有的单体应用(巨石应用)向微服务改造。 接下来,将持续整理一些在微服务路上的学习与成长。 为什么要做微服务 单体应用,开发、部署简...

艳沐石
54分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部