简体   繁体   English

连接重置-Java(底层套接字状态保持建立状态)Azure VM

[英]Connection reset - Java (underlying socket status remain established) Azure VM

I am debugging one problem of connection reset and need some help. 我正在调试连接重置的一个问题,需要一些帮助。

Here is the background 这是背景

Using java version 8, apache httpClient 4.5.2 使用Java版本8,Apache httpClient 4.5.2

I have a following program, which runs successfully on windows 10, 7 but end up with connection reset on Azure windows server 2016 VM. 我有一个以下程序,该程序可在Windows 10、7上成功运行,但最终在Azure Windows Server 2016 VM上重置连接。

import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;





public class TestConnectionReset
{
  static PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();
  static  {
    connManager.setMaxTotal(10);
    connManager.setDefaultMaxPerRoute(2);
  }
  public static void main(String[] args) throws ClientProtocolException, IOException, InterruptedException {
    while (true) {
      HttpClientBuilder clientBuilder = HttpClientBuilder.create();
      RequestConfig config = RequestConfig.custom().setConnectTimeout(1800000).setConnectionRequestTimeout(1800000)
        .setSocketTimeout(1800000).build();
      clientBuilder.setDefaultRequestConfig(config);
      clientBuilder.setConnectionManager(connManager);
      String userName = "xxxxx";
      String password = "xxxxx";
      String userNamePasswordPair = String.valueOf(userName) + ":" + password;

      String authenticationData = "Basic " + new String((new Base64()).encode(userNamePasswordPair.getBytes()));

      HttpPost post = new HttpPost("https://url/rest/oauth/token");
      Map<String, String> requestBodyMap = new HashMap<String, String>();
      requestBodyMap.put("grant_type", "client_credentials");

      String req = getFormUrlEncodedBodyFromMap(requestBodyMap);

      StringEntity stringEntity = new StringEntity(req);
      post.setEntity(stringEntity);
      post.setHeader("Authorization", authenticationData);
      post.setHeader("Content-Type", "application/x-www-form-urlencoded");

      CloseableHttpClient closeableHttpClient = clientBuilder.build();
      HttpResponse response = closeableHttpClient.execute(post);
      Header[] hs = response.getAllHeaders();
      for (Header header : hs) {
        System.out.println(header.toString());
    }
      System.out.println(EntityUtils.toString(response.getEntity()));
      Thread.sleep(10*60*1000L);
    } 
  }


  public static String getFormUrlEncodedBodyFromMap(Map<String, String> formData) {
    StringBuilder requestBody = new StringBuilder();
    Iterator<Map.Entry<String, String>> itrFormData = formData.entrySet().iterator();
    while (itrFormData.hasNext()) {
      Map.Entry<?, ?> entry = (Map.Entry)itrFormData.next();
      requestBody.append(entry.getKey()).append("=").append(entry.getValue());
      if (itrFormData.hasNext()) {
        requestBody.append("&");
      }
    } 
    return requestBody.toString();
  }
}

I am using pooling httpclient connection manager. 我正在使用池httpclient连接管理器。 1st request in 1st time loop execution succeeded but subsequent iteration of for loop with next request fails. 第一个时间循环执行中的第一个请求成功,但随后的下一个请求for循环的后续迭代失败。

My findings 我的发现

If we see underlying socket connection on windows 10, after 1st request socket goes into CLOSE_WAIT state and next request executes with closing the existing connection and creating new connection. 如果我们在Windows 10上看到底层套接字连接,则在第一个请求套接字进入CLOSE_WAIT状态后,下一个请求将在关闭现有连接并创建新连接的情况下执行。

Actually server closes the connection in duration of 5 minutes. 实际上,服务器会在5分钟的时间内关闭连接。 But windows 10 able to detect it and re-initiate the connection when next request is triggered. 但是Windows 10能够检测到它,并在触发下一个请求时重新启动连接。

Now, on windows server 2016, I can see that netstat shows socket ESTABLISHED state. 现在,在Windows Server 2016上,我可以看到netstat显示套接字已建立状态。 Means connection is ready to use and in that, it picks up the same connection and finally server has already closed it so results into connection reset error. 意味着连接已准备就绪,可以使用该连接,并且服务器已关闭该连接,因此导致连接重置错误。

I suspect its an environmental issue, where server 2016 is keeping socket ESTABLISHED even after server has terminated it, but on windows 10 socket status changed to CLOSE_WAIT. 我怀疑它是一个环境问题,即使服务器终止后,服务器2016仍保持套接字已建立,但在Windows 10上套接字状态已更改为CLOSE_WAIT。

Help on this is much appreciated 对此的帮助非常感谢

Finally got the root cause, 终于找到了根本原因,

Its issue with microsoft azure. Microsoft Azure的问题。 They are using SNAT and closing outbound TCP connections after 4 minute idle time. 他们使用SNAT并在4分钟的空闲时间后关闭出站TCP连接。 This wasted my 5 days to figureout. 这浪费了我5天的时间去弄清楚。

Means if you are connected with server with keep-alive and hope that you can reuse the connection till server time out and sends FIN. 表示如果您通过保持活动状态与服务器连接,并希望您可以重用连接,直到服务器超时并发送FIN。 But before that if idle period reaches to 4 minutes, azure kills it. 但是在此之前,如果闲置时间达到4分钟,天蓝色就会杀死它。 BOOM!!. 繁荣!!。 Worst part is, it is not even notifying server or client with RST, means violating TCP and questioning its reliability. 最糟糕的是,它甚至没有通过RST通知服务器或客户端,这意味着违反TCP并质疑其可靠性。

 clientBuilder.setKeepAliveStrategy(new ConnectionKeepAliveStrategy() {

        @Override
        public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
            // TODO Auto-generated method stub
            return 3*60*1000;
        }
    });

Using above code, I managed to close connection on 3 minute expiry and close it before azure kills it. 使用上面的代码,我设法在3分钟到期时关闭连接,并在天蓝色杀死它之前将其关闭。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM