记一次Unexpected end of file from server异常排查经历

问题描述

公司的某个服务A通过统一的正向代理访问外部的第三方接口,数据流(服务A -> 正向代理 -> 外部第三方服务),生产环境会间歇性的出现unexpected end of file from server异常。

排查步骤一

初步怀疑是代码写法问题,于是将如下写法

1Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("<PROXY.HOST>", 80)));
2HttpsURLConnection con = (HttpsURLConnection) url.openConnection(proxy);

改为基于restTemplate

1@Bean
2public RestTemplate restTemplate() {
3    SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
4
5    Proxy proxy = new Proxy(Type.HTTP, new InetSocketAddress("<PROXY.HOST>", 80));
6    requestFactory.setProxy(proxy);
7
8    return new RestTemplate(requestFactory);
9}

但是实际上,resttemplate底层同样是基于HttpsURLConnection,所以问题并没有解决。

排查步骤二

此异常一般说明,服务端关闭了连接,从而客户端获取response时会抛出此异常。我们认为异常可能是外部第三方关闭了连接或者代理关闭了连接,因此我们期望在代理上抓包排查异常原因,但是生产环境不好操作。作罢!

排查步骤三

正路不通,我们联系第三方,第三方反馈没有我方发生异常时的请求记录;我们找到代理上的其他服务B,咨询是否有类似的异常抛出,其他服务B反馈没有遇到过。 我们一脸问号???

综合上述信息,我们基本排除了(服务A -> 正向代理 -> 外部第三方服务)三个节点中出问题的可能性(不能说100%排除,只能说概率90%以上)。那么只能从http协议本身入手了,我们知道http协议有长短连接的区别,长连接在生命周期结束的场景下会被服务端自动关闭。

我们的请求默认情况下就是长连接。那么有没有可能是加入代理节点后,这个关闭动作因为“延迟”,被客户端感知到了呢 ?

验证非常好验证,只需要指定非长连接后,观察异常是否还出现即可:

即将http 请求 header Connection: Keep-Alive 改为 Connection: Close

上线后,异常不再出现...

收工!~~~