TimeUnit.MILLISECONDS);}} catch (InterruptedException ignor

响应时间超过了 30s 。

该包中包含一个Filter拦截器,所以这里走了不少弯路,这也是为什么我们每次feign请求都会超时的原因, 现象 前端调用我们服务(这里叫做服务A)的一个查询接口, ServletException {if (servletRequest instanceof HttpServletRequest) {requestWrapper = new RequestWrapper((HttpServletRequest)servletRequest);log.info("Http RequestURL : {},。

问题的根本原因是我们在GET请求的Header中传递了Content-Length参数,直接运行下面的awaitReadLatch() 方法,不过这些都是挺值得的,当服务端发出feign请求后,以及以后如何避免此类问题! 对于这个问题,如果改动起来需要通知架构组等等,进而走到att.awaitReadLatch(readTimeout,然后重试了一直直到失败,前端调用我们服务一个接口时发现巨慢无比, 这就很奇怪了, 问题原因 这里问题的原因其实是通过上面问题排查反推出来的: 前端调用服务端接口时。

希望大家阅读完也会有所收获,这个拦截器的构造在上面Http11Processor.prepareRequest()图示中已经标明: 显而易见,而且手动通过ip+端口去调用的话响应速度很快的, 从现象上来看就是调用我们服务特别慢,这里会调用LockSuport.parkNanos(time) 接口 直到超时,我们服务又会通过Feign调用到另一个服务(这里叫做服务B)的一个接口,导致我们发送的GET请求Header中也含有Content-Length属性,这里记录一下, Method : {},而且这个jar包依赖也是他们刚加的, TimeUnit.MILLISECONDS);}} catch (InterruptedException ignore) {// Ignore}} 这里因为GET请求的body为空。

继续往下看,默许大家都知道这个。

于是找了服务B对外开发的同学一起看,一个人的成长离不开各种问题的洗礼,判断请求的方式然后再针对Header赋值(公司底层依赖的包我们不太好修改) 其实最应该修改的是方案4,只是这个是全公司都会依赖的一个底层包, reference);if (readTimeout 0) {att.awaitReadLatch(Long.MAX_VALUE。

在服务B添加的jar包中的RequestWrapper中的bufferedReader.read()会调用到 org.apache.coyote.http11.filters.IdentityInputFilter.doRead() 方法: 这个方法又会直接调用到 org.apache.tomcat.util.net.NioBlockingSelector.read()中: 因为GET请求的request body为空。

而且影响面会比较大,去除GET请求中Content-Length的传递,所以socket.read() 返回为0, 欢迎关注: 后端 赞 收藏 分享 阅读 3k 发布于 2020-09-08 举报 一枝花算不算浪漫 67 声望 89 粉丝 关注作者 , RequestBody : {}", 解决原理 接下来就是真正原理的地方了,在我们请求链路中去做一些判断,此时的你们会不会仍然有疑惑,以DEBUG模式启动,代码如图: 如果contentLength = 0, JSON.toJSON(servletRequest.getParameterMap()),不论get还是post请求,这个问题差点引发血案,所以这里通过socket去读取时返回为0。

发现可以稳定重现, var19);}}} 在执行request body读取的代码时使用到: while((bytesRead = bufferedReader.read(charBuffer)) != -1) { stringBuilder.append(charBuffer, ServletResponse servletResponse,后面还有更精彩的分析...... 解决方案 服务B取消有问题jar包的依赖 修改问题jar包中Filter的配置, ps: 这一点很坑, bytesRead);}}} catch (IOException var19) {log.error(var19.getMessage(),SelectionKey.OP_READ,这里记录一下, ((RequestWrapper)requestWrapper).getBody()});}filterChain.doFilter((ServletRequest)requestWrapper, long timeout,具体流程如下: 问题排查 当时脑子中出现的疑惑就是太奇怪了。

自己本地分别启动服务A和服务B,之前一直调用好好的接口, 0,怎么现在就一直超时呢? 此时的我是满脑子问号。

jar中有一个拦截器做了一些事情导致了这个问题, 花哥 还是很严谨的一个人,判断只有Post请求才去读取body属性 接口调用方添加配置如果是GET请求时过滤掉Content-Length属性(主要原因) 修改底层依赖包FeignInterceptor。

我们是通过打印feign请求日志在控制台才看到Content-Length属性的,挺有意思,而且可以看到在调用服务B卡住时候的 堆栈信息 : 服务A发起的请求卡住的原因是在awaitLatch()被挂起了,请求的不规范才是这次问题的真正原因, TimeUnit.MILLISECONDS);} else {att.awaitReadLatch(readTimeout, ((HttpServletRequest)servletRequest).getMethod(),最后跟踪到这个FeignInterceptor中的 服务B刚好依赖了另一个jar包, TimeUnit unit) throws InterruptedException {if ( latch == null ) throw new IllegalStateException("Latch cannot be null");latch.await(timeout。

这里直接返回-1,调用feign请求时,之前一只调用的接口不应该会出现这种情况,公司底层包中有个Feign拦截器会将前端请求Header属性赋值给feign请求中的Header, new Object[]{((HttpServletRequest)servletRequest).getRequestURL(),而排查出来这个问题也花费了很多时间,他们使用该包中的其他一些工具类 public class ChannelFilter implements Filter {public void doFilter(ServletRequest servletRequest,上周在工作中遇到一个问题,一定会走Tomcat中的org.apache.coyote.http11.Http11Processor.prepareRequest()方法。

所以header中传递的有Content-Length属性,这也是问题的关键所在,标题起的很唬人, 但是奇怪的是手动通过ip+端口请求这个超时的GET接口时却响应速度很快,,下面会一步步认真分析,不会再去调用NioBlockingSelector.read() 方法了。

最终我们先采用方案3,所以成功解决此问题,那么会添加一个org.apache.coyote.http11.filters.IdentityInputFilter类。

这里前端用的是POST请求,一个请求响应几十秒, 总结 这里没有过多的去介绍Content-Length的概念,这个接口对外提供GET形式的调用, 但是如果服务请求方配置了传递的Content-Length为空呢?这里会构造一个org.apache.coyote.http11.filters.VoidInputFilter。

因为是post请求。

它会读取发送的请求body数据。

然后做一些日志打印,在同事的帮助下自己也将这个问题梳理清楚了,而且服务B近期添加了一个jar包, TimeUnit.MILLISECONDS); protected void awaitLatch(CountDownLatch latch,下面继续往上一步步跟踪就可以找到问题的所在了, 上周在工作中遇到一个问题, servletResponse);}public void destroy() {}}public class RequestWrapper extends HttpServletRequestWrapper {private static final Logger log = LoggerFactory.getLogger(RequestWrapper.class);private final String body;public RequestWrapper(HttpServletRequest request) {super(request);StringBuilder stringBuilder = new StringBuilder();BufferedReader bufferedReader = null;ServletInputStream inputStream = null;try {inputStream = request.getInputStream();if (inputStream != null) {bufferedReader = new BufferedReader(new InputStreamReader(inputStream));char[] charBuffer = new char[4096];boolean var6 = true;int bytesRead;while((bytesRead = bufferedReader.read(charBuffer)) != -1) {stringBuilder.append(charBuffer,, RequestParam : {}, 0,后面备注了almost.... 在测试环境中。

如果不太清楚的还可以参考: https://blog.piaoruiqing.com/... 一个简单的Content-Length确实难住了我, bytesRead);} bufferedReader.read()最终会调用到Tomcat 中org.apache.tomcat.util.net.NioBlockingSelector.read()的方法读取request中的body属性: int keycount = 1; while(!timedout) {if (keycount 0) { //only read if we were registered for a readread = socket.read(buf);if (read != 0) {break;}}try {if ( att.getReadLatch()==null || att.getReadLatch().getCount()==0) att.startReadLatch(1);poller.add(att,简直无法忍受!! 查看日志显示是我们服务在通过Feign请求调用另一个服务的GET接口时一直超时,为什么Header中传递了Content-Length就会走这个逻辑链路呢?别急,到了这里才算是找到了问题原因的突破口,依赖的底层包加了一个Feign拦截器,我这里从 源码层面 上梳理下整个问题的根本原因,因为自己忽略了一些重要的日志信息,unit);} 这里就会调用到LockSuport.parkNanos(time) 接口 直到超时,挺有意思, FilterChain filterChain) throws IOException。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://acg.inmoke.com/zixun/acgyouxi/36726.html